Newer
Older
Angie Byron
committed
use Drupal\Component\Utility\Crypt;
catch
committed
use Drupal\Component\Utility\Json;
catch
committed
use Drupal\Component\Utility\Number;
Dries Buytaert
committed
use Drupal\Component\Utility\Settings;
use Drupal\Component\Utility\SortArray;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Tags;
use Drupal\Component\Utility\Url;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\Language;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
catch
committed
use Drupal\Component\PhpStorage\PhpStorageFactory;
use Drupal\Component\Utility\MapArray;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Routing\GeneratorNotInitializedException;
catch
committed
use Drupal\Core\SystemListingInfo;
Dries Buytaert
committed
use Drupal\Core\Template\Attribute;
Larry Garfield
committed
/**
* @file
* Common functions that many Drupal modules will need to reference.
*
* The functions that are critical and need to be available even when serving
* a cached page are instead located in bootstrap.inc.
*/
Dries Buytaert
committed
/**
* @defgroup php_wrappers PHP wrapper functions
* @{
* Functions that are wrappers or custom implementations of PHP functions.
*
* Certain PHP functions should not be used in Drupal. Instead, Drupal's
* replacement functions should be used.
*
* For example, for improved or more secure UTF8-handling, or RFC-compliant
* handling of URLs in Drupal.
*
* For ease of use and memorizing, all these wrapper functions use the same name
* as the original PHP function, but prefixed with "drupal_". Beware, however,
* that not all wrapper functions support the same arguments as the original
* functions.
*
* You should always use these wrapper functions in your code.
*
* Wrong:
* @code
* $my_substring = substr($original_string, 0, 5);
* @endcode
*
* Correct:
* @code
* $my_substring = drupal_substr($original_string, 0, 5);
* @endcode
*
* @}
Dries Buytaert
committed
*/
Steven Wittens
committed
/**
* Return status for saving which involved creating a new item.
*/
const SAVED_NEW = 1;
Steven Wittens
committed
/**
* Return status for saving which involved an update to an existing item.
*/
const SAVED_UPDATED = 2;
Steven Wittens
committed
/**
* Return status for saving which deleted an existing item.
*/
const SAVED_DELETED = 3;
Steven Wittens
committed
Dries Buytaert
committed
/**
Angie Byron
committed
* The default aggregation group for CSS files added to the page.
Dries Buytaert
committed
*/
Angie Byron
committed
const CSS_AGGREGATE_DEFAULT = 0;
Dries Buytaert
committed
/**
Angie Byron
committed
* The default aggregation group for theme CSS files added to the page.
Dries Buytaert
committed
*/
Angie Byron
committed
const CSS_AGGREGATE_THEME = 100;
/**
* The default weight for CSS rules that style HTML elements ("base" styles).
*/
const CSS_BASE = -200;
/**
* The default weight for CSS rules that layout a page.
*/
const CSS_LAYOUT = -100;
/**
* The default weight for CSS rules that style design components (and their associated states and skins.)
*/
const CSS_COMPONENT = 0;
/**
* The default weight for CSS rules that style states and are not included with components.
*/
const CSS_STATE = 100;
/**
* The default weight for CSS rules that style skins and are not included with components.
*/
const CSS_SKIN = 200;
Dries Buytaert
committed
/**
* The default group for JavaScript settings added to the page.
*/
const JS_SETTING = -200;
Angie Byron
committed
/**
catch
committed
* The default group for JavaScript and jQuery libraries added to the page.
Angie Byron
committed
*/
const JS_LIBRARY = -100;
Angie Byron
committed
/**
Dries Buytaert
committed
* The default group for module JavaScript code added to the page.
Angie Byron
committed
*/
const JS_DEFAULT = 0;
Angie Byron
committed
/**
Dries Buytaert
committed
* The default group for theme JavaScript code added to the page.
Angie Byron
committed
*/
const JS_THEME = 100;
Angie Byron
committed
/**
Jennifer Hodgdon
committed
* @defgroup block_caching Block Caching
* @{
* Constants that define each block's caching state.
*
* Modules specify how their blocks can be cached in their hook_block_info()
* implementations. Caching can be turned off (DRUPAL_NO_CACHE), managed by the
* module declaring the block (DRUPAL_CACHE_CUSTOM), or managed by the core
* Block module. If the Block module is managing the cache, you can specify that
* the block is the same for every page and user (DRUPAL_CACHE_GLOBAL), or that
* it can change depending on the page (DRUPAL_CACHE_PER_PAGE) or by user
* (DRUPAL_CACHE_PER_ROLE or DRUPAL_CACHE_PER_USER). Page and user settings can
* be combined with a bitwise-binary or operator; for example,
* DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE means that the block can change
* depending on the user role or page it is on.
*
* The block cache is cleared when the 'content' cache tag is invalidated,
* following the same pattern as the page cache (node, comment, user, taxonomy
* added or updated...).
*
* Note that user 1 is excluded from block caching.
*/
/**
catch
committed
* The block should not get cached.
*
* This setting should be used:
* - For simple blocks (notably those that do not perform any db query), where
* querying the db cache would be more expensive than directly generating the
* content.
* - For blocks that change too frequently.
*/
const DRUPAL_NO_CACHE = -1;
/**
catch
committed
* The block is handling its own caching in its hook_block_view().
*
* This setting is useful when time based expiration is needed or a site uses a
* node access which invalidates standard block cache.
*/
const DRUPAL_CACHE_CUSTOM = -2;
/**
catch
committed
* The block or element can change depending on the user's roles.
*
* This is the default setting for blocks, used when the block does not specify
* anything.
*/
const DRUPAL_CACHE_PER_ROLE = 0x0001;
/**
catch
committed
* The block or element can change depending on the user.
*
* This setting can be resource-consuming for sites with large number of users,
* and thus should only be used when DRUPAL_CACHE_PER_ROLE is not sufficient.
*/
const DRUPAL_CACHE_PER_USER = 0x0002;
/**
* The block or element can change depending on the page being viewed.
*/
const DRUPAL_CACHE_PER_PAGE = 0x0004;
/**
catch
committed
* The block or element is the same for every user and page that it is visible.
*/
const DRUPAL_CACHE_GLOBAL = 0x0008;
Jennifer Hodgdon
committed
/**
* @} End of "defgroup block_caching".
*/
Dries Buytaert
committed
/**
* The delimiter used to split plural strings.
*
* This is the ETX (End of text) character and is used as a minimal means to
* separate singular and plural variants in source and translation text. It
* was found to be the most compatible delimiter for the supported databases.
*/
const LOCALE_PLURAL_DELIMITER = "\03";
catch
committed
* Adds content to a specified region.
*
* @param $region
Dries Buytaert
committed
* Page region the content is added to.
Dries Buytaert
committed
* Content to be added.
Dries Buytaert
committed
function drupal_add_region_content($region = NULL, $data = NULL) {
static $content = array();
Dries Buytaert
committed
if (isset($region) && isset($data)) {
$content[$region][] = $data;
}
return $content;
}
/**
catch
committed
* Gets assigned content for a given region.
*
* @param $region
* A specified region to fetch content for. If NULL, all regions will be
* returned.
Dries Buytaert
committed
* Content to be inserted between imploded array elements.
Dries Buytaert
committed
function drupal_get_region_content($region = NULL, $delimiter = ' ') {
$content = drupal_add_region_content();
if (isset($region)) {
if (isset($content[$region]) && is_array($content[$region])) {
}
else {
foreach (array_keys($content) as $region) {
if (is_array($content[$region])) {
$content[$region] = implode($delimiter, $content[$region]);
}
}
return $content;
}
}
Angie Byron
committed
/**
Jennifer Hodgdon
committed
* Gets the name of the currently active installation profile.
Angie Byron
committed
*
* When this function is called during Drupal's initial installation process,
* the name of the profile that's about to be installed is stored in the global
Jennifer Hodgdon
committed
* installation state. At all other times, the "install_profile" setting will be
* available in settings.php.
Angie Byron
committed
*
* @return $profile
Jennifer Hodgdon
committed
* The name of the installation profile.
Angie Byron
committed
*/
function drupal_get_profile() {
global $install_state;
Dries Buytaert
committed
if (drupal_installation_attempted()) {
// If the profile has been selected return it.
if (isset($install_state['parameters']['profile'])) {
$profile = $install_state['parameters']['profile'];
}
else {
$profile = '';
}
Angie Byron
committed
}
else {
Dries Buytaert
committed
$profile = settings()->get('install_profile') ?: 'standard';
Angie Byron
committed
}
return $profile;
}
catch
committed
* Sets the breadcrumb trail for the current page.
* @param $breadcrumb
* Array of links, starting with "home" and proceeding up to but not including
* the current page.
*
* @deprecated This will be removed in 8.0. Instead, register a new breadcrumb
* builder service.
*
Alex Pott
committed
* @see \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface
Dries Buytaert
committed
$stored_breadcrumb = &drupal_static(__FUNCTION__);
Dries Buytaert
committed
if (isset($breadcrumb)) {
$stored_breadcrumb = $breadcrumb;
}
return $stored_breadcrumb;
}
catch
committed
* Adds output to the HEAD tag of the HTML page.
* This function can be called as long as the headers aren't sent. Pass no
* arguments (or NULL for both) to retrieve the currently stored elements.
*
* @param $data
* A renderable array. If the '#type' key is not set then 'html_tag' will be
* added as the default '#type'.
* @param $key
* A unique string key to allow implementations of hook_html_head_alter() to
* identify the element in $data. Required if $data is not NULL.
*
* @return
* An array of all stored HEAD elements.
*
catch
committed
* @see drupal_pre_render_html_tag()
function drupal_add_html_head($data = NULL, $key = NULL) {
$stored_head = &drupal_static(__FUNCTION__);
if (!isset($stored_head)) {
// Make sure the defaults, including Content-Type, come first.
$stored_head = _drupal_default_html_head();
}
if (isset($data) && isset($key)) {
if (!isset($data['#type'])) {
$data['#type'] = 'html_tag';
}
$stored_head[$key] = $data;
* Returns elements that are always displayed in the HEAD tag of the HTML page.
*/
function _drupal_default_html_head() {
// Add default elements. Make sure the Content-Type comes first because the
// IE browser may be vulnerable to XSS via encoding attacks from any content
// that comes before this META tag, such as a TITLE tag.
$elements['system_meta_content_type'] = array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#attributes' => array(
catch
committed
'charset' => 'utf-8',
),
// Security: This always has to be output first.
'#weight' => -1000,
);
// Show Drupal and the major version number in the META GENERATOR tag.
// Get the major version.
list($version, ) = explode('.', \Drupal::VERSION);
$elements['system_meta_generator'] = array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#attributes' => array(
'name' => 'Generator',
'content' => 'Drupal ' . $version . ' (http://drupal.org)',
),
);
// Also send the generator in the HTTP header.
$elements['system_meta_generator']['#attached']['drupal_add_http_header'][] = array('X-Generator', $elements['system_meta_generator']['#attributes']['content']);
return $elements;
}
/**
catch
committed
* Retrieves output to be displayed in the HEAD tag of the HTML page.
$elements = drupal_add_html_head();
drupal_alter('html_head', $elements);
return drupal_render($elements);
catch
committed
* Adds a feed URL for the current page.
* This function can be called as long the HTML header hasn't been sent.
*
* An internal system path or a fully qualified external URL of the feed.
* @param $title
* The title of the feed.
function drupal_add_feed($url = NULL, $title = '') {
Dries Buytaert
committed
$stored_feed_links = &drupal_static(__FUNCTION__, array());
if (isset($url)) {
Dries Buytaert
committed
$stored_feed_links[$url] = theme('feed_icon', array('url' => $url, 'title' => $title));
catch
committed
$build['#attached']['drupal_add_html_head_link'][][] = array(
'rel' => 'alternate',
'type' => 'application/rss+xml',
'title' => $title,
// Force the URL to be absolute, for consistency with other <link> tags
// output by Drupal.
'href' => url($url, array('absolute' => TRUE)),
catch
committed
);
drupal_render($build);
}
return $stored_feed_links;
}
/**
catch
committed
* Gets the feed URLs for the current page.
*
* @param $delimiter
* A delimiter to split feeds by.
*/
function drupal_get_feeds($delimiter = "\n") {
$feeds = drupal_add_feed();
return implode($feeds, $delimiter);
}
* @defgroup http_handling HTTP handling
Gerhard Killesreiter
committed
/**
catch
committed
* Processes a URL query parameter array to remove unwanted elements.
Gerhard Killesreiter
committed
*
* @param $query
Dries Buytaert
committed
* (optional) An array to be processed. Defaults to $_GET.
Gerhard Killesreiter
committed
* @param $exclude
Dries Buytaert
committed
* (optional) A list of $query array keys to remove. Use "parent[child]" to
Dries Buytaert
committed
* exclude nested items.
Gerhard Killesreiter
committed
* @param $parent
Dries Buytaert
committed
* Internal use only. Used to build the $query array key for nested items.
*
Gerhard Killesreiter
committed
* @return
Dries Buytaert
committed
* An array containing query parameters, which can be used for url().
*
* @deprecated as of Drupal 8.0. Use Url::filterQueryParameters() instead.
Gerhard Killesreiter
committed
*/
Dries Buytaert
committed
function drupal_get_query_parameters(array $query = NULL, array $exclude = array(), $parent = '') {
Dries Buytaert
committed
if (!isset($query)) {
$query = \Drupal::request()->query->all();
Angie Byron
committed
}
return Url::filterQueryParameters($query, $exclude, $parent);
Angie Byron
committed
}
Dries Buytaert
committed
/**
catch
committed
* Parses an array into a valid, rawurlencoded query string.
Dries Buytaert
committed
*
* @see drupal_get_query_parameters()
* @deprecated as of Drupal 8.0. Use Url::buildQuery() instead.
Dries Buytaert
committed
* @ingroup php_wrappers
*
* @deprecated as of Drupal 8.0. Use Url::buildQuery() instead.
Dries Buytaert
committed
*/
function drupal_http_build_query(array $query, $parent = '') {
return Url::buildQuery($query, $parent);
Gerhard Killesreiter
committed
}
/**
* Prepares a 'destination' URL query parameter for use with url().
* Used to direct the user back to the referring page after completing a form.
* By default the current URL is returned. If a destination exists in the
* previous request, that destination is returned. As such, a destination can
* persist across multiple pages.
*
Jennifer Hodgdon
committed
* @return
* An associative array containing the key:
* - destination: The path provided via the destination query string or, if
* not available, the current path.
*
* @see current_path()
*/
function drupal_get_destination() {
Dries Buytaert
committed
$destination = &drupal_static(__FUNCTION__);
if (isset($destination)) {
return $destination;
}
$query = \Drupal::request()->query;
if ($query->has('destination')) {
$destination = array('destination' => $query->get('destination'));
Dries Buytaert
committed
}
else {
Dries Buytaert
committed
$path = current_path();
$query = Url::buildQuery(Url::filterQueryParameters($query->all()));
Gerhard Killesreiter
committed
if ($query != '') {
$path .= '?' . $query;
Gerhard Killesreiter
committed
}
Dries Buytaert
committed
$destination = array('destination' => $path);
}
return $destination;
}
/**
catch
committed
* Parses a system URL string into an associative array suitable for url().
Angie Byron
committed
*
* This function should only be used for URLs that have been generated by the
* system, such as via url(). It should not be used for URLs that come from
* external sources, or URLs that link to external resources.
Dries Buytaert
committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
*
* The returned array contains a 'path' that may be passed separately to url().
* For example:
* @code
* $options = drupal_parse_url($_GET['destination']);
* $my_url = url($options['path'], $options);
* $my_link = l('Example link', $options['path'], $options);
* @endcode
*
* This is required, because url() does not support relative URLs containing a
* query string or fragment in its $path argument. Instead, any query string
* needs to be parsed into an associative query parameter array in
* $options['query'] and the fragment into $options['fragment'].
*
* @param $url
* The URL string to parse, f.e. $_GET['destination'].
*
* @return
* An associative array containing the keys:
* - 'path': The path of the URL. If the given $url is external, this includes
* the scheme and host.
* - 'query': An array of query parameters of $url, if existent.
* - 'fragment': The fragment of $url, if existent.
*
* @see url()
* @ingroup php_wrappers
*
* @deprecated as of Drupal 8.0. Use Url::parse() instead.
Dries Buytaert
committed
*/
function drupal_parse_url($url) {
return Url::parse($url);
Dries Buytaert
committed
}
/**
Dries Buytaert
committed
* Encodes a Drupal path for use in a URL.
Dries Buytaert
committed
*
Dries Buytaert
committed
* For aesthetic reasons slashes are not escaped.
Dries Buytaert
committed
*
Dries Buytaert
committed
* Note that url() takes care of calling this function, so a path passed to that
* function should not be encoded in advance.
Dries Buytaert
committed
*
* @param $path
Dries Buytaert
committed
* The Drupal path to encode.
*
* @deprecated as of Drupal 8.0. Use Url::encodePath() instead.
Dries Buytaert
committed
*/
function drupal_encode_path($path) {
return Url::encodePath($path);
}
/**
* Determines if an external URL points to this Drupal installation.
*
* @param $url
* A string containing an external URL, such as "http://example.com/foo".
*
* @return
* TRUE if the URL has the same domain and base path.
*
* @deprecated as of Drupal 8.0. Use Url::externalIsLocal() instead.
*/
function _external_url_is_local($url) {
return Url::externalIsLocal($url, base_path());
}
Dries Buytaert
committed
/**
* Helper function for determining hosts excluded from needing a proxy.
*
* @return
* TRUE if a proxy should be used for this host.
*/
function _drupal_http_use_proxy($host) {
$proxy_exceptions = settings()->get('proxy_exceptions', array('localhost', '127.0.0.1'));
Dries Buytaert
committed
return !in_array(strtolower($host), $proxy_exceptions, TRUE);
}
* @} End of "defgroup http_handling".
Dries Buytaert
committed
/**
catch
committed
* Verifies the syntax of the given e-mail address.
Dries Buytaert
committed
* This uses the
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
Dries Buytaert
committed
*
* A string containing an e-mail address.
catch
committed
*
Dries Buytaert
committed
*/
return (bool)filter_var($mail, FILTER_VALIDATE_EMAIL);
Dries Buytaert
committed
}
catch
committed
* Verifies the syntax of the given URL.
* This function should only be used on actual URLs. It should not be used for
* Drupal menu paths, which can contain arbitrary characters.
Dries Buytaert
committed
* Valid values per RFC 3986.
* Whether the URL is absolute (beginning with a scheme such as "http:").
catch
committed
*
*
* @see \Drupal\Component\Utility\Url::isValid()
*
* @deprecated as of Drupal 8.0. Use Url::isValid() instead.
return Url::isValid($url, $absolute);
/**
* Verifies that a number is a multiple of a given step.
*
catch
committed
* @see \Drupal\Component\Utility\Number::validStep()
catch
committed
* @param numeric $value
* The value that needs to be checked.
catch
committed
* @param numeric $step
* The step scale factor. Must be positive.
catch
committed
* @param numeric $offset
* (optional) An offset, to which the difference must be a multiple of the
* given step.
*
* @return bool
* TRUE if no step mismatch has occured, or FALSE otherwise.
*
catch
committed
* @deprecated as of Drupal 8.0. Use
* \Drupal\Component\Utility\Number::validStep() directly instead
*/
function valid_number_step($value, $step, $offset = 0.0) {
catch
committed
return Number::validStep($value, $step, $offset);
/**
* @} End of "defgroup validation".
*/
/**
* @defgroup sanitization Sanitization functions
* @{
* Functions to sanitize values.
Dries Buytaert
committed
*
* See http://drupal.org/writing-secure-code for information
* on writing secure code.
* Strips dangerous protocols (e.g. 'javascript:') from a URI.
*
* This function must be called for all URIs within user-entered input prior
* to being output to an HTML attribute value. It is often called as part of
* check_url() or filter_xss(), but those functions return an HTML-encoded
* string, so this function can be called independently when the output needs to
* be a plain-text string for passing to t(), l(),
* Drupal\Core\Template\Attribute, or another function that will call
Angie Byron
committed
* \Drupal\Component\Utility\String::checkPlain() separately.
*
* @param $uri
* A plain-text URI that might contain dangerous protocols.
*
* @return
* A plain-text URI stripped of dangerous protocols. As with all plain-text
* strings, this return value must not be output to an HTML page without
Angie Byron
committed
* \Drupal\Component\Utility\String::checkPlain() being called on it. However,
* it can be passed to functions expecting plain-text strings.
*
* @see \Drupal\Component\Utility\Url::stripDangerousProtocols()
*/
function drupal_strip_dangerous_protocols($uri) {
return Url::stripDangerousProtocols($uri);
}
/**
catch
committed
* Strips dangerous protocols from a URI and encodes it for output to HTML.
*
* @param $uri
* A plain-text URI that might contain dangerous protocols.
*
* @return
* A URI stripped of dangerous protocols and encoded for output to an HTML
* attribute value. Because it is already encoded, it should not be set as a
* value within a $attributes array passed to Drupal\Core\Template\Attribute,
* because Drupal\Core\Template\Attribute expects those values to be
* plain-text strings. To pass a filtered URI to
Angie Byron
committed
* Drupal\Core\Template\Attribute, call
* \Drupal\Component\Utility\Url::stripDangerousProtocols() instead.
*
* @see \Drupal\Component\Utility\Url::stripDangerousProtocols()
* @see \Drupal\Component\Utility\String::checkPlain()
return String::checkPlain(Url::stripDangerousProtocols($uri));
catch
committed
* Applies a very permissive XSS/HTML filter for admin-only use.
*
* Use only for fields where it is impractical to use the
* whole filter system, but where some (mainly inline) mark-up
Angie Byron
committed
* is desired (so \Drupal\Component\Utility\String::checkPlain() is not
* acceptable).
*
* Allows all tags that can be used inside an HTML body, save
* for scripts and styles.
*
* @param string $string
* The string to apply the filter to.
*
* @return string
* The filtered string.
*
* @see \Drupal\Component\Utility\Xss::filterAdmin()
*/
function filter_xss_admin($string) {
return Xss::filterAdmin($string);
}
/**
catch
committed
* Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.
Dries Buytaert
committed
* Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
* For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
*
* This code does four things:
Dries Buytaert
committed
* - Removes characters and constructs that can trick browsers.
* - Makes sure all HTML entities are well-formed.
* - Makes sure all HTML tags and attributes are well-formed.
* - Makes sure no HTML tags contain URLs with a disallowed protocol (e.g.
* javascript:).
*
* @param $string
Dries Buytaert
committed
* The string with raw HTML in it. It will be stripped of everything that can
* cause an XSS attack.
* @param $allowed_tags
* An array of allowed tags.
Dries Buytaert
committed
*
* @return
* An XSS safe version of $string, or an empty string if $string is not
* valid UTF-8.
*
* @see \Drupal\Component\Utility\Xss::filter()
*
Dries Buytaert
committed
* @ingroup sanitization
*/
function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
return Xss::filter($string, $allowed_tags);
}
/**
catch
committed
* Processes an HTML attribute value and strips dangerous protocols from URLs.
* @param string $string
* The string with the attribute value.
catch
committed
*
* @return string
* Cleaned up and HTML-escaped version of $string.
*
* @see \Drupal\Component\Utility\Url::filterBadProtocol()
function filter_xss_bad_protocol($string) {
return Url::filterBadProtocol($string);
}
/**
* @} End of "defgroup sanitization".
*/
/**
* Formats an RSS channel.
*
* Arbitrary elements may be added using the $args associative array.
*/
Gábor Hojtsy
committed
function format_rss_channel($title, $link, $description, $items, $langcode = NULL, $args = array()) {
$langcode = $langcode ? $langcode : language(Language::TYPE_CONTENT)->id;
Angie Byron
committed
$output .= ' <title>' . String::checkPlain($title) . "</title>\n";
$output .= ' <link>' . check_url($link) . "</link>\n";
// The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
// We strip all HTML tags, but need to prevent double encoding from properly
// escaped source data (such as & becoming &amp;).
Angie Byron
committed
$output .= ' <description>' . String::checkPlain(decode_entities(strip_tags($description))) . "</description>\n";
$output .= ' <language>' . String::checkPlain($langcode) . "</language>\n";
$output .= format_xml_elements($args);
$output .= $items;
$output .= "</channel>\n";
return $output;
}
catch
committed
* Formats a single RSS item.
*
* Arbitrary elements may be added using the $args associative array.
*/
function format_rss_item($title, $link, $description, $args = array()) {
Angie Byron
committed
$output .= ' <title>' . String::checkPlain($title) . "</title>\n";
$output .= ' <link>' . check_url($link) . "</link>\n";
Angie Byron
committed
$output .= ' <description>' . String::checkPlain($description) . "</description>\n";
$output .= format_xml_elements($args);
$output .= "</item>\n";
return $output;
}
/**
catch
committed
* Formats XML elements.
*
* @param $array
* An array where each item represents an element and is either a:
* - (key => value) pair (<key>value</key>)
* - Associative array with fields:
* - 'key': element name
* - 'value': element contents
* - 'attributes': associative array of element attributes
*
* In both cases, 'value' can be a simple string, or it can be another array
* with the same format as $array itself for nesting.
*/
function format_xml_elements($array) {
Steven Wittens
committed
$output = '';
foreach ($array as $key => $value) {
if (is_numeric($key)) {
$output .= ' <' . $value['key'];
Dries Buytaert
committed
if (isset($value['attributes']) && is_array($value['attributes'])) {
$output .= new Attribute($value['attributes']);
if (isset($value['value']) && $value['value'] != '') {
Angie Byron
committed
$output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : String::checkPlain($value['value'])) . '</' . $value['key'] . ">\n";
Angie Byron
committed
$output .= ' <' . $key . '>' . (is_array($value) ? format_xml_elements($value) : String::checkPlain($value)) . "</$key>\n";
catch
committed
* Formats a string containing a count of items.
* This function ensures that the string is pluralized correctly. Since t() is
* called by this function, make sure not to pass already-localized strings to
* it.
* For example:
* @code
* $output = format_plural($node->comment_count, '1 comment', '@count comments');
* @endcode
*
* Example with additional replacements:
* @code
* $output = format_plural($update_count,
* 'Changed the content type of 1 post from %old-type to %new-type.',
* 'Changed the content type of @count posts from %old-type to %new-type.',
* array('%old-type' => $info->old_type, '%new-type' => $info->new_type));
* @endcode
*
* @param $count
* The item count to display.
* @param $singular
catch
committed
* The string for the singular case. Make sure it is clear this is singular,
* to ease translation (e.g. use "1 new comment" instead of "1 new"). Do not
* use @count in the singular string.
catch
committed
* The string for the plural case. Make sure it is clear this is plural, to
* ease translation. Use @count in place of the item count, as in
* "@count new comments".
* @param $args
catch
committed
* An associative array of replacements to make after translation. Instances
* of any key in this array are replaced with the corresponding value.
catch
committed
* Based on the first character of the key, the value is escaped and/or
* themed. See format_string(). Note that you do not need to include @count
* in this array; this replacement is done automatically for the plural case.
Dries Buytaert
committed
* @param $options
catch
committed
* An associative array of additional options. See t() for allowed keys.
*
catch
committed
*
* @see t()
* @see format_string()
Dries Buytaert
committed
function format_plural($count, $singular, $plural, array $args = array(), array $options = array()) {
Gábor Hojtsy
committed
$args['@count'] = $count;
Dries Buytaert
committed
// Join both forms to search a translation.
$tranlatable_string = implode(LOCALE_PLURAL_DELIMITER, array($singular, $plural));
// Translate as usual.
$translated_strings = t($tranlatable_string, $args, $options);
// Split joined translation strings into array.
$translated_array = explode(LOCALE_PLURAL_DELIMITER, $translated_strings);
if ($count == 1) {
Dries Buytaert
committed
return $translated_array[0];
// Get the plural index through the gettext formula.
Dries Buytaert
committed
// @todo implement static variable to minimize function_exists() usage.
Dries Buytaert
committed
$index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
Dries Buytaert
committed
if ($index == 0) {
// Singular form.
return $translated_array[0];
Dries Buytaert
committed
if (isset($translated_array[$index])) {
// N-th plural form.
return $translated_array[$index];
}
else {
// If the index cannot be computed or there's no translation, use
// the second plural form as a fallback (which allows for most flexiblity
// with the replaceable @count value).
return $translated_array[1];
Dries Buytaert
committed
/**
catch
committed
* Parses a given byte count.
Dries Buytaert
committed
*
* @param $size
Dries Buytaert
committed
* A size expressed as a number of bytes with optional SI or IEC binary unit
* prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8 bytes, 9mbytes).
catch
committed
*
Dries Buytaert
committed
* @return
Dries Buytaert
committed
* An integer representation of the size in bytes.
Dries Buytaert
committed
*/
function parse_size($size) {
Dries Buytaert
committed
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
$size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
if ($unit) {
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
return round($size * pow(DRUPAL_KILOBYTE, stripos('bkmgtpezy', $unit[0])));
}
else {
return round($size);
Dries Buytaert
committed
}
}
catch
committed
* Generates a string representation for the given byte count.
* A size in bytes.
Gábor Hojtsy
committed
* @param $langcode
* Optional language code to translate to a language other than what is used
* to display the page.
catch
committed
*
Gábor Hojtsy
committed
function format_size($size, $langcode = NULL) {
Dries Buytaert
committed
if ($size < DRUPAL_KILOBYTE) {
Dries Buytaert
committed
return format_plural($size, '1 byte', '@count bytes', array(), array('langcode' => $langcode));
Dries Buytaert
committed
$size = $size / DRUPAL_KILOBYTE; // Convert bytes to kilobytes.
Dries Buytaert
committed
$units = array(
Dries Buytaert
committed
t('@size KB', array(), array('langcode' => $langcode)),
t('@size MB', array(), array('langcode' => $langcode)),
t('@size GB', array(), array('langcode' => $langcode)),
t('@size TB', array(), array('langcode' => $langcode)),