diff --git a/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..e2921fc346193 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql @@ -0,0 +1,2 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..895cf8faf99e6 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql @@ -0,0 +1,2 @@ +INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..0435fa8fa6402 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql @@ -0,0 +1,6 @@ +SET IDENTITY_INSERT [#__extensions] ON; + +INSERT [#__extensions] ([extension_id], [name], [type], [element], [folder], [client_id], [enabled], [access], [protected], [manifest_cache], [params], [custom_data], [system_data], [checked_out], [checked_out_time], [ordering], [state]) +SELECT 452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0; + +SET IDENTITY_INSERT [#__extensions] OFF; diff --git a/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini b/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini new file mode 100644 index 0000000000000..bca688cb3049c --- /dev/null +++ b/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini @@ -0,0 +1,23 @@ +; Joomla! Project +; Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_SYSTEM_UPDATENOTIFICATION="System - Joomla! Update Notification" +PLG_SYSTEM_UPDATENOTIFICATION_DESCRIPTION="This plugin periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update Joomla!. Pro Tip: You can customise the email message by overriding the language string keys PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT and PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY." + +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_LBL="Super User Emails" +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_DESC="A comma separated list of the email addresses which will receive the update notification emails. The addresses in the list MUST belong to existing users of your site who have the Super User privilege. If none of the listed emails belogns to Super Users, or if it's left blank, all Super Users of this site will receive the update notification email." +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_LBL="Email language" +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC="If you choose Auto (default), the update notification email to Super Users will be in the logged in user's front-end language at the time the plugin is triggered. In multi-language sites this can create confusion: the user's language may be one the Super User receiving the email doesn't speak. By selecting a language here you are forcing the update notification emails to be sent in this specific language." +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE="Auto" + +; You can use the following merge codes: +; [NEWVERSION] New Joomla! version, e.g. 1.2.3 +; [CURVERSION] Currently installed Joomla! version, e.g. 1.2.0 +; [SITENAME] Site name, as set in Global Configuration. +; [URL] URL of the site's front-end page. +; [LINK] Update URL (link to com_joomlaupdate, will request login if the Super User isn't already logged in). +; \n Newline character. Use it to start a new line in the email. NO LINE SHOULD EXCEED 300 CHARACTERS! +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT="Joomla! Update available for [SITENAME] – [URL]" +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY="This email IS NOT sent by Joomla.org It is sent automatically by your own site,\n[SITENAME]\n\n================================================================================\nUPDATE INFORMATION\n================================================================================\n\nYour site has discovered that there is an updated version of Joomla! available\nfor download.\n\nJoomla! version currently installed: [CURVERSION]\nJoomla! version available for installation: [NEWVERSION]\n\nThis email is sent to you by your site to remind you of this fact. The Joomla!\nproject will never contact you directly about available updates of Joomla! on\nyour site.\n\n================================================================================\nUPDATE INSTRUCTIONS\n================================================================================\n\nTo install the update on [SITENAME] please click the following link. (If the URL\nis not a link, simply copy & paste it to your browser).\n\nUpdate link: [LINK]\n\n================================================================================\nWHY AM I RECEIVING THIS EMAIL?\n================================================================================\n\nThis email has been automatically sent by a plugin provided by Joomla!, the\nsoftware which powers your site. This plugin looks for updated versions of\nJoomla! and sends an email notification to its administrators. You will receive\nseveral similar emails from your site until you either update the software or\ndisable these emails.\n\nTo disable these emails, please unpublish the 'System - Joomla! Update\nNotification' plugin in the Plugin Manager on your site.\n\nIf you do not understand what is Joomla! and what you need to do please do not\ncontact the Joomla! project. They are NOT sending you this email and they cannot\nhelp you. Instead, please contact the person who built or manages your site.\n\nIf you are the person who built or manages your website, please note that this\nplugin may have been activated automatically when you installed or updated Joomla!\non your site.\n\n================================================================================\nWHO SENT ME THIS EMAIL?\n================================================================================\n\nThis email is sent to you by your own site, [SITENAME]" \ No newline at end of file diff --git a/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini b/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini new file mode 100644 index 0000000000000..894a51561a1ca --- /dev/null +++ b/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_SYSTEM_UPDATENOTIFICATION="System - Joomla! Update Notification" +PLG_SYSTEM_UPDATENOTIFICATION_DESCRIPTION="This plugin periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update Joomla!. Pro Tip: You can customise the email message by overriding the language string keys PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT and PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY." \ No newline at end of file diff --git a/components/com_content/helpers/legacyrouter.php b/components/com_content/helpers/legacyrouter.php new file mode 100644 index 0000000000000..ed3cac432ce98 --- /dev/null +++ b/components/com_content/helpers/legacyrouter.php @@ -0,0 +1,479 @@ +router = $router; + } + + /** + * Preprocess the route for the com_content component + * + * @param array &$query An array of URL arguments + * + * @return void + * + * @since 3.4 + * @deprecated 4.0 + */ + public function preprocess(&$query) + { + } + + /** + * Build the route for the com_content component + * + * @param array &$query An array of URL arguments + * @param array &$segments The URL arguments to use to assemble the subsequent URL. + * + * @return void + * + * @since 3.4 + * @deprecated 4.0 + */ + public function build(&$query, &$segments) + { + // Get a menu item based on Itemid or currently active + $params = JComponentHelper::getParams('com_content'); + $advanced = $params->get('sef_advanced_link', 0); + + // We need a menu item. Either the one specified in the query, or the current active one if none specified + if (empty($query['Itemid'])) + { + $menuItem = $this->router->menu->getActive(); + $menuItemGiven = false; + } + else + { + $menuItem = $this->router->menu->getItem($query['Itemid']); + $menuItemGiven = true; + } + + // Check again + if ($menuItemGiven && isset($menuItem) && $menuItem->component != 'com_content') + { + $menuItemGiven = false; + unset($query['Itemid']); + } + + if (isset($query['view'])) + { + $view = $query['view']; + } + else + { + // We need to have a view in the query or it is an invalid URL + return; + } + + // Are we dealing with an article or category that is attached to a menu item? + if (($menuItem instanceof stdClass) + && $menuItem->query['view'] == $query['view'] + && isset($query['id']) + && $menuItem->query['id'] == (int) $query['id']) + { + unset($query['view']); + + if (isset($query['catid'])) + { + unset($query['catid']); + } + + if (isset($query['layout'])) + { + unset($query['layout']); + } + + unset($query['id']); + + return; + } + + if ($view == 'category' || $view == 'article') + { + if (!$menuItemGiven) + { + $segments[] = $view; + } + + unset($query['view']); + + if ($view == 'article') + { + if (isset($query['id']) && isset($query['catid']) && $query['catid']) + { + $catid = $query['catid']; + + // Make sure we have the id and the alias + if (strpos($query['id'], ':') === false) + { + $db = JFactory::getDbo(); + $dbQuery = $db->getQuery(true) + ->select('alias') + ->from('#__content') + ->where('id=' . (int) $query['id']); + $db->setQuery($dbQuery); + $alias = $db->loadResult(); + $query['id'] = $query['id'] . ':' . $alias; + } + } + else + { + // We should have these two set for this view. If we don't, it is an error + return; + } + } + else + { + if (isset($query['id'])) + { + $catid = $query['id']; + } + else + { + // We should have id set for this view. If we don't, it is an error + return; + } + } + + if ($menuItemGiven && isset($menuItem->query['id'])) + { + $mCatid = $menuItem->query['id']; + } + else + { + $mCatid = 0; + } + + $categories = JCategories::getInstance('Content'); + $category = $categories->get($catid); + + if (!$category) + { + // We couldn't find the category we were given. Bail. + return; + } + + $path = array_reverse($category->getPath()); + + $array = array(); + + foreach ($path as $id) + { + if ((int) $id == (int) $mCatid) + { + break; + } + + list($tmp, $id) = explode(':', $id, 2); + + $array[] = $id; + } + + $array = array_reverse($array); + + if (!$advanced && count($array)) + { + $array[0] = (int) $catid . ':' . $array[0]; + } + + $segments = array_merge($segments, $array); + + if ($view == 'article') + { + if ($advanced) + { + list($tmp, $id) = explode(':', $query['id'], 2); + } + else + { + $id = $query['id']; + } + + $segments[] = $id; + } + + unset($query['id']); + unset($query['catid']); + } + + if ($view == 'archive') + { + if (!$menuItemGiven) + { + $segments[] = $view; + unset($query['view']); + } + + if (isset($query['year'])) + { + if ($menuItemGiven) + { + $segments[] = $query['year']; + unset($query['year']); + } + } + + if (isset($query['year']) && isset($query['month'])) + { + if ($menuItemGiven) + { + $segments[] = $query['month']; + unset($query['month']); + } + } + } + + if ($view == 'featured') + { + if (!$menuItemGiven) + { + $segments[] = $view; + } + + unset($query['view']); + } + + /* + * If the layout is specified and it is the same as the layout in the menu item, we + * unset it so it doesn't go into the query string. + */ + if (isset($query['layout'])) + { + if ($menuItemGiven && isset($menuItem->query['layout'])) + { + if ($query['layout'] == $menuItem->query['layout']) + { + unset($query['layout']); + } + } + else + { + if ($query['layout'] == 'default') + { + unset($query['layout']); + } + } + } + + $total = count($segments); + + for ($i = 0; $i < $total; $i++) + { + $segments[$i] = str_replace(':', '-', $segments[$i]); + } + } + + /** + * Parse the segments of a URL. + * + * @param array &$segments The segments of the URL to parse. + * @param array &$vars The URL attributes to be used by the application. + * + * @return void + * + * @since 3.4 + * @deprecated 4.0 + */ + public function parse(&$segments, &$vars) + { + $total = count($segments); + + for ($i = 0; $i < $total; $i++) + { + $segments[$i] = preg_replace('/-/', ':', $segments[$i], 1); + } + + // Get the active menu item. + $item = $this->router->menu->getActive(); + $params = JComponentHelper::getParams('com_content'); + $advanced = $params->get('sef_advanced_link', 0); + $db = JFactory::getDbo(); + + // Count route segments + $count = count($segments); + + /* + * Standard routing for articles. If we don't pick up an Itemid then we get the view from the segments + * the first segment is the view and the last segment is the id of the article or category. + */ + if (!isset($item)) + { + $vars['view'] = $segments[0]; + $vars['id'] = $segments[$count - 1]; + + return; + } + + /* + * If there is only one segment, then it points to either an article or a category. + * We test it first to see if it is a category. If the id and alias match a category, + * then we assume it is a category. If they don't we assume it is an article + */ + if ($count == 1) + { + // We check to see if an alias is given. If not, we assume it is an article + if (strpos($segments[0], ':') === false) + { + $vars['view'] = 'article'; + $vars['id'] = (int) $segments[0]; + + return; + } + + list($id, $alias) = explode(':', $segments[0], 2); + + // First we check if it is a category + $category = JCategories::getInstance('Content')->get($id); + + if ($category && $category->alias == $alias) + { + $vars['view'] = 'category'; + $vars['id'] = $id; + + return; + } + else + { + $query = $db->getQuery(true) + ->select($db->quoteName(array('alias', 'catid'))) + ->from($db->quoteName('#__content')) + ->where($db->quoteName('id') . ' = ' . (int) $id); + $db->setQuery($query); + $article = $db->loadObject(); + + if ($article) + { + if ($article->alias == $alias) + { + $vars['view'] = 'article'; + $vars['catid'] = (int) $article->catid; + $vars['id'] = (int) $id; + + return; + } + } + } + } + + /* + * If there was more than one segment, then we can determine where the URL points to + * because the first segment will have the target category id prepended to it. If the + * last segment has a number prepended, it is an article, otherwise, it is a category. + */ + if (!$advanced) + { + $cat_id = (int) $segments[0]; + + $article_id = (int) $segments[$count - 1]; + + if ($article_id > 0) + { + $vars['view'] = 'article'; + $vars['catid'] = $cat_id; + $vars['id'] = $article_id; + } + else + { + $vars['view'] = 'category'; + $vars['id'] = $cat_id; + } + + return; + } + + // We get the category id from the menu item and search from there + $id = $item->query['id']; + $category = JCategories::getInstance('Content')->get($id); + + if (!$category) + { + JError::raiseError(404, JText::_('COM_CONTENT_ERROR_PARENT_CATEGORY_NOT_FOUND')); + + return; + } + + $categories = $category->getChildren(); + $vars['catid'] = $id; + $vars['id'] = $id; + $found = 0; + + foreach ($segments as $segment) + { + $segment = str_replace(':', '-', $segment); + + foreach ($categories as $category) + { + if ($category->alias == $segment) + { + $vars['id'] = $category->id; + $vars['catid'] = $category->id; + $vars['view'] = 'category'; + $categories = $category->getChildren(); + $found = 1; + break; + } + } + + if ($found == 0) + { + if ($advanced) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from('#__content') + ->where($db->quoteName('catid') . ' = ' . (int) $vars['catid']) + ->where($db->quoteName('alias') . ' = ' . $db->quote($segment)); + $db->setQuery($query); + $cid = $db->loadResult(); + } + else + { + $cid = $segment; + } + + $vars['id'] = $cid; + + if ($item->query['view'] == 'archive' && $count != 1) + { + $vars['year'] = $count >= 2 ? $segments[$count - 2] : null; + $vars['month'] = $segments[$count - 1]; + $vars['view'] = 'archive'; + } + else + { + $vars['view'] = 'article'; + } + } + + $found = 0; + } + } +} diff --git a/components/com_content/helpers/route.php b/components/com_content/helpers/route.php index 357b6f954cdd0..1b790ec487145 100644 --- a/components/com_content/helpers/route.php +++ b/components/com_content/helpers/route.php @@ -16,8 +16,6 @@ */ abstract class ContentHelperRoute { - protected static $lookup = array(); - /** * Get the article route. * @@ -31,35 +29,17 @@ abstract class ContentHelperRoute */ public static function getArticleRoute($id, $catid = 0, $language = 0) { - $needles = array( - 'article' => array((int) $id) - ); - // Create the link $link = 'index.php?option=com_content&view=article&id=' . $id; if ((int) $catid > 1) { - $categories = JCategories::getInstance('Content'); - $category = $categories->get((int) $catid); - - if ($category) - { - $needles['category'] = array_reverse($category->getPath()); - $needles['categories'] = $needles['category']; - $link .= '&catid=' . $catid; - } + $link .= '&catid=' . $catid; } if ($language && $language != "*" && JLanguageMultilang::isEnabled()) { $link .= '&lang=' . $language; - $needles['language'] = $language; - } - - if ($item = self::_findItem($needles)) - { - $link .= '&Itemid=' . $item; } return $link; @@ -79,36 +59,24 @@ public static function getCategoryRoute($catid, $language = 0) { if ($catid instanceof JCategoryNode) { - $id = $catid->id; - $category = $catid; + $id = $catid->id; } else { - $id = (int) $catid; - $category = JCategories::getInstance('Content')->get($id); + $id = (int) $catid; } - if ($id < 1 || !($category instanceof JCategoryNode)) + if ($id < 1) { $link = ''; } else { - $needles = array(); - $link = 'index.php?option=com_content&view=category&id=' . $id; - $catids = array_reverse($category->getPath()); - $needles['category'] = $catids; - $needles['categories'] = $catids; + $link = 'index.php?option=com_content&view=category&id=' . $id; if ($language && $language != "*" && JLanguageMultilang::isEnabled()) { $link .= '&lang=' . $language; - $needles['language'] = $language; - } - - if ($item = self::_findItem($needles)) - { - $link .= '&Itemid=' . $item; } } @@ -126,109 +94,6 @@ public static function getCategoryRoute($catid, $language = 0) */ public static function getFormRoute($id) { - // Create the link - if ($id) - { - $link = 'index.php?option=com_content&task=article.edit&a_id=' . $id; - } - else - { - $link = 'index.php?option=com_content&task=article.edit&a_id=0'; - } - - return $link; - } - - /** - * Find an item ID. - * - * @param array $needles An array of language codes. - * - * @return mixed The ID found or null otherwise. - * - * @since 1.5 - */ - protected static function _findItem($needles = null) - { - $app = JFactory::getApplication(); - $menus = $app->getMenu('site'); - $language = isset($needles['language']) ? $needles['language'] : '*'; - - // Prepare the reverse lookup array. - if (!isset(self::$lookup[$language])) - { - self::$lookup[$language] = array(); - - $component = JComponentHelper::getComponent('com_content'); - - $attributes = array('component_id'); - $values = array($component->id); - - if ($language != '*') - { - $attributes[] = 'language'; - $values[] = array($needles['language'], '*'); - } - - $items = $menus->getItems($attributes, $values); - - foreach ($items as $item) - { - if (isset($item->query) && isset($item->query['view'])) - { - $view = $item->query['view']; - - if (!isset(self::$lookup[$language][$view])) - { - self::$lookup[$language][$view] = array(); - } - - if (isset($item->query['id'])) - { - /** - * Here it will become a bit tricky - * language != * can override existing entries - * language == * cannot override existing entries - */ - if (!isset(self::$lookup[$language][$view][$item->query['id']]) || $item->language != '*') - { - self::$lookup[$language][$view][$item->query['id']] = $item->id; - } - } - } - } - } - - if ($needles) - { - foreach ($needles as $view => $ids) - { - if (isset(self::$lookup[$language][$view])) - { - foreach ($ids as $id) - { - if (isset(self::$lookup[$language][$view][(int) $id])) - { - return self::$lookup[$language][$view][(int) $id]; - } - } - } - } - } - - // Check if the active menuitem matches the requested language - $active = $menus->getActive(); - - if ($active - && $active->component == 'com_content' - && ($language == '*' || in_array($active->language, array('*', $language)) || !JLanguageMultilang::isEnabled())) - { - return $active->id; - } - - // If not found, return language specific home link - $default = $menus->getDefault($language); - - return !empty($default->id) ? $default->id : null; + return 'index.php?option=com_content&task=article.edit&a_id=' . (int) $id; } } diff --git a/components/com_content/router.php b/components/com_content/router.php index 43b2d450be16f..ad0cd4f1f0efc 100644 --- a/components/com_content/router.php +++ b/components/com_content/router.php @@ -10,444 +10,129 @@ defined('_JEXEC') or die; /** - * Routing class from com_content + * Routing class of com_content * * @since 3.3 */ -class ContentRouter extends JComponentRouterBase +class ContentRouter extends JComponentRouterView { + function __construct($app = null, $menu = null) + { + $categories = new JComponentRouterViewconfiguration('categories'); + $categories->setKey('id'); + $this->registerView($categories); + $category = new JComponentRouterViewconfiguration('category'); + $category->setKey('id')->setParent($categories, 'id')->setNestable()->addLayout('blog'); + $this->registerView($category); + $article = new JComponentRouterViewconfiguration('article'); + $article->setKey('id')->setParent($category, 'catid'); + $this->registerView($article); + $this->registerView(new JComponentRouterViewconfiguration('archive')); + $this->registerView(new JComponentRouterViewconfiguration('featured')); + $this->registerView(new JComponentRouterViewconfiguration('form')); + + parent::__construct($app, $menu); + + $this->attachRule(new JComponentRouterRulesMenu($this)); + require_once JPATH_SITE . '/components/com_content/helpers/legacyrouter.php'; + $this->attachRule(new ContentRouterRulesLegacy($this)); + } + /** - * Build the route for the com_content component + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is build right now * - * @param array &$query An array of URL arguments - * - * @return array The URL arguments to use to assemble the subsequent URL. - * - * @since 3.3 + * @return array|string The segments of this item */ - public function build(&$query) + public function getCategorySegment($id, $query) { - $segments = array(); - - // Get a menu item based on Itemid or currently active - $params = JComponentHelper::getParams('com_content'); - $advanced = $params->get('sef_advanced_link', 0); - - // We need a menu item. Either the one specified in the query, or the current active one if none specified - if (empty($query['Itemid'])) - { - $menuItem = $this->menu->getActive(); - $menuItemGiven = false; - } - else - { - $menuItem = $this->menu->getItem($query['Itemid']); - $menuItemGiven = true; - } - - // Check again - if ($menuItemGiven && isset($menuItem) && $menuItem->component != 'com_content') - { - $menuItemGiven = false; - unset($query['Itemid']); - } - - if (isset($query['view'])) - { - $view = $query['view']; - } - else - { - // We need to have a view in the query or it is an invalid URL - return $segments; - } - - // Are we dealing with an article or category that is attached to a menu item? - if (($menuItem instanceof stdClass) - && $menuItem->query['view'] == $query['view'] - && isset($query['id']) - && $menuItem->query['id'] == (int) $query['id']) - { - unset($query['view']); - - if (isset($query['catid'])) - { - unset($query['catid']); - } - - if (isset($query['layout'])) - { - unset($query['layout']); - } - - unset($query['id']); - - return $segments; - } - - if ($view == 'category' || $view == 'article') - { - if (!$menuItemGiven) - { - $segments[] = $view; - } - - unset($query['view']); - - if ($view == 'article') - { - if (isset($query['id']) && isset($query['catid']) && $query['catid']) - { - $catid = $query['catid']; - - // Make sure we have the id and the alias - if (strpos($query['id'], ':') === false) - { - $db = JFactory::getDbo(); - $dbQuery = $db->getQuery(true) - ->select('alias') - ->from('#__content') - ->where('id=' . (int) $query['id']); - $db->setQuery($dbQuery); - $alias = $db->loadResult(); - $query['id'] = $query['id'] . ':' . $alias; - } - } - else - { - // We should have these two set for this view. If we don't, it is an error - return $segments; - } - } - else - { - if (isset($query['id'])) - { - $catid = $query['id']; - } - else - { - // We should have id set for this view. If we don't, it is an error - return $segments; - } - } - - if ($menuItemGiven && isset($menuItem->query['id'])) - { - $mCatid = $menuItem->query['id']; - } - else - { - $mCatid = 0; - } - - $categories = JCategories::getInstance('Content'); - $category = $categories->get($catid); - - if (!$category) - { - // We couldn't find the category we were given. Bail. - return $segments; - } - - $path = array_reverse($category->getPath()); - - $array = array(); - - foreach ($path as $id) - { - if ((int) $id == (int) $mCatid) - { - break; - } - - list($tmp, $id) = explode(':', $id, 2); - - $array[] = $id; - } - - $array = array_reverse($array); - - if (!$advanced && count($array)) - { - $array[0] = (int) $catid . ':' . $array[0]; - } - - $segments = array_merge($segments, $array); - - if ($view == 'article') - { - if ($advanced) - { - list($tmp, $id) = explode(':', $query['id'], 2); - } - else - { - $id = $query['id']; - } - - $segments[] = $id; - } - - unset($query['id']); - unset($query['catid']); - } - - if ($view == 'archive') - { - if (!$menuItemGiven) - { - $segments[] = $view; - unset($query['view']); - } - - if (isset($query['year'])) - { - if ($menuItemGiven) - { - $segments[] = $query['year']; - unset($query['year']); - } - } - - if (isset($query['year']) && isset($query['month'])) - { - if ($menuItemGiven) - { - $segments[] = $query['month']; - unset($query['month']); - } - } - } - - if ($view == 'featured') - { - if (!$menuItemGiven) - { - $segments[] = $view; - } - - unset($query['view']); - } - - /* - * If the layout is specified and it is the same as the layout in the menu item, we - * unset it so it doesn't go into the query string. - */ - if (isset($query['layout'])) - { - if ($menuItemGiven && isset($menuItem->query['layout'])) - { - if ($query['layout'] == $menuItem->query['layout']) - { - unset($query['layout']); - } - } - else - { - if ($query['layout'] == 'default') - { - unset($query['layout']); - } - } - } - - $total = count($segments); - - for ($i = 0; $i < $total; $i++) + $category = JCategories::getInstance($this->getName())->get($id); + if ($category) { - $segments[$i] = str_replace(':', '-', $segments[$i]); + return array_reverse($category->getPath()); } - return $segments; + return array(); } /** - * Parse the segments of a URL. + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is build right now * - * @param array &$segments The segments of the URL to parse. - * - * @return array The URL attributes to be used by the application. - * - * @since 3.3 + * @return array|string The segments of this item */ - public function parse(&$segments) + public function getCategoriesSegment($id, $query) { - $total = count($segments); - $vars = array(); - - for ($i = 0; $i < $total; $i++) - { - $segments[$i] = preg_replace('/-/', ':', $segments[$i], 1); - } - - // Get the active menu item. - $item = $this->menu->getActive(); - $params = JComponentHelper::getParams('com_content'); - $advanced = $params->get('sef_advanced_link', 0); - $db = JFactory::getDbo(); - - // Count route segments - $count = count($segments); - - /* - * Standard routing for articles. If we don't pick up an Itemid then we get the view from the segments - * the first segment is the view and the last segment is the id of the article or category. - */ - if (!isset($item)) - { - $vars['view'] = $segments[0]; - $vars['id'] = $segments[$count - 1]; + return $this->getCategorySegment($id, $query); + } - return $vars; - } + /** + * Method to get the segment(s) for an article + * + * @param string $id ID of the article to retrieve the segments for + * @param array $query The request that is build right now + * + * @return array|string The segments of this item + */ + public function getArticleSegment($id, $query) + { + return array($id); + } - /* - * If there is only one segment, then it points to either an article or a category. - * We test it first to see if it is a category. If the id and alias match a category, - * then we assume it is a category. If they don't we assume it is an article - */ - if ($count == 1) + /** + * Method to get the id for a category + * + * @param string $segment Segment to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return array|int The id of this item + */ + public function getCategoryId($segment, $query) + { + if (isset($query['id'])) { - // We check to see if an alias is given. If not, we assume it is an article - if (strpos($segments[0], ':') === false) - { - $vars['view'] = 'article'; - $vars['id'] = (int) $segments[0]; + $category = JCategories::getInstance($this->getName())->get($query['id']); - return $vars; - } - - list($id, $alias) = explode(':', $segments[0], 2); - - // First we check if it is a category - $category = JCategories::getInstance('Content')->get($id); - - if ($category && $category->alias == $alias) + foreach ($category->getChildren() as $child) { - $vars['view'] = 'category'; - $vars['id'] = $id; - - return $vars; - } - else - { - $query = $db->getQuery(true) - ->select($db->quoteName(array('alias', 'catid'))) - ->from($db->quoteName('#__content')) - ->where($db->quoteName('id') . ' = ' . (int) $id); - $db->setQuery($query); - $article = $db->loadObject(); - - if ($article) + if ($child->id == (int) $segment) { - if ($article->alias == $alias) - { - $vars['view'] = 'article'; - $vars['catid'] = (int) $article->catid; - $vars['id'] = (int) $id; - - return $vars; - } + return $child->id; } } } - /* - * If there was more than one segment, then we can determine where the URL points to - * because the first segment will have the target category id prepended to it. If the - * last segment has a number prepended, it is an article, otherwise, it is a category. - */ - if (!$advanced) - { - $cat_id = (int) $segments[0]; - - $article_id = (int) $segments[$count - 1]; - - if ($article_id > 0) - { - $vars['view'] = 'article'; - $vars['catid'] = $cat_id; - $vars['id'] = $article_id; - } - else - { - $vars['view'] = 'category'; - $vars['id'] = $cat_id; - } - - return $vars; - } - - // We get the category id from the menu item and search from there - $id = $item->query['id']; - $category = JCategories::getInstance('Content')->get($id); - - if (!$category) - { - JError::raiseError(404, JText::_('COM_CONTENT_ERROR_PARENT_CATEGORY_NOT_FOUND')); - - return $vars; - } - - $categories = $category->getChildren(); - $vars['catid'] = $id; - $vars['id'] = $id; - $found = 0; - - foreach ($segments as $segment) - { - $segment = str_replace(':', '-', $segment); - - foreach ($categories as $category) - { - if ($category->alias == $segment) - { - $vars['id'] = $category->id; - $vars['catid'] = $category->id; - $vars['view'] = 'category'; - $categories = $category->getChildren(); - $found = 1; - break; - } - } - - if ($found == 0) - { - if ($advanced) - { - $db = JFactory::getDbo(); - $query = $db->getQuery(true) - ->select($db->quoteName('id')) - ->from('#__content') - ->where($db->quoteName('catid') . ' = ' . (int) $vars['catid']) - ->where($db->quoteName('alias') . ' = ' . $db->quote($segment)); - $db->setQuery($query); - $cid = $db->loadResult(); - } - else - { - $cid = $segment; - } - - $vars['id'] = $cid; - - if ($item->query['view'] == 'archive' && $count != 1) - { - $vars['year'] = $count >= 2 ? $segments[$count - 2] : null; - $vars['month'] = $segments[$count - 1]; - $vars['view'] = 'archive'; - } - else - { - $vars['view'] = 'article'; - } - } + return false; + } - $found = 0; - } + /** + * Method to get the segment(s) for a category + * + * @param string $id ID of the category to retrieve the segments for + * @param array $query The request that is parsed right now + * + * @return array|int The segments of this item + */ + public function getCategoriesId($segment, $query) + { + return $this->getCategoryId($segment, $query); + } - return $vars; + /** + * Method to get the segment(s) for an article + * + * @param string $segment Segment of the article to retrieve the ID for + * @param array $query The request that is parsed right now + * + * @return array|int The segments of this item + */ + public function getArticleId($segment, $query) + { + return (int) $segment; } } @@ -465,7 +150,8 @@ public function parse(&$segments) */ function contentBuildRoute(&$query) { - $router = new ContentRouter; + $app = JFactory::getApplication(); + $router = new ContentRouter($app, $app->getMenu()); return $router->build($query); } @@ -485,7 +171,8 @@ function contentBuildRoute(&$query) */ function contentParseRoute($segments) { - $router = new ContentRouter; + $app = JFactory::getApplication(); + $router = new ContentRouter($app, $app->getMenu()); return $router->parse($segments); } diff --git a/composer.json b/composer.json index 6bde779989852..905e1614efdea 100644 --- a/composer.json +++ b/composer.json @@ -10,12 +10,14 @@ }, "require": { "php": ">=5.3.10", - "joomla/application": "~1.2", + "joomla/application": "~1.4", "joomla/di": "~1.2", - "joomla/registry": "~1.2", - "joomla/string": "~1.2", + "joomla/event": "~1.1", + "joomla/registry": "~1.4 >=1.4.5", + "joomla/session": "~1.2", + "joomla/string": "~1.3", "joomla/uri": "~1.1", - "joomla/utilities": "~1.3", + "joomla/utilities": "~1.3 >=1.3.3", "ircmaxell/password-compat": "1.*", "leafo/lessphp": "0.3.9", "phpmailer/phpmailer": "5.2.9", diff --git a/composer.lock b/composer.lock index 851ef2c8e375c..9de6606e5d5e1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "385d58b11d816b21d0484b902310db7e", + "hash": "a305fbfdb073d809dbff32a3210e110f", "packages": [ { "name": "ircmaxell/password-compat", @@ -50,32 +50,35 @@ }, { "name": "joomla/application", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/joomla-framework/application.git", - "reference": "b7745273664294387bdd7fb694d75e65b7491f28" + "reference": "185b68fe55537281385b637a90e11856ea01c8da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/application/zipball/b7745273664294387bdd7fb694d75e65b7491f28", - "reference": "b7745273664294387bdd7fb694d75e65b7491f28", + "url": "https://api.github.com/repos/joomla-framework/application/zipball/185b68fe55537281385b637a90e11856ea01c8da", + "reference": "185b68fe55537281385b637a90e11856ea01c8da", "shasum": "" }, "require": { "joomla/input": "~1.2", "joomla/registry": "~1.1", - "joomla/session": "~1.1", - "joomla/string": "~1.1", - "joomla/uri": "~1.1", "php": ">=5.3.10", "psr/log": "~1.0" }, "require-dev": { + "joomla/session": "~1.1", "joomla/test": "~1.1", + "joomla/uri": "~1.1", "phpunit/phpunit": "4.*", "squizlabs/php_codesniffer": "1.*" }, + "suggest": { + "joomla/session": "To use AbstractWebApplication with session support, install joomla/session", + "joomla/uri": "To use AbstractWebApplication, install joomla/uri" + }, "type": "joomla-package", "extra": { "branch-alias": { @@ -99,7 +102,7 @@ "framework", "joomla" ], - "time": "2014-10-13 12:43:54" + "time": "2015-03-06 17:37:01" }, { "name": "joomla/compat", @@ -325,21 +328,21 @@ }, { "name": "joomla/registry", - "version": "1.4.4", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/joomla-framework/registry.git", - "reference": "730467978ad52677903e973bb33be2306eb161eb" + "reference": "4f926ba961ca45eb95076a1598c3ae689cb02fc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/registry/zipball/730467978ad52677903e973bb33be2306eb161eb", - "reference": "730467978ad52677903e973bb33be2306eb161eb", + "url": "https://api.github.com/repos/joomla-framework/registry/zipball/4f926ba961ca45eb95076a1598c3ae689cb02fc5", + "reference": "4f926ba961ca45eb95076a1598c3ae689cb02fc5", "shasum": "" }, "require": { "joomla/compat": "~1.0", - "joomla/string": "~1.2", + "joomla/string": "~1.3", "joomla/utilities": "~1.0", "php": ">=5.3.10" }, @@ -375,7 +378,7 @@ "joomla", "registry" ], - "time": "2015-03-16 18:49:29" + "time": "2015-03-28 17:54:38" }, { "name": "joomla/session", @@ -424,16 +427,16 @@ }, { "name": "joomla/string", - "version": "1.2.2", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/joomla-framework/string.git", - "reference": "9f7b27d6b2d48d65b2fe81b5c6d72225629ad692" + "reference": "0df8ead8c726a1f648e624d3bcbef8cf05c1d0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/string/zipball/9f7b27d6b2d48d65b2fe81b5c6d72225629ad692", - "reference": "9f7b27d6b2d48d65b2fe81b5c6d72225629ad692", + "url": "https://api.github.com/repos/joomla-framework/string/zipball/0df8ead8c726a1f648e624d3bcbef8cf05c1d0da", + "reference": "0df8ead8c726a1f648e624d3bcbef8cf05c1d0da", "shasum": "" }, "require": { @@ -467,7 +470,7 @@ "joomla", "string" ], - "time": "2015-03-13 12:29:00" + "time": "2015-03-26 01:02:20" }, { "name": "joomla/uri", @@ -508,20 +511,20 @@ }, { "name": "joomla/utilities", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/joomla-framework/utilities.git", - "reference": "2e7f37a69162fea02059c764a318a920121f8b4a" + "reference": "3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/utilities/zipball/2e7f37a69162fea02059c764a318a920121f8b4a", - "reference": "2e7f37a69162fea02059c764a318a920121f8b4a", + "url": "https://api.github.com/repos/joomla-framework/utilities/zipball/3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4", + "reference": "3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4", "shasum": "" }, "require": { - "joomla/string": "~1.0", + "joomla/string": "~1.3", "php": ">=5.3.10" }, "require-dev": { @@ -551,7 +554,7 @@ "joomla", "utilities" ], - "time": "2015-03-16 18:50:58" + "time": "2015-03-28 17:52:43" }, { "name": "leafo/lessphp", diff --git a/installation/sql/mysql/joomla.sql b/installation/sql/mysql/joomla.sql index 1fcc2322cd4e1..1c6bc04112472 100644 --- a/installation/sql/mysql/joomla.sql +++ b/installation/sql/mysql/joomla.sql @@ -610,6 +610,7 @@ INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder` (449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (503, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), (504, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), (506, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), diff --git a/installation/sql/postgresql/joomla.sql b/installation/sql/postgresql/joomla.sql index 876d4263487aa..cdf03653eaece 100644 --- a/installation/sql/postgresql/joomla.sql +++ b/installation/sql/postgresql/joomla.sql @@ -610,7 +610,8 @@ INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder" (448, 'plg_twofactorauth_totp', 'plugin', 'totp', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), (449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), (450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), -(451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0); +(451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0); -- Templates INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES diff --git a/installation/sql/sqlazure/joomla.sql b/installation/sql/sqlazure/joomla.sql index 9ef97578f6c9d..b0d54edddb22a 100644 --- a/installation/sql/sqlazure/joomla.sql +++ b/installation/sql/sqlazure/joomla.sql @@ -1011,7 +1011,9 @@ SELECT 449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0 UNION ALL SELECT 450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0 UNION ALL -SELECT 451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1900-01-01 00:00:00', 0, 0; +SELECT 451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1900-01-01 00:00:00', 0, 0 +UNION ALL +SELECT 452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0; INSERT [#__extensions] ([extension_id], [name], [type], [element], [folder], [client_id], [enabled], [access], [protected], [manifest_cache], [params], [custom_data], [system_data], [checked_out], [checked_out_time], [ordering], [state]) diff --git a/libraries/cms/component/router/base.php b/libraries/cms/component/router/base.php index a75a5924892c9..bdf19b48859f5 100644 --- a/libraries/cms/component/router/base.php +++ b/libraries/cms/component/router/base.php @@ -48,7 +48,7 @@ public function __construct($app = null, $menu = null) } else { - $this->app = JFactory::getApplication(); + $this->app = JFactory::getApplication('site'); } if ($menu) diff --git a/libraries/cms/component/router/rules/menu.php b/libraries/cms/component/router/rules/menu.php new file mode 100644 index 0000000000000..b2227693b3266 --- /dev/null +++ b/libraries/cms/component/router/rules/menu.php @@ -0,0 +1,215 @@ +router = $router; + + $this->buildLookup(); + } + + /** + * Finds the right Itemid for this query + * + * @param array &$query The query array to process + * + * @return void + * + * @since 3.4 + */ + public function preprocess(&$query) + { + if (isset($query['Itemid']) && $query['Itemid'] != $this->router->menu->getActive()->id) + { + return; + } + + $language = '*'; + if (isset($query['lang'])) + { + $language = $query['lang']; + + if (!isset($this->lookup[$query['lang']])) + { + $this->buildLookup($query['lang']); + } + } + + $needles = $this->router->getPath($query); + + if ($needles) + { + foreach ($needles as $view => $ids) + { + if (isset($this->lookup[$language][$view])) + { + if (is_bool($ids)) + { + $query['Itemid'] = $this->lookup[$language][$view]; + return; + } + foreach ($ids as $id) + { + if (isset($this->lookup[$language][$view][(int) $id])) + { + $query['Itemid'] = $this->lookup[$language][$view][(int) $id]; + return; + } + } + } + } + } + + // Check if the active menuitem matches the requested language + $active = $this->router->menu->getActive(); + + if ($active && $active->component == 'com_' . $this->router->getName() + && ($language == '*' || in_array($active->language, array('*', $language)) || !JLanguageMultilang::isEnabled())) + { + $query['Itemid'] = $active->id; + return; + } + + // If not found, return language specific home link + $default = $this->router->menu->getDefault($language); + + if (!empty($default->id)) + { + $query['Itemid'] = $default->id; + } + } + + /** + * Method to build the lookup array + * + * @param string $language The language that the lookup should be built up for + * + * @return void + * + * @since 3.4 + */ + protected function buildLookup($language = '*') + { + // Prepare the reverse lookup array. + if (!isset($this->lookup[$language])) + { + $this->lookup[$language] = array(); + + $component = JComponentHelper::getComponent('com_' . $this->router->getName()); + $views = $this->router->getViews(); + + $attributes = array('component_id'); + $values = array((int) $component->id); + + $attributes[] = 'language'; + $values[] = array($language, '*'); + + $items = $this->router->menu->getItems($attributes, $values); + + foreach ($items as $item) + { + if (isset($item->query) && isset($item->query['view'])) + { + $view = $item->query['view']; + + if ($views[$view]->key) + { + if (!isset($this->lookup[$language][$view])) + { + $this->lookup[$language][$view] = array(); + } + + /** + * Here it will become a bit tricky + * language != * can override existing entries + * language == * cannot override existing entries + */ + if (isset($item->query[$views[$view]->key]) + && (!isset($this->lookup[$language][$view][$item->query[$views[$view]->key]]) || $item->language != '*')) + { + $this->lookup[$language][$view][$item->query['id']] = $item->id; + } + } + else + { + /** + * Here it will become a bit tricky + * language != * can override existing entries + * language == * cannot override existing entries + */ + if (!isset($this->lookup[$language][$view]) || $item->language != '*') + { + $this->lookup[$language][$view] = $item->id; + } + } + } + } + } + } + + /** + * Dummymethod to fullfill the interface requirements + * + * @param array &$segments The URL segments to parse + * @param array &$vars The vars that result from the segments + * + * @return void + * + * @since 3.4 + * @codeCoverageIgnore + */ + public function parse(&$segments, &$vars) + { + } + + /** + * Dummymethod to fullfill the interface requirements + * + * @param array &$query The vars that should be converted + * @param array &$segments The URL segments to create + * + * @return void + * + * @since 3.4 + * @codeCoverageIgnore + */ + public function build(&$query, &$segments) + { + } +} diff --git a/libraries/cms/component/router/view.php b/libraries/cms/component/router/view.php new file mode 100644 index 0000000000000..91e8f32285183 --- /dev/null +++ b/libraries/cms/component/router/view.php @@ -0,0 +1,264 @@ +views[$view->name] = $view; + } + + /** + * Return an array of registered view objects + * + * @return JComponentRouterViewconfiguration[] Array of registered view objects + * + * @since 3.4 + */ + public function getViews() + { + return $this->views; + } + + /** + * Get the path of views from target view to root view + * including content items of a nestable view + * + * @param array $query Array of query elements + * + * @return array List of views including IDs of content items + */ + public function getPath($query) + { + $views = $this->getViews(); + $result = array(); + $key = false; + + // Get the right view object + if (isset($query['view']) && $views[$query['view']]) + { + $viewobj = $views[$query['view']]; + } + + // Get the path from the current item to the root view with all IDs + if (isset($viewobj)) + { + $path = array_reverse($viewobj->path); + $start = true; + $childkey = false; + + foreach ($path as $element) + { + $view = $views[$element]; + + if ($start) + { + $key = $view->key; + $start = false; + } + else + { + $key = $childkey; + } + $childkey = $view->parent_key; + + if ($key && isset($query[$key]) && is_callable(array($this, 'get' . ucfirst($view->name) . 'Segment'))) + { + $result[$view->name] = call_user_func_array(array($this, 'get' . ucfirst($view->name) . 'Segment'), array($query[$key], $query)); + } + else + { + $result[$view->name] = true; + } + } + } + return $result; + } + + /** + * Get all currently attached rules + * + * @return JComponentRouterRulesInterface[] All currently attached rules in an array + * + * @since 3.4 + */ + public function getRules() + { + return $this->rules; + } + + /** + * Add a number of router rules to the object + * + * @param JComponentRouterRulesInterface[] $rules Array of JComponentRouterRulesInterface objects + * + * @return void + * + * @since 3.4 + */ + public function attachRules($rules) + { + foreach ($rules as $rule) + { + $this->attachRule($rule); + } + } + + /** + * Attach a build rule + * + * @param JComponentRouterRulesInterface $rule The function to be called. + * + * @return void + */ + public function attachRule(JComponentRouterRulesInterface $rule) + { + $this->rules[] = $rule; + } + + /** + * Remove a build rule + * + * @param JComponentRouterRulesInterface $rule The rule to be removed. + * + * @return boolean Was a rule removed? + */ + public function detachRule(JComponentRouterRulesInterface $rule) + { + foreach ($this->rules as $id => $r) + { + if ($r == $rule) + { + unset($this->rules[$id]); + return true; + } + } + + return false; + } + + /** + * Generic method to preprocess a URL + * + * @param array $query An associative array of URL arguments + * + * @return array The URL arguments to use to assemble the subsequent URL. + * + * @since 3.3 + */ + public function preprocess($query) + { + // Process the parsed variables based on custom defined rules + foreach ($this->rules as $rule) + { + $rule->preprocess($query); + } + return $query; + } + + /** + * Build method for URLs + * + * @param array &$query Array of query elements + * + * @return array Array of URL segments + */ + public function build(&$query) + { + $segments = array(); + + // Process the parsed variables based on custom defined rules + foreach ($this->rules as $rule) + { + $rule->build($query, $segments); + } + return $segments; + } + + /** + * Parse method for URLs + * + * @param array &$segments Array of URL string-segments + * + * @return array Associative array of query values + */ + public function parse(&$segments) + { + $vars = array(); + + // Process the parsed variables based on custom defined rules + foreach ($this->rules as $rule) + { + $rule->parse($segments, $vars); + } + return $vars; + } + + /** + * Method to return the name of the router + * + * @return string Name of the router + * + * @since 3.4 + */ + public function getName() + { + if (empty($this->name)) + { + $r = null; + if (!preg_match('/(.*)Router/i', get_class($this), $r)) + { + throw new Exception('JLIB_APPLICATION_ERROR_ROUTER_GET_NAME', 500); + } + $this->name = strtolower($r[1]); + } + + return $this->name; + } +} diff --git a/libraries/cms/component/router/viewconfiguration.php b/libraries/cms/component/router/viewconfiguration.php new file mode 100644 index 0000000000000..1511e805f0f58 --- /dev/null +++ b/libraries/cms/component/router/viewconfiguration.php @@ -0,0 +1,229 @@ +name = $name; + $this->path[] = $name; + } + + /** + * Set the name of the view + * + * @param string $name Name of the view + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function setName($name) + { + $this->name = $name; + + array_pop($this->path); + $this->path[] = $name; + + return $this; + } + + /** + * Set the key-identifier for the view + * + * @param string $key Key of the view + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function setKey($key) + { + $this->key = $key; + + return $this; + } + + /** + * Set the parent view of this view + * + * @param JComponentRouterViewconfiguration $parent Parent view object + * @param string $parent_key Key of the parent view in this context + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function setParent(JComponentRouterViewconfiguration $parent, $parent_key = false) + { + if ($this->parent) + { + $key = array_search($this, $this->parent->children); + + if ($key !== false) + { + unset($this->parent->children[$key]); + } + + if ($this->parent_key) { + $child_key = array_search($this->parent_key, $this->parent->child_keys); + unset($this->parent->child_keys[$child_key]); + } + } + + $this->parent = $parent; + $parent->children[] = $this; + + $this->path = $parent->path; + $this->path[] = $this->name; + + $this->parent_key = $parent_key; + + if ($parent_key) + { + $parent->child_keys[] = $parent_key; + } + + return $this; + } + + /** + * Set if this view is nestable or not + * + * @param bool $isNestable If set to true, the view is nestable + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function setNestable($isNestable = true) + { + $this->nestable = (bool) $isNestable; + + return $this; + } + + /** + * Add a layout to this view + * + * @param string $layout Layouts that this view supports + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function addLayout($layout) + { + array_push($this->layouts, $layout); + $this->layouts = array_unique($this->layouts); + + return $this; + } + + /** + * Remove a layout from this view + * + * @param string $layout Layouts that this view supports + * + * @return JComponentRouterViewconfiguration This object for chaining + * @since 3.4 + */ + public function removeLayout($layout) + { + $key = array_search($layout, $this->layouts); + + if ($key !== false) + { + unset($this->layouts[$key]); + } + + return $this; + } +} diff --git a/libraries/joomla/string/string.php b/libraries/joomla/string/string.php index 2d06d771097ff..526c2e4102888 100644 --- a/libraries/joomla/string/string.php +++ b/libraries/joomla/string/string.php @@ -9,7 +9,7 @@ defined('JPATH_PLATFORM') or die; -use Joomla\String\String; +use Joomla\String\StringHelper; /** * String handling class for utf-8 data @@ -17,9 +17,9 @@ * All functions assume the validity of utf-8 strings. * * @since 11.1 - * @deprecated 4.0 Use {@link \Joomla\String\String} instead unless otherwise noted. + * @deprecated 4.0 Use {@link \Joomla\String\StringHelper} instead unless otherwise noted. */ -abstract class JString extends String +abstract class JString extends StringHelper { /** * Split a string in camel case format diff --git a/libraries/joomla/updater/updater.php b/libraries/joomla/updater/updater.php index b260b701d5ae8..be96c27d51aec 100644 --- a/libraries/joomla/updater/updater.php +++ b/libraries/joomla/updater/updater.php @@ -100,9 +100,9 @@ public static function getInstance() /** * Finds an update for an extension * - * @param integer $eid Extension Identifier; if zero use all sites - * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the update information - * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc, 4=stable + * @param int|array $eid Extension Identifier or list of Extension Identifiers; if zero use all sites + * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the update information + * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc, 4=stable * * @return boolean True if there are updates * diff --git a/libraries/vendor/autoload.php b/libraries/vendor/autoload.php index baecd9740292a..4cc388d9f7229 100644 --- a/libraries/vendor/autoload.php +++ b/libraries/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInitf9aed076f12471aff0049364a504b3f7::getLoader(); +return ComposerAutoloaderInit0efb534ee20646bcb987f4359c38b3aa::getLoader(); diff --git a/libraries/vendor/composer/autoload_real.php b/libraries/vendor/composer/autoload_real.php index 60bdad1198a32..024522060c11a 100644 --- a/libraries/vendor/composer/autoload_real.php +++ b/libraries/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInitf9aed076f12471aff0049364a504b3f7 +class ComposerAutoloaderInit0efb534ee20646bcb987f4359c38b3aa { private static $loader; @@ -19,9 +19,9 @@ public static function getLoader() return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInitf9aed076f12471aff0049364a504b3f7', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit0efb534ee20646bcb987f4359c38b3aa', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInitf9aed076f12471aff0049364a504b3f7', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit0efb534ee20646bcb987f4359c38b3aa', 'loadClassLoader')); $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -42,14 +42,14 @@ public static function getLoader() $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequiref9aed076f12471aff0049364a504b3f7($file); + composerRequire0efb534ee20646bcb987f4359c38b3aa($file); } return $loader; } } -function composerRequiref9aed076f12471aff0049364a504b3f7($file) +function composerRequire0efb534ee20646bcb987f4359c38b3aa($file) { require $file; } diff --git a/libraries/vendor/composer/installed.json b/libraries/vendor/composer/installed.json index 1f834aefe431c..dbd823136ee3d 100644 --- a/libraries/vendor/composer/installed.json +++ b/libraries/vendor/composer/installed.json @@ -116,92 +116,6 @@ "uri" ] }, - { - "name": "joomla/event", - "version": "1.1.1", - "version_normalized": "1.1.1.0", - "source": { - "type": "git", - "url": "https://github.com/joomla-framework/event.git", - "reference": "bb957bc45aba897e465384bbe21cd0eb79aca901" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/event/zipball/bb957bc45aba897e465384bbe21cd0eb79aca901", - "reference": "bb957bc45aba897e465384bbe21cd0eb79aca901", - "shasum": "" - }, - "require": { - "php": ">=5.3.10" - }, - "time": "2014-02-09 01:30:54", - "type": "joomla-package", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Joomla\\Event\\": "src/", - "Joomla\\Event\\Tests\\": "Tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "description": "Joomla Event Package", - "homepage": "https://github.com/joomla-framework/event", - "keywords": [ - "event", - "framework", - "joomla" - ] - }, - { - "name": "joomla/session", - "version": "1.2.3", - "version_normalized": "1.2.3.0", - "target-dir": "Joomla/Session", - "source": { - "type": "git", - "url": "https://github.com/joomla-framework/session.git", - "reference": "ef955cf9642793c4ad5874f334069051c33ba604" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/session/zipball/ef955cf9642793c4ad5874f334069051c33ba604", - "reference": "ef955cf9642793c4ad5874f334069051c33ba604", - "shasum": "" - }, - "require": { - "joomla/event": "~1.1", - "joomla/filter": "~1.0", - "php": ">=5.3.10" - }, - "require-dev": { - "joomla/test": "~1.0" - }, - "suggest": { - "joomla/database": "Install joomla/database if you want to use Database session storage." - }, - "time": "2014-08-18 17:41:06", - "type": "joomla-package", - "installation-source": "dist", - "autoload": { - "psr-0": { - "Joomla\\Session": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "description": "Joomla Session Package", - "homepage": "https://github.com/joomla-framework/session", - "keywords": [ - "framework", - "joomla", - "session" - ] - }, { "name": "leafo/lessphp", "version": "v0.3.9", @@ -295,61 +209,6 @@ "joomla" ] }, - { - "name": "joomla/application", - "version": "1.3.0", - "version_normalized": "1.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/joomla-framework/application.git", - "reference": "b7745273664294387bdd7fb694d75e65b7491f28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/application/zipball/b7745273664294387bdd7fb694d75e65b7491f28", - "reference": "b7745273664294387bdd7fb694d75e65b7491f28", - "shasum": "" - }, - "require": { - "joomla/input": "~1.2", - "joomla/registry": "~1.1", - "joomla/session": "~1.1", - "joomla/string": "~1.1", - "joomla/uri": "~1.1", - "php": ">=5.3.10", - "psr/log": "~1.0" - }, - "require-dev": { - "joomla/test": "~1.1", - "phpunit/phpunit": "4.*", - "squizlabs/php_codesniffer": "1.*" - }, - "time": "2014-10-13 12:43:54", - "type": "joomla-package", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Joomla\\Application\\": "src/", - "Joomla\\Application\\Tests\\": "Tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "description": "Joomla Application Package", - "homepage": "https://github.com/joomla-framework/application", - "keywords": [ - "application", - "framework", - "joomla" - ] - }, { "name": "ircmaxell/password-compat", "version": "v1.0.4", @@ -605,17 +464,17 @@ }, { "name": "joomla/string", - "version": "1.2.2", - "version_normalized": "1.2.2.0", + "version": "1.3.0", + "version_normalized": "1.3.0.0", "source": { "type": "git", "url": "https://github.com/joomla-framework/string.git", - "reference": "9f7b27d6b2d48d65b2fe81b5c6d72225629ad692" + "reference": "0df8ead8c726a1f648e624d3bcbef8cf05c1d0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/string/zipball/9f7b27d6b2d48d65b2fe81b5c6d72225629ad692", - "reference": "9f7b27d6b2d48d65b2fe81b5c6d72225629ad692", + "url": "https://api.github.com/repos/joomla-framework/string/zipball/0df8ead8c726a1f648e624d3bcbef8cf05c1d0da", + "reference": "0df8ead8c726a1f648e624d3bcbef8cf05c1d0da", "shasum": "" }, "require": { @@ -626,7 +485,7 @@ "phpunit/phpunit": "4.*", "squizlabs/php_codesniffer": "1.*" }, - "time": "2015-03-13 12:29:00", + "time": "2015-03-26 01:02:20", "type": "joomla-package", "extra": { "branch-alias": { @@ -652,24 +511,73 @@ "string" ] }, + { + "name": "joomla/utilities", + "version": "1.3.3", + "version_normalized": "1.3.3.0", + "source": { + "type": "git", + "url": "https://github.com/joomla-framework/utilities.git", + "reference": "3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/joomla-framework/utilities/zipball/3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4", + "reference": "3e43b0806c194a92b58a176b73d6cc2dc6c9c3a4", + "shasum": "" + }, + "require": { + "joomla/string": "~1.3", + "php": ">=5.3.10" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "squizlabs/php_codesniffer": "1.*" + }, + "time": "2015-03-28 17:52:43", + "type": "joomla-package", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Joomla\\Utilities\\": "src/", + "Joomla\\Utilities\\Tests\\": "Tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "description": "Joomla Utilities Package", + "homepage": "https://github.com/joomla-framework/utilities", + "keywords": [ + "framework", + "joomla", + "utilities" + ] + }, { "name": "joomla/registry", - "version": "1.4.4", - "version_normalized": "1.4.4.0", + "version": "1.4.5", + "version_normalized": "1.4.5.0", "source": { "type": "git", "url": "https://github.com/joomla-framework/registry.git", - "reference": "730467978ad52677903e973bb33be2306eb161eb" + "reference": "4f926ba961ca45eb95076a1598c3ae689cb02fc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/registry/zipball/730467978ad52677903e973bb33be2306eb161eb", - "reference": "730467978ad52677903e973bb33be2306eb161eb", + "url": "https://api.github.com/repos/joomla-framework/registry/zipball/4f926ba961ca45eb95076a1598c3ae689cb02fc5", + "reference": "4f926ba961ca45eb95076a1598c3ae689cb02fc5", "shasum": "" }, "require": { "joomla/compat": "~1.0", - "joomla/string": "~1.2", + "joomla/string": "~1.3", "joomla/utilities": "~1.0", "php": ">=5.3.10" }, @@ -682,7 +590,7 @@ "suggest": { "symfony/yaml": "Install 2.* if you require YAML support." }, - "time": "2015-03-16 18:49:29", + "time": "2015-03-28 17:54:38", "type": "joomla-package", "extra": { "branch-alias": { @@ -709,29 +617,38 @@ ] }, { - "name": "joomla/utilities", - "version": "1.3.2", - "version_normalized": "1.3.2.0", + "name": "joomla/application", + "version": "1.4.0", + "version_normalized": "1.4.0.0", "source": { "type": "git", - "url": "https://github.com/joomla-framework/utilities.git", - "reference": "2e7f37a69162fea02059c764a318a920121f8b4a" + "url": "https://github.com/joomla-framework/application.git", + "reference": "185b68fe55537281385b637a90e11856ea01c8da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/joomla-framework/utilities/zipball/2e7f37a69162fea02059c764a318a920121f8b4a", - "reference": "2e7f37a69162fea02059c764a318a920121f8b4a", + "url": "https://api.github.com/repos/joomla-framework/application/zipball/185b68fe55537281385b637a90e11856ea01c8da", + "reference": "185b68fe55537281385b637a90e11856ea01c8da", "shasum": "" }, "require": { - "joomla/string": "~1.0", - "php": ">=5.3.10" + "joomla/input": "~1.2", + "joomla/registry": "~1.1", + "php": ">=5.3.10", + "psr/log": "~1.0" }, "require-dev": { + "joomla/session": "~1.1", + "joomla/test": "~1.1", + "joomla/uri": "~1.1", "phpunit/phpunit": "4.*", "squizlabs/php_codesniffer": "1.*" }, - "time": "2015-03-16 18:50:58", + "suggest": { + "joomla/session": "To use AbstractWebApplication with session support, install joomla/session", + "joomla/uri": "To use AbstractWebApplication, install joomla/uri" + }, + "time": "2015-03-06 17:37:01", "type": "joomla-package", "extra": { "branch-alias": { @@ -741,20 +658,106 @@ "installation-source": "dist", "autoload": { "psr-4": { - "Joomla\\Utilities\\": "src/", - "Joomla\\Utilities\\Tests\\": "Tests/" + "Joomla\\Application\\": "src/", + "Joomla\\Application\\Tests\\": "Tests/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "GPL-2.0+" ], - "description": "Joomla Utilities Package", - "homepage": "https://github.com/joomla-framework/utilities", + "description": "Joomla Application Package", + "homepage": "https://github.com/joomla-framework/application", + "keywords": [ + "application", + "framework", + "joomla" + ] + }, + { + "name": "joomla/event", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/joomla-framework/event.git", + "reference": "bb957bc45aba897e465384bbe21cd0eb79aca901" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/joomla-framework/event/zipball/bb957bc45aba897e465384bbe21cd0eb79aca901", + "reference": "bb957bc45aba897e465384bbe21cd0eb79aca901", + "shasum": "" + }, + "require": { + "php": ">=5.3.10" + }, + "time": "2014-02-09 01:30:54", + "type": "joomla-package", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Joomla\\Event\\": "src/", + "Joomla\\Event\\Tests\\": "Tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "description": "Joomla Event Package", + "homepage": "https://github.com/joomla-framework/event", + "keywords": [ + "event", + "framework", + "joomla" + ] + }, + { + "name": "joomla/session", + "version": "1.2.3", + "version_normalized": "1.2.3.0", + "target-dir": "Joomla/Session", + "source": { + "type": "git", + "url": "https://github.com/joomla-framework/session.git", + "reference": "ef955cf9642793c4ad5874f334069051c33ba604" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/joomla-framework/session/zipball/ef955cf9642793c4ad5874f334069051c33ba604", + "reference": "ef955cf9642793c4ad5874f334069051c33ba604", + "shasum": "" + }, + "require": { + "joomla/event": "~1.1", + "joomla/filter": "~1.0", + "php": ">=5.3.10" + }, + "require-dev": { + "joomla/test": "~1.0" + }, + "suggest": { + "joomla/database": "Install joomla/database if you want to use Database session storage." + }, + "time": "2014-08-18 17:41:06", + "type": "joomla-package", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Joomla\\Session": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "description": "Joomla Session Package", + "homepage": "https://github.com/joomla-framework/session", "keywords": [ "framework", "joomla", - "utilities" + "session" ] } ] diff --git a/libraries/vendor/joomla/application/src/AbstractApplication.php b/libraries/vendor/joomla/application/src/AbstractApplication.php index a921e1fa07a88..9842c80ecfb23 100644 --- a/libraries/vendor/joomla/application/src/AbstractApplication.php +++ b/libraries/vendor/joomla/application/src/AbstractApplication.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/AbstractCliApplication.php b/libraries/vendor/joomla/application/src/AbstractCliApplication.php index 9c1c601bfcb69..6ba345c5511af 100644 --- a/libraries/vendor/joomla/application/src/AbstractCliApplication.php +++ b/libraries/vendor/joomla/application/src/AbstractCliApplication.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/AbstractDaemonApplication.php b/libraries/vendor/joomla/application/src/AbstractDaemonApplication.php index 0fb8ebf8d2c5e..4fadb812483cd 100644 --- a/libraries/vendor/joomla/application/src/AbstractDaemonApplication.php +++ b/libraries/vendor/joomla/application/src/AbstractDaemonApplication.php @@ -2,13 +2,12 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Application; -use Joomla\Filesystem\Folder; use Joomla\Registry\Registry; use Joomla\Input\Cli; use Psr\Log\LoggerAwareInterface; diff --git a/libraries/vendor/joomla/application/src/AbstractWebApplication.php b/libraries/vendor/joomla/application/src/AbstractWebApplication.php index 961bc69f47290..fcdcd0786febc 100644 --- a/libraries/vendor/joomla/application/src/AbstractWebApplication.php +++ b/libraries/vendor/joomla/application/src/AbstractWebApplication.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ @@ -10,7 +10,6 @@ use Joomla\Uri\Uri; use Joomla\Input\Input; -use Joomla\String\String; use Joomla\Session\Session; use Joomla\Registry\Registry; @@ -285,7 +284,7 @@ public function redirect($url, $moved = false) */ if (!preg_match('#^[a-z]+\://#i', $url)) { - // Get a JURI instance for the requested URI. + // Get a Uri instance for the requested URI. $uri = new Uri($this->get('uri.request')); // Get a base URL to prepend from the requested URI. @@ -314,7 +313,7 @@ public function redirect($url, $moved = false) else { // We have to use a JavaScript redirect here because MSIE doesn't play nice with utf-8 URLs. - if (($this->client->engine == Web\WebClient::TRIDENT) && !String::is_ascii($url)) + if (($this->client->engine == Web\WebClient::TRIDENT) && !$this->isAscii($url)) { $html = '
'; $html .= ''; @@ -526,6 +525,11 @@ public function getBody($asArray = false) */ public function getSession() { + if ($this->session === null) + { + throw new \RuntimeException('A \Joomla\Session\Session object has not been set.'); + } + return $this->session; } @@ -776,7 +780,7 @@ public function checkToken($method = 'post') if (!$this->input->$method->get($token, '', 'alnum')) { - if ($this->session->isNew()) + if ($this->getSession()->isNew()) { // Redirect to login screen. $this->redirect('index.php'); @@ -808,6 +812,25 @@ public function getFormToken($forceNew = false) // @todo we need the user id somehow here $userId = 0; - return md5($this->get('secret') . $userId . $this->session->getToken($forceNew)); + return md5($this->get('secret') . $userId . $this->getSession()->getToken($forceNew)); + } + + /** + * Tests whether a string contains only 7bit ASCII bytes. + * + * You might use this to conditionally check whether a string + * needs handling as UTF-8 or not, potentially offering performance + * benefits by using the native PHP equivalent if it's just ASCII e.g.; + * + * @param string $str The string to test. + * + * @return boolean True if the string is all ASCII + * + * @since 1.4.0 + */ + public static function isAscii($str) + { + // Search for any bytes which are outside the ASCII range... + return (preg_match('/(?:[^\x00-\x7F])/', $str) !== 1); } } diff --git a/libraries/vendor/joomla/application/src/Cli/CliOutput.php b/libraries/vendor/joomla/application/src/Cli/CliOutput.php index bd6a808d9085a..ecec4912906e4 100644 --- a/libraries/vendor/joomla/application/src/Cli/CliOutput.php +++ b/libraries/vendor/joomla/application/src/Cli/CliOutput.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/ColorProcessor.php b/libraries/vendor/joomla/application/src/Cli/ColorProcessor.php index 4349d034e75e2..1a19932eec53e 100644 --- a/libraries/vendor/joomla/application/src/Cli/ColorProcessor.php +++ b/libraries/vendor/joomla/application/src/Cli/ColorProcessor.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/ColorStyle.php b/libraries/vendor/joomla/application/src/Cli/ColorStyle.php index 7f4726b3cab3a..a0d7ee9752316 100644 --- a/libraries/vendor/joomla/application/src/Cli/ColorStyle.php +++ b/libraries/vendor/joomla/application/src/Cli/ColorStyle.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/Output/Processor/ColorProcessor.php b/libraries/vendor/joomla/application/src/Cli/Output/Processor/ColorProcessor.php index 74e83b74c8917..3084a49bb0f2a 100644 --- a/libraries/vendor/joomla/application/src/Cli/Output/Processor/ColorProcessor.php +++ b/libraries/vendor/joomla/application/src/Cli/Output/Processor/ColorProcessor.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php b/libraries/vendor/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php index 6531db36e3c85..a9665d4f94c05 100644 --- a/libraries/vendor/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php +++ b/libraries/vendor/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/Output/Stdout.php b/libraries/vendor/joomla/application/src/Cli/Output/Stdout.php index ed789d52d9616..3291240845757 100644 --- a/libraries/vendor/joomla/application/src/Cli/Output/Stdout.php +++ b/libraries/vendor/joomla/application/src/Cli/Output/Stdout.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Cli/Output/Xml.php b/libraries/vendor/joomla/application/src/Cli/Output/Xml.php index 056e40c71b086..adb945f88c926 100644 --- a/libraries/vendor/joomla/application/src/Cli/Output/Xml.php +++ b/libraries/vendor/joomla/application/src/Cli/Output/Xml.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/application/src/Web/WebClient.php b/libraries/vendor/joomla/application/src/Web/WebClient.php index ade33c3252b48..83109f8ea19c5 100644 --- a/libraries/vendor/joomla/application/src/Web/WebClient.php +++ b/libraries/vendor/joomla/application/src/Web/WebClient.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework Application Package * - * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/registry/src/Format/Json.php b/libraries/vendor/joomla/registry/src/Format/Json.php index 16f3b597bf466..a2e9729eca659 100644 --- a/libraries/vendor/joomla/registry/src/Format/Json.php +++ b/libraries/vendor/joomla/registry/src/Format/Json.php @@ -9,7 +9,7 @@ namespace Joomla\Registry\Format; use Joomla\Registry\AbstractRegistryFormat; -use Joomla\String\String; +use Joomla\String\StringHelper; /** * JSON format handler for Registry. @@ -30,7 +30,7 @@ class Json extends AbstractRegistryFormat */ public function objectToString($object, $options = array()) { - return String::unicode_to_utf8(json_encode($object)); + return StringHelper::unicode_to_utf8(json_encode($object)); } /** diff --git a/libraries/vendor/joomla/string/src/Inflector.php b/libraries/vendor/joomla/string/src/Inflector.php index 4100b1c514de2..89b35aec5e892 100644 --- a/libraries/vendor/joomla/string/src/Inflector.php +++ b/libraries/vendor/joomla/string/src/Inflector.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework String Package * - * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/string/src/Normalise.php b/libraries/vendor/joomla/string/src/Normalise.php index e11437666a058..ca73c8bdccd27 100644 --- a/libraries/vendor/joomla/string/src/Normalise.php +++ b/libraries/vendor/joomla/string/src/Normalise.php @@ -2,7 +2,7 @@ /** * Part of the Joomla Framework String Package * - * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ diff --git a/libraries/vendor/joomla/string/src/String.php b/libraries/vendor/joomla/string/src/String.php index 4eb3a2d1a113c..f535e0874efb9 100644 --- a/libraries/vendor/joomla/string/src/String.php +++ b/libraries/vendor/joomla/string/src/String.php @@ -2,840 +2,20 @@ /** * Part of the Joomla Framework String Package * - * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved. + * @copyright Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\String; -// PHP mbstring and iconv local configuration -if (version_compare(PHP_VERSION, '5.6', '>=')) -{ - @ini_set('default_charset', 'UTF-8'); -} -else -{ - // Check if mbstring extension is loaded and attempt to load it if not present except for windows - if (extension_loaded('mbstring')) - { - @ini_set('mbstring.internal_encoding', 'UTF-8'); - @ini_set('mbstring.http_input', 'UTF-8'); - @ini_set('mbstring.http_output', 'UTF-8'); - } - - // Same for iconv - if (function_exists('iconv')) - { - iconv_set_encoding('internal_encoding', 'UTF-8'); - iconv_set_encoding('input_encoding', 'UTF-8'); - iconv_set_encoding('output_encoding', 'UTF-8'); - } -} - -/** - * Include the utf8 package - */ -if (!defined('UTF8')) -{ - require_once __DIR__ . '/phputf8/utf8.php'; -} - -if (!function_exists('utf8_strcasecmp')) -{ - require_once __DIR__ . '/phputf8/strcasecmp.php'; -} - /** * String handling class for utf-8 data * Wraps the phputf8 library * All functions assume the validity of utf-8 strings. * - * @since 1.0 + * @since 1.0 + * @deprecated 2.0 Use StringHelper instead */ -abstract class String +abstract class String extends StringHelper { - /** - * Increment styles. - * - * @var array - * @since 1.0 - */ - protected static $incrementStyles = array( - 'dash' => array( - '#-(\d+)$#', - '-%d' - ), - 'default' => array( - array('#\((\d+)\)$#', '#\(\d+\)$#'), - array(' (%d)', '(%d)'), - ), - ); - - /** - * Increments a trailing number in a string. - * - * Used to easily create distinct labels when copying objects. The method has the following styles: - * - * default: "Label" becomes "Label (2)" - * dash: "Label" becomes "Label-2" - * - * @param string $string The source string. - * @param string $style The the style (default|dash). - * @param integer $n If supplied, this number is used for the copy, otherwise it is the 'next' number. - * - * @return string The incremented string. - * - * @since 1.0 - */ - public static function increment($string, $style = 'default', $n = 0) - { - $styleSpec = isset(self::$incrementStyles[$style]) ? self::$incrementStyles[$style] : self::$incrementStyles['default']; - - // Regular expression search and replace patterns. - if (is_array($styleSpec[0])) - { - $rxSearch = $styleSpec[0][0]; - $rxReplace = $styleSpec[0][1]; - } - else - { - $rxSearch = $rxReplace = $styleSpec[0]; - } - - // New and old (existing) sprintf formats. - if (is_array($styleSpec[1])) - { - $newFormat = $styleSpec[1][0]; - $oldFormat = $styleSpec[1][1]; - } - else - { - $newFormat = $oldFormat = $styleSpec[1]; - } - - // Check if we are incrementing an existing pattern, or appending a new one. - if (preg_match($rxSearch, $string, $matches)) - { - $n = empty($n) ? ($matches[1] + 1) : $n; - $string = preg_replace($rxReplace, sprintf($oldFormat, $n), $string); - } - else - { - $n = empty($n) ? 2 : $n; - $string .= sprintf($newFormat, $n); - } - - return $string; - } - - /** - * Tests whether a string contains only 7bit ASCII bytes. - * You might use this to conditionally check whether a string - * needs handling as UTF-8 or not, potentially offering performance - * benefits by using the native PHP equivalent if it's just ASCII e.g.; - * - *
- * if (String::is_ascii($someString))
- * {
- * // It's just ASCII - use the native PHP version
- * $someString = strtolower($someString);
- * }
- * else
- * {
- * $someString = String::strtolower($someString);
- * }
- *
- *
- * @param string $str The string to test.
- *
- * @return boolean True if the string is all ASCII
- *
- * @since 1.0
- */
- public static function is_ascii($str)
- {
- require_once __DIR__ . '/phputf8/utils/ascii.php';
-
- return utf8_is_ascii($str);
- }
-
- /**
- * UTF-8 aware alternative to strpos.
- *
- * Find position of first occurrence of a string.
- *
- * @param string $str String being examined
- * @param string $search String being searched for
- * @param integer $offset Optional, specifies the position from which the search should be performed
- *
- * @return mixed Number of characters before the first match or FALSE on failure
- *
- * @see http://www.php.net/strpos
- * @since 1.0
- */
- public static function strpos($str, $search, $offset = false)
- {
- if ($offset === false)
- {
- return utf8_strpos($str, $search);
- }
-
- return utf8_strpos($str, $search, $offset);
- }
-
- /**
- * UTF-8 aware alternative to strrpos
- * Finds position of last occurrence of a string
- *
- * @param string $str String being examined.
- * @param string $search String being searched for.
- * @param integer $offset Offset from the left of the string.
- *
- * @return mixed Number of characters before the last match or false on failure
- *
- * @see http://www.php.net/strrpos
- * @since 1.0
- */
- public static function strrpos($str, $search, $offset = 0)
- {
- return utf8_strrpos($str, $search, $offset);
- }
-
- /**
- * UTF-8 aware alternative to substr
- * Return part of a string given character offset (and optionally length)
- *
- * @param string $str String being processed
- * @param integer $offset Number of UTF-8 characters offset (from left)
- * @param integer $length Optional length in UTF-8 characters from offset
- *
- * @return mixed string or FALSE if failure
- *
- * @see http://www.php.net/substr
- * @since 1.0
- */
- public static function substr($str, $offset, $length = false)
- {
- if ($length === false)
- {
- return utf8_substr($str, $offset);
- }
-
- return utf8_substr($str, $offset, $length);
- }
-
- /**
- * UTF-8 aware alternative to strtlower
- *
- * Make a string lowercase
- * Note: The concept of a characters "case" only exists is some alphabets
- * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
- * not exist in the Chinese alphabet, for example. See Unicode Standard
- * Annex #21: Case Mappings
- *
- * @param string $str String being processed
- *
- * @return mixed Either string in lowercase or FALSE is UTF-8 invalid
- *
- * @see http://www.php.net/strtolower
- * @since 1.0
- */
- public static function strtolower($str)
- {
- return utf8_strtolower($str);
- }
-
- /**
- * UTF-8 aware alternative to strtoupper
- * Make a string uppercase
- * Note: The concept of a characters "case" only exists is some alphabets
- * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
- * not exist in the Chinese alphabet, for example. See Unicode Standard
- * Annex #21: Case Mappings
- *
- * @param string $str String being processed
- *
- * @return mixed Either string in uppercase or FALSE is UTF-8 invalid
- *
- * @see http://www.php.net/strtoupper
- * @since 1.0
- */
- public static function strtoupper($str)
- {
- return utf8_strtoupper($str);
- }
-
- /**
- * UTF-8 aware alternative to strlen.
- *
- * Returns the number of characters in the string (NOT THE NUMBER OF BYTES),
- *
- * @param string $str UTF-8 string.
- *
- * @return integer Number of UTF-8 characters in string.
- *
- * @see http://www.php.net/strlen
- * @since 1.0
- */
- public static function strlen($str)
- {
- return utf8_strlen($str);
- }
-
- /**
- * UTF-8 aware alternative to str_ireplace
- * Case-insensitive version of str_replace
- *
- * @param string $search String to search
- * @param string $replace Existing string to replace
- * @param string $str New string to replace with
- * @param integer $count Optional count value to be passed by referene
- *
- * @return string UTF-8 String
- *
- * @see http://www.php.net/str_ireplace
- * @since 1.0
- */
- public static function str_ireplace($search, $replace, $str, $count = null)
- {
- require_once __DIR__ . '/phputf8/str_ireplace.php';
-
- if ($count === false)
- {
- return utf8_ireplace($search, $replace, $str);
- }
-
- return utf8_ireplace($search, $replace, $str, $count);
- }
-
- /**
- * UTF-8 aware alternative to str_split
- * Convert a string to an array
- *
- * @param string $str UTF-8 encoded string to process
- * @param integer $split_len Number to characters to split string by
- *
- * @return array
- *
- * @see http://www.php.net/str_split
- * @since 1.0
- */
- public static function str_split($str, $split_len = 1)
- {
- require_once __DIR__ . '/phputf8/str_split.php';
-
- return utf8_str_split($str, $split_len);
- }
-
- /**
- * UTF-8/LOCALE aware alternative to strcasecmp
- * A case insensitive string comparison
- *
- * @param string $str1 string 1 to compare
- * @param string $str2 string 2 to compare
- * @param mixed $locale The locale used by strcoll or false to use classical comparison
- *
- * @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
- *
- * @see http://www.php.net/strcasecmp
- * @see http://www.php.net/strcoll
- * @see http://www.php.net/setlocale
- * @since 1.0
- */
- public static function strcasecmp($str1, $str2, $locale = false)
- {
- if ($locale)
- {
- // Get current locale
- $locale0 = setlocale(LC_COLLATE, 0);
-
- if (!$locale = setlocale(LC_COLLATE, $locale))
- {
- $locale = $locale0;
- }
-
- // See if we have successfully set locale to UTF-8
- if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
- {
- $encoding = 'CP' . $m[1];
- }
- elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
- {
- $encoding = 'UTF-8';
- }
- else
- {
- $encoding = 'nonrecodable';
- }
-
- // If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
- if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
- {
- return strcoll(utf8_strtolower($str1), utf8_strtolower($str2));
- }
-
- return strcoll(
- self::transcode(utf8_strtolower($str1), 'UTF-8', $encoding),
- self::transcode(utf8_strtolower($str2), 'UTF-8', $encoding)
- );
- }
-
- return utf8_strcasecmp($str1, $str2);
- }
-
- /**
- * UTF-8/LOCALE aware alternative to strcmp
- * A case sensitive string comparison
- *
- * @param string $str1 string 1 to compare
- * @param string $str2 string 2 to compare
- * @param mixed $locale The locale used by strcoll or false to use classical comparison
- *
- * @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
- *
- * @see http://www.php.net/strcmp
- * @see http://www.php.net/strcoll
- * @see http://www.php.net/setlocale
- * @since 1.0
- */
- public static function strcmp($str1, $str2, $locale = false)
- {
- if ($locale)
- {
- // Get current locale
- $locale0 = setlocale(LC_COLLATE, 0);
-
- if (!$locale = setlocale(LC_COLLATE, $locale))
- {
- $locale = $locale0;
- }
-
- // See if we have successfully set locale to UTF-8
- if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
- {
- $encoding = 'CP' . $m[1];
- }
- elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
- {
- $encoding = 'UTF-8';
- }
- else
- {
- $encoding = 'nonrecodable';
- }
-
- // If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
- if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
- {
- return strcoll($str1, $str2);
- }
-
- return strcoll(self::transcode($str1, 'UTF-8', $encoding), self::transcode($str2, 'UTF-8', $encoding));
- }
-
- return strcmp($str1, $str2);
- }
-
- /**
- * UTF-8 aware alternative to strcspn
- * Find length of initial segment not matching mask
- *
- * @param string $str The string to process
- * @param string $mask The mask
- * @param integer $start Optional starting character position (in characters)
- * @param integer $length Optional length
- *
- * @return integer The length of the initial segment of str1 which does not contain any of the characters in str2
- *
- * @see http://www.php.net/strcspn
- * @since 1.0
- */
- public static function strcspn($str, $mask, $start = null, $length = null)
- {
- require_once __DIR__ . '/phputf8/strcspn.php';
-
- if ($start === false && $length === false)
- {
- return utf8_strcspn($str, $mask);
- }
-
- if ($length === false)
- {
- return utf8_strcspn($str, $mask, $start);
- }
-
- return utf8_strcspn($str, $mask, $start, $length);
- }
-
- /**
- * UTF-8 aware alternative to stristr
- * Returns all of haystack from the first occurrence of needle to the end.
- * needle and haystack are examined in a case-insensitive manner
- * Find first occurrence of a string using case insensitive comparison
- *
- * @param string $str The haystack
- * @param string $search The needle
- *
- * @return string the sub string
- *
- * @see http://www.php.net/stristr
- * @since 1.0
- */
- public static function stristr($str, $search)
- {
- require_once __DIR__ . '/phputf8/stristr.php';
-
- return utf8_stristr($str, $search);
- }
-
- /**
- * UTF-8 aware alternative to strrev
- * Reverse a string
- *
- * @param string $str String to be reversed
- *
- * @return string The string in reverse character order
- *
- * @see http://www.php.net/strrev
- * @since 1.0
- */
- public static function strrev($str)
- {
- require_once __DIR__ . '/phputf8/strrev.php';
-
- return utf8_strrev($str);
- }
-
- /**
- * UTF-8 aware alternative to strspn
- * Find length of initial segment matching mask
- *
- * @param string $str The haystack
- * @param string $mask The mask
- * @param integer $start Start optional
- * @param integer $length Length optional
- *
- * @return integer
- *
- * @see http://www.php.net/strspn
- * @since 1.0
- */
- public static function strspn($str, $mask, $start = null, $length = null)
- {
- require_once __DIR__ . '/phputf8/strspn.php';
-
- if ($start === null && $length === null)
- {
- return utf8_strspn($str, $mask);
- }
-
- if ($length === null)
- {
- return utf8_strspn($str, $mask, $start);
- }
-
- return utf8_strspn($str, $mask, $start, $length);
- }
-
- /**
- * UTF-8 aware substr_replace
- * Replace text within a portion of a string
- *
- * @param string $str The haystack
- * @param string $repl The replacement string
- * @param integer $start Start
- * @param integer $length Length (optional)
- *
- * @return string
- *
- * @see http://www.php.net/substr_replace
- * @since 1.0
- */
- public static function substr_replace($str, $repl, $start, $length = null)
- {
- // Loaded by library loader
- if ($length === false)
- {
- return utf8_substr_replace($str, $repl, $start);
- }
-
- return utf8_substr_replace($str, $repl, $start, $length);
- }
-
- /**
- * UTF-8 aware replacement for ltrim()
- *
- * Strip whitespace (or other characters) from the beginning of a string
- * You only need to use this if you are supplying the charlist
- * optional arg and it contains UTF-8 characters. Otherwise ltrim will
- * work normally on a UTF-8 string
- *
- * @param string $str The string to be trimmed
- * @param string $charlist The optional charlist of additional characters to trim
- *
- * @return string The trimmed string
- *
- * @see http://www.php.net/ltrim
- * @since 1.0
- */
- public static function ltrim($str, $charlist = false)
- {
- if (empty($charlist) && $charlist !== false)
- {
- return $str;
- }
-
- require_once __DIR__ . '/phputf8/trim.php';
-
- if ($charlist === false)
- {
- return utf8_ltrim($str);
- }
-
- return utf8_ltrim($str, $charlist);
- }
-
- /**
- * UTF-8 aware replacement for rtrim()
- * Strip whitespace (or other characters) from the end of a string
- * You only need to use this if you are supplying the charlist
- * optional arg and it contains UTF-8 characters. Otherwise rtrim will
- * work normally on a UTF-8 string
- *
- * @param string $str The string to be trimmed
- * @param string $charlist The optional charlist of additional characters to trim
- *
- * @return string The trimmed string
- *
- * @see http://www.php.net/rtrim
- * @since 1.0
- */
- public static function rtrim($str, $charlist = false)
- {
- if (empty($charlist) && $charlist !== false)
- {
- return $str;
- }
-
- require_once __DIR__ . '/phputf8/trim.php';
-
- if ($charlist === false)
- {
- return utf8_rtrim($str);
- }
-
- return utf8_rtrim($str, $charlist);
- }
-
- /**
- * UTF-8 aware replacement for trim()
- * Strip whitespace (or other characters) from the beginning and end of a string
- * Note: you only need to use this if you are supplying the charlist
- * optional arg and it contains UTF-8 characters. Otherwise trim will
- * work normally on a UTF-8 string
- *
- * @param string $str The string to be trimmed
- * @param string $charlist The optional charlist of additional characters to trim
- *
- * @return string The trimmed string
- *
- * @see http://www.php.net/trim
- * @since 1.0
- */
- public static function trim($str, $charlist = false)
- {
- if (empty($charlist) && $charlist !== false)
- {
- return $str;
- }
-
- require_once __DIR__ . '/phputf8/trim.php';
-
- if ($charlist === false)
- {
- return utf8_trim($str);
- }
-
- return utf8_trim($str, $charlist);
- }
-
- /**
- * UTF-8 aware alternative to ucfirst
- * Make a string's first character uppercase or all words' first character uppercase
- *
- * @param string $str String to be processed
- * @param string $delimiter The words delimiter (null means do not split the string)
- * @param string $newDelimiter The new words delimiter (null means equal to $delimiter)
- *
- * @return string If $delimiter is null, return the string with first character as upper case (if applicable)
- * else consider the string of words separated by the delimiter, apply the ucfirst to each words
- * and return the string with the new delimiter
- *
- * @see http://www.php.net/ucfirst
- * @since 1.0
- */
- public static function ucfirst($str, $delimiter = null, $newDelimiter = null)
- {
- require_once __DIR__ . '/phputf8/ucfirst.php';
-
- if ($delimiter === null)
- {
- return utf8_ucfirst($str);
- }
-
- if ($newDelimiter === null)
- {
- $newDelimiter = $delimiter;
- }
-
- return implode($newDelimiter, array_map('utf8_ucfirst', explode($delimiter, $str)));
- }
-
- /**
- * UTF-8 aware alternative to ucwords
- * Uppercase the first character of each word in a string
- *
- * @param string $str String to be processed
- *
- * @return string String with first char of each word uppercase
- *
- * @see http://www.php.net/ucwords
- * @since 1.0
- */
- public static function ucwords($str)
- {
- require_once __DIR__ . '/phputf8/ucwords.php';
-
- return utf8_ucwords($str);
- }
-
- /**
- * Transcode a string.
- *
- * @param string $source The string to transcode.
- * @param string $from_encoding The source encoding.
- * @param string $to_encoding The target encoding.
- *
- * @return mixed The transcoded string, or null if the source was not a string.
- *
- * @link https://bugs.php.net/bug.php?id=48147
- *
- * @since 1.0
- */
- public static function transcode($source, $from_encoding, $to_encoding)
- {
- if (is_string($source))
- {
- switch (ICONV_IMPL)
- {
- case 'glibc':
- return @iconv($from_encoding, $to_encoding . '//TRANSLIT,IGNORE', $source);
-
- case 'libiconv':
- default:
- return iconv($from_encoding, $to_encoding . '//IGNORE//TRANSLIT', $source);
- }
- }
-
- return null;
- }
-
- /**
- * Tests a string as to whether it's valid UTF-8 and supported by the Unicode standard.
- *
- * Note: this function has been modified to simple return true or false.
- *
- * @param string $str UTF-8 encoded string.
- *
- * @return boolean true if valid
- *
- * @author
+ * if (String::is_ascii($someString))
+ * {
+ * // It's just ASCII - use the native PHP version
+ * $someString = strtolower($someString);
+ * }
+ * else
+ * {
+ * $someString = String::strtolower($someString);
+ * }
+ *
+ *
+ * @param string $str The string to test.
+ *
+ * @return boolean True if the string is all ASCII
+ *
+ * @since 1.3.0
+ */
+ public static function is_ascii($str)
+ {
+ require_once __DIR__ . '/phputf8/utils/ascii.php';
+
+ return utf8_is_ascii($str);
+ }
+
+ /**
+ * UTF-8 aware alternative to strpos.
+ *
+ * Find position of first occurrence of a string.
+ *
+ * @param string $str String being examined
+ * @param string $search String being searched for
+ * @param integer $offset Optional, specifies the position from which the search should be performed
+ *
+ * @return mixed Number of characters before the first match or FALSE on failure
+ *
+ * @see http://www.php.net/strpos
+ * @since 1.3.0
+ */
+ public static function strpos($str, $search, $offset = false)
+ {
+ if ($offset === false)
+ {
+ return utf8_strpos($str, $search);
+ }
+
+ return utf8_strpos($str, $search, $offset);
+ }
+
+ /**
+ * UTF-8 aware alternative to strrpos
+ * Finds position of last occurrence of a string
+ *
+ * @param string $str String being examined.
+ * @param string $search String being searched for.
+ * @param integer $offset Offset from the left of the string.
+ *
+ * @return mixed Number of characters before the last match or false on failure
+ *
+ * @see http://www.php.net/strrpos
+ * @since 1.3.0
+ */
+ public static function strrpos($str, $search, $offset = 0)
+ {
+ return utf8_strrpos($str, $search, $offset);
+ }
+
+ /**
+ * UTF-8 aware alternative to substr
+ * Return part of a string given character offset (and optionally length)
+ *
+ * @param string $str String being processed
+ * @param integer $offset Number of UTF-8 characters offset (from left)
+ * @param integer $length Optional length in UTF-8 characters from offset
+ *
+ * @return mixed string or FALSE if failure
+ *
+ * @see http://www.php.net/substr
+ * @since 1.3.0
+ */
+ public static function substr($str, $offset, $length = false)
+ {
+ if ($length === false)
+ {
+ return utf8_substr($str, $offset);
+ }
+
+ return utf8_substr($str, $offset, $length);
+ }
+
+ /**
+ * UTF-8 aware alternative to strtlower
+ *
+ * Make a string lowercase
+ * Note: The concept of a characters "case" only exists is some alphabets
+ * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
+ * not exist in the Chinese alphabet, for example. See Unicode Standard
+ * Annex #21: Case Mappings
+ *
+ * @param string $str String being processed
+ *
+ * @return mixed Either string in lowercase or FALSE is UTF-8 invalid
+ *
+ * @see http://www.php.net/strtolower
+ * @since 1.3.0
+ */
+ public static function strtolower($str)
+ {
+ return utf8_strtolower($str);
+ }
+
+ /**
+ * UTF-8 aware alternative to strtoupper
+ * Make a string uppercase
+ * Note: The concept of a characters "case" only exists is some alphabets
+ * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
+ * not exist in the Chinese alphabet, for example. See Unicode Standard
+ * Annex #21: Case Mappings
+ *
+ * @param string $str String being processed
+ *
+ * @return mixed Either string in uppercase or FALSE is UTF-8 invalid
+ *
+ * @see http://www.php.net/strtoupper
+ * @since 1.3.0
+ */
+ public static function strtoupper($str)
+ {
+ return utf8_strtoupper($str);
+ }
+
+ /**
+ * UTF-8 aware alternative to strlen.
+ *
+ * Returns the number of characters in the string (NOT THE NUMBER OF BYTES),
+ *
+ * @param string $str UTF-8 string.
+ *
+ * @return integer Number of UTF-8 characters in string.
+ *
+ * @see http://www.php.net/strlen
+ * @since 1.3.0
+ */
+ public static function strlen($str)
+ {
+ return utf8_strlen($str);
+ }
+
+ /**
+ * UTF-8 aware alternative to str_ireplace
+ * Case-insensitive version of str_replace
+ *
+ * @param string $search String to search
+ * @param string $replace Existing string to replace
+ * @param string $str New string to replace with
+ * @param integer $count Optional count value to be passed by referene
+ *
+ * @return string UTF-8 String
+ *
+ * @see http://www.php.net/str_ireplace
+ * @since 1.3.0
+ */
+ public static function str_ireplace($search, $replace, $str, $count = null)
+ {
+ require_once __DIR__ . '/phputf8/str_ireplace.php';
+
+ if ($count === false)
+ {
+ return utf8_ireplace($search, $replace, $str);
+ }
+
+ return utf8_ireplace($search, $replace, $str, $count);
+ }
+
+ /**
+ * UTF-8 aware alternative to str_split
+ * Convert a string to an array
+ *
+ * @param string $str UTF-8 encoded string to process
+ * @param integer $split_len Number to characters to split string by
+ *
+ * @return array
+ *
+ * @see http://www.php.net/str_split
+ * @since 1.3.0
+ */
+ public static function str_split($str, $split_len = 1)
+ {
+ require_once __DIR__ . '/phputf8/str_split.php';
+
+ return utf8_str_split($str, $split_len);
+ }
+
+ /**
+ * UTF-8/LOCALE aware alternative to strcasecmp
+ * A case insensitive string comparison
+ *
+ * @param string $str1 string 1 to compare
+ * @param string $str2 string 2 to compare
+ * @param mixed $locale The locale used by strcoll or false to use classical comparison
+ *
+ * @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
+ *
+ * @see http://www.php.net/strcasecmp
+ * @see http://www.php.net/strcoll
+ * @see http://www.php.net/setlocale
+ * @since 1.3.0
+ */
+ public static function strcasecmp($str1, $str2, $locale = false)
+ {
+ if ($locale)
+ {
+ // Get current locale
+ $locale0 = setlocale(LC_COLLATE, 0);
+
+ if (!$locale = setlocale(LC_COLLATE, $locale))
+ {
+ $locale = $locale0;
+ }
+
+ // See if we have successfully set locale to UTF-8
+ if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
+ {
+ $encoding = 'CP' . $m[1];
+ }
+ elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
+ {
+ $encoding = 'UTF-8';
+ }
+ else
+ {
+ $encoding = 'nonrecodable';
+ }
+
+ // If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
+ if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
+ {
+ return strcoll(utf8_strtolower($str1), utf8_strtolower($str2));
+ }
+
+ return strcoll(
+ self::transcode(utf8_strtolower($str1), 'UTF-8', $encoding),
+ self::transcode(utf8_strtolower($str2), 'UTF-8', $encoding)
+ );
+ }
+
+ return utf8_strcasecmp($str1, $str2);
+ }
+
+ /**
+ * UTF-8/LOCALE aware alternative to strcmp
+ * A case sensitive string comparison
+ *
+ * @param string $str1 string 1 to compare
+ * @param string $str2 string 2 to compare
+ * @param mixed $locale The locale used by strcoll or false to use classical comparison
+ *
+ * @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
+ *
+ * @see http://www.php.net/strcmp
+ * @see http://www.php.net/strcoll
+ * @see http://www.php.net/setlocale
+ * @since 1.3.0
+ */
+ public static function strcmp($str1, $str2, $locale = false)
+ {
+ if ($locale)
+ {
+ // Get current locale
+ $locale0 = setlocale(LC_COLLATE, 0);
+
+ if (!$locale = setlocale(LC_COLLATE, $locale))
+ {
+ $locale = $locale0;
+ }
+
+ // See if we have successfully set locale to UTF-8
+ if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
+ {
+ $encoding = 'CP' . $m[1];
+ }
+ elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
+ {
+ $encoding = 'UTF-8';
+ }
+ else
+ {
+ $encoding = 'nonrecodable';
+ }
+
+ // If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
+ if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
+ {
+ return strcoll($str1, $str2);
+ }
+
+ return strcoll(self::transcode($str1, 'UTF-8', $encoding), self::transcode($str2, 'UTF-8', $encoding));
+ }
+
+ return strcmp($str1, $str2);
+ }
+
+ /**
+ * UTF-8 aware alternative to strcspn
+ * Find length of initial segment not matching mask
+ *
+ * @param string $str The string to process
+ * @param string $mask The mask
+ * @param integer $start Optional starting character position (in characters)
+ * @param integer $length Optional length
+ *
+ * @return integer The length of the initial segment of str1 which does not contain any of the characters in str2
+ *
+ * @see http://www.php.net/strcspn
+ * @since 1.3.0
+ */
+ public static function strcspn($str, $mask, $start = null, $length = null)
+ {
+ require_once __DIR__ . '/phputf8/strcspn.php';
+
+ if ($start === false && $length === false)
+ {
+ return utf8_strcspn($str, $mask);
+ }
+
+ if ($length === false)
+ {
+ return utf8_strcspn($str, $mask, $start);
+ }
+
+ return utf8_strcspn($str, $mask, $start, $length);
+ }
+
+ /**
+ * UTF-8 aware alternative to stristr
+ * Returns all of haystack from the first occurrence of needle to the end.
+ * needle and haystack are examined in a case-insensitive manner
+ * Find first occurrence of a string using case insensitive comparison
+ *
+ * @param string $str The haystack
+ * @param string $search The needle
+ *
+ * @return string the sub string
+ *
+ * @see http://www.php.net/stristr
+ * @since 1.3.0
+ */
+ public static function stristr($str, $search)
+ {
+ require_once __DIR__ . '/phputf8/stristr.php';
+
+ return utf8_stristr($str, $search);
+ }
+
+ /**
+ * UTF-8 aware alternative to strrev
+ * Reverse a string
+ *
+ * @param string $str String to be reversed
+ *
+ * @return string The string in reverse character order
+ *
+ * @see http://www.php.net/strrev
+ * @since 1.3.0
+ */
+ public static function strrev($str)
+ {
+ require_once __DIR__ . '/phputf8/strrev.php';
+
+ return utf8_strrev($str);
+ }
+
+ /**
+ * UTF-8 aware alternative to strspn
+ * Find length of initial segment matching mask
+ *
+ * @param string $str The haystack
+ * @param string $mask The mask
+ * @param integer $start Start optional
+ * @param integer $length Length optional
+ *
+ * @return integer
+ *
+ * @see http://www.php.net/strspn
+ * @since 1.3.0
+ */
+ public static function strspn($str, $mask, $start = null, $length = null)
+ {
+ require_once __DIR__ . '/phputf8/strspn.php';
+
+ if ($start === null && $length === null)
+ {
+ return utf8_strspn($str, $mask);
+ }
+
+ if ($length === null)
+ {
+ return utf8_strspn($str, $mask, $start);
+ }
+
+ return utf8_strspn($str, $mask, $start, $length);
+ }
+
+ /**
+ * UTF-8 aware substr_replace
+ * Replace text within a portion of a string
+ *
+ * @param string $str The haystack
+ * @param string $repl The replacement string
+ * @param integer $start Start
+ * @param integer $length Length (optional)
+ *
+ * @return string
+ *
+ * @see http://www.php.net/substr_replace
+ * @since 1.3.0
+ */
+ public static function substr_replace($str, $repl, $start, $length = null)
+ {
+ // Loaded by library loader
+ if ($length === false)
+ {
+ return utf8_substr_replace($str, $repl, $start);
+ }
+
+ return utf8_substr_replace($str, $repl, $start, $length);
+ }
+
+ /**
+ * UTF-8 aware replacement for ltrim()
+ *
+ * Strip whitespace (or other characters) from the beginning of a string
+ * You only need to use this if you are supplying the charlist
+ * optional arg and it contains UTF-8 characters. Otherwise ltrim will
+ * work normally on a UTF-8 string
+ *
+ * @param string $str The string to be trimmed
+ * @param string $charlist The optional charlist of additional characters to trim
+ *
+ * @return string The trimmed string
+ *
+ * @see http://www.php.net/ltrim
+ * @since 1.3.0
+ */
+ public static function ltrim($str, $charlist = false)
+ {
+ if (empty($charlist) && $charlist !== false)
+ {
+ return $str;
+ }
+
+ require_once __DIR__ . '/phputf8/trim.php';
+
+ if ($charlist === false)
+ {
+ return utf8_ltrim($str);
+ }
+
+ return utf8_ltrim($str, $charlist);
+ }
+
+ /**
+ * UTF-8 aware replacement for rtrim()
+ * Strip whitespace (or other characters) from the end of a string
+ * You only need to use this if you are supplying the charlist
+ * optional arg and it contains UTF-8 characters. Otherwise rtrim will
+ * work normally on a UTF-8 string
+ *
+ * @param string $str The string to be trimmed
+ * @param string $charlist The optional charlist of additional characters to trim
+ *
+ * @return string The trimmed string
+ *
+ * @see http://www.php.net/rtrim
+ * @since 1.3.0
+ */
+ public static function rtrim($str, $charlist = false)
+ {
+ if (empty($charlist) && $charlist !== false)
+ {
+ return $str;
+ }
+
+ require_once __DIR__ . '/phputf8/trim.php';
+
+ if ($charlist === false)
+ {
+ return utf8_rtrim($str);
+ }
+
+ return utf8_rtrim($str, $charlist);
+ }
+
+ /**
+ * UTF-8 aware replacement for trim()
+ * Strip whitespace (or other characters) from the beginning and end of a string
+ * Note: you only need to use this if you are supplying the charlist
+ * optional arg and it contains UTF-8 characters. Otherwise trim will
+ * work normally on a UTF-8 string
+ *
+ * @param string $str The string to be trimmed
+ * @param string $charlist The optional charlist of additional characters to trim
+ *
+ * @return string The trimmed string
+ *
+ * @see http://www.php.net/trim
+ * @since 1.3.0
+ */
+ public static function trim($str, $charlist = false)
+ {
+ if (empty($charlist) && $charlist !== false)
+ {
+ return $str;
+ }
+
+ require_once __DIR__ . '/phputf8/trim.php';
+
+ if ($charlist === false)
+ {
+ return utf8_trim($str);
+ }
+
+ return utf8_trim($str, $charlist);
+ }
+
+ /**
+ * UTF-8 aware alternative to ucfirst
+ * Make a string's first character uppercase or all words' first character uppercase
+ *
+ * @param string $str String to be processed
+ * @param string $delimiter The words delimiter (null means do not split the string)
+ * @param string $newDelimiter The new words delimiter (null means equal to $delimiter)
+ *
+ * @return string If $delimiter is null, return the string with first character as upper case (if applicable)
+ * else consider the string of words separated by the delimiter, apply the ucfirst to each words
+ * and return the string with the new delimiter
+ *
+ * @see http://www.php.net/ucfirst
+ * @since 1.3.0
+ */
+ public static function ucfirst($str, $delimiter = null, $newDelimiter = null)
+ {
+ require_once __DIR__ . '/phputf8/ucfirst.php';
+
+ if ($delimiter === null)
+ {
+ return utf8_ucfirst($str);
+ }
+
+ if ($newDelimiter === null)
+ {
+ $newDelimiter = $delimiter;
+ }
+
+ return implode($newDelimiter, array_map('utf8_ucfirst', explode($delimiter, $str)));
+ }
+
+ /**
+ * UTF-8 aware alternative to ucwords
+ * Uppercase the first character of each word in a string
+ *
+ * @param string $str String to be processed
+ *
+ * @return string String with first char of each word uppercase
+ *
+ * @see http://www.php.net/ucwords
+ * @since 1.3.0
+ */
+ public static function ucwords($str)
+ {
+ require_once __DIR__ . '/phputf8/ucwords.php';
+
+ return utf8_ucwords($str);
+ }
+
+ /**
+ * Transcode a string.
+ *
+ * @param string $source The string to transcode.
+ * @param string $from_encoding The source encoding.
+ * @param string $to_encoding The target encoding.
+ *
+ * @return mixed The transcoded string, or null if the source was not a string.
+ *
+ * @link https://bugs.php.net/bug.php?id=48147
+ *
+ * @since 1.3.0
+ */
+ public static function transcode($source, $from_encoding, $to_encoding)
+ {
+ if (is_string($source))
+ {
+ switch (ICONV_IMPL)
+ {
+ case 'glibc':
+ return @iconv($from_encoding, $to_encoding . '//TRANSLIT,IGNORE', $source);
+
+ case 'libiconv':
+ default:
+ return iconv($from_encoding, $to_encoding . '//IGNORE//TRANSLIT', $source);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Tests a string as to whether it's valid UTF-8 and supported by the Unicode standard.
+ *
+ * Note: this function has been modified to simple return true or false.
+ *
+ * @param string $str UTF-8 encoded string.
+ *
+ * @return boolean true if valid
+ *
+ * @author