alter('html_head', $elements);
if ($render) {
return drupal_render($elements);
}
else {
return $elements;
}
}
/**
* 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.
*
* @return
* An associative array containing the key:
* - destination: The path provided via the destination query string or, if
* not available, the current path.
*
* @ingroup form_api
*/
function drupal_get_destination() {
$destination = &drupal_static(__FUNCTION__);
if (isset($destination)) {
return $destination;
}
$query = \Drupal::request()->query;
if ($query->has('destination')) {
$destination = array('destination' => $query->get('destination'));
}
else {
$path = \Drupal::routeMatch()->getRouteName() ? Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath() : '';
$query = UrlHelper::buildQuery(UrlHelper::filterQueryParameters($query->all()));
if ($query != '') {
$path .= '?' . $query;
}
$destination = array('destination' => $path);
}
return $destination;
}
/**
* @defgroup validation Input validation
* @{
* Functions to validate user input.
*/
/**
* Verifies the syntax of the given email address.
*
* This uses the
* @link http://php.net/manual/filter.filters.validate.php PHP email validation filter. @endlink
*
* @param $mail
* A string containing an email address.
*
* @return
* TRUE if the address is in a valid format.
*/
function valid_email_address($mail) {
return (bool)filter_var($mail, FILTER_VALIDATE_EMAIL);
}
/**
* @} End of "defgroup validation".
*/
/**
* @defgroup sanitization Sanitization functions
* @{
* Functions to sanitize values.
*
* See http://drupal.org/writing-secure-code for information
* on writing secure code.
*/
/**
* 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
* Drupal\Core\Template\Attribute, call
* \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() instead.
*
* @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
* @see \Drupal\Component\Utility\String::checkPlain()
*/
function check_url($uri) {
return String::checkPlain(UrlHelper::stripDangerousProtocols($uri));
}
/**
* @} End of "defgroup sanitization".
*/
/**
* @defgroup format Formatting
* @{
* Functions to format numbers, strings, dates, etc.
*/
/**
* Formats XML elements.
*
* Note: It is the caller's responsibility to sanitize any input parameters.
* This function does not perform sanitization.
*
* @param $array
* An array where each item represents an element and is either a:
* - (key => value) pair (value)
* - Associative array with fields:
* - 'key': The element name. Element names are not sanitized, so do not
* pass user input.
* - '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) {
$output = '';
foreach ($array as $key => $value) {
if (is_numeric($key)) {
if ($value['key']) {
$output .= ' <' . $value['key'];
if (isset($value['attributes']) && is_array($value['attributes'])) {
$output .= new Attribute($value['attributes']);
}
if (isset($value['value']) && $value['value'] != '') {
$output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : String::checkPlain($value['value'])) . '' . $value['key'] . ">\n";
}
else {
$output .= " />\n";
}
}
}
else {
$output .= ' <' . $key . '>' . (is_array($value) ? format_xml_elements($value) : String::checkPlain($value)) . "$key>\n";
}
}
// @todo This is marking the output string as safe HTML, but we have only
// sanitized the attributes and tag values, not the tag names, and we
// cannot guarantee the assembled markup is safe. Consider a fix in:
// https://www.drupal.org/node/2296885
return SafeMarkup::set($output);
}
/**
* Generates a string representation for the given byte count.
*
* @param $size
* A size in bytes.
* @param $langcode
* Optional language code to translate to a language other than what is used
* to display the page.
*
* @return
* A translated string representation of the size.
*/
function format_size($size, $langcode = NULL) {
if ($size < Bytes::KILOBYTE) {
return \Drupal::translation()->formatPlural($size, '1 byte', '@count bytes', array(), array('langcode' => $langcode));
}
else {
$size = $size / Bytes::KILOBYTE; // Convert bytes to kilobytes.
$units = array(
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)),
t('@size PB', array(), array('langcode' => $langcode)),
t('@size EB', array(), array('langcode' => $langcode)),
t('@size ZB', array(), array('langcode' => $langcode)),
t('@size YB', array(), array('langcode' => $langcode)),
);
foreach ($units as $unit) {
if (round($size, 2) >= Bytes::KILOBYTE) {
$size = $size / Bytes::KILOBYTE;
}
else {
break;
}
}
return str_replace('@size', round($size, 2), $unit);
}
}
/**
* Formats a date, using a date type or a custom date format string.
*
* @param $timestamp
* A UNIX timestamp to format.
* @param $type
* (optional) The format to use, one of:
* - One of the built-in formats: 'short', 'medium',
* 'long', 'html_datetime', 'html_date', 'html_time',
* 'html_yearless_date', 'html_week', 'html_month', 'html_year'.
* - The name of a date type defined by a date format config entity.
* - The machine name of an administrator-defined date format.
* - 'custom', to use $format.
* Defaults to 'medium'.
* @param $format
* (optional) If $type is 'custom', a PHP date format string suitable for
* input to date(). Use a backslash to escape ordinary text, so it does not
* get interpreted as date format characters.
* @param $timezone
* (optional) Time zone identifier, as described at
* http://php.net/manual/timezones.php Defaults to the time zone used to
* display the page.
* @param $langcode
* (optional) Language code to translate to. Defaults to the language used to
* display the page.
*
* @return
* A translated date string in the requested format.
*
* @see \Drupal\Core\Datetime\DateFormatter::format()
*/
function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
return \Drupal::service('date.formatter')->format($timestamp, $type, $format, $timezone, $langcode);
}
/**
* Returns an ISO8601 formatted date based on the given date.
*
* @param $date
* A UNIX timestamp.
*
* @return string
* An ISO8601 formatted date.
*/
function date_iso8601($date) {
// The DATE_ISO8601 constant cannot be used here because it does not match
// date('c') and produces invalid RDF markup.
return date('c', $date);
}
/**
* Translates a formatted date string.
*
* Callback for preg_replace_callback() within format_date().
*/
function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
// We cache translations to avoid redundant and rather costly calls to t().
static $cache, $langcode;
if (!isset($matches)) {
$langcode = $new_langcode;
return;
}
$code = $matches[1];
$string = $matches[2];
if (!isset($cache[$langcode][$code][$string])) {
$options = array(
'langcode' => $langcode,
);
if ($code == 'F') {
$options['context'] = 'Long month name';
}
if ($code == '') {
$cache[$langcode][$code][$string] = $string;
}
else {
$cache[$langcode][$code][$string] = t($string, array(), $options);
}
}
return $cache[$langcode][$code][$string];
}
/**
* @} End of "defgroup format".
*/
/**
* Generates an internal or external URL.
*
* When creating links in modules, consider whether l() could be a better
* alternative than url().
*
* @see \Drupal\Core\Url::fromUri()
* @see \Drupal\Core\Url::fromRoute()
* @see \Drupal\Core\Url::toString()
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal\Core\Url::fromRoute() for internal paths served by Drupal
* controllers or \Drupal\Core\Url::fromUri() for external paths or
* non-controller or sub-domain URIs such as core/install.php. Note that
* \Drupal\Core\Url::fromUri() expects a valid URI including the scheme. URIs
* from the same sub-domain that are not handled by Drupal controllers should
* be prepended with base://. For example:
* @code
* $installer_url = \Drupal\Core\Url::fromUri('base://core/install.php')->toString();
* $external_url = \Drupal\Core\Url::fromUri('http://example.com', ['query' => ['foo' => 'bar']])->toString();
* $internal_url = \Drupal\Core\Url::fromRoute('system.admin')->toString();
* @endcode
*/
function _url($path = NULL, array $options = array()) {
return \Drupal::urlGenerator()->generateFromPath($path, $options);
}
/**
* Formats an attribute string for an HTTP header.
*
* @param $attributes
* An associative array of attributes such as 'rel'.
*
* @return
* A ; separated string ready for insertion in a HTTP header. No escaping is
* performed for HTML entities, so this string is not safe to be printed.
*/
function drupal_http_header_attributes(array $attributes = array()) {
foreach ($attributes as $attribute => &$data) {
if (is_array($data)) {
$data = implode(' ', $data);
}
$data = $attribute . '="' . $data . '"';
}
return $attributes ? ' ' . implode('; ', $attributes) : '';
}
/**
* Formats an internal or external URL link as an HTML anchor tag.
*
* This function correctly handles aliased paths and adds an 'active' class
* attribute to links that point to the current page (for theming), so all
* internal links output by modules should be generated by this function if
* possible.
*
* However, for links enclosed in translatable text you should use t() and
* embed the HTML anchor tag directly in the translated string. For example:
* @code
* t('Visit the settings page', array('@url' => \Drupal::url('system.admin')));
* @endcode
* This keeps the context of the link title ('settings' in the example) for
* translators.
*
* This function does not support generating links from internal routes. For
* that use \Drupal\Core\Utility\LinkGenerator::generate(), which is exposed via
* the 'link_generator' service. It requires an internal route name and does not
* support external URLs. Using Drupal 7 style system paths should be avoided if
* possible but l() should still be used when rendering links to external URLs.
*
* @param string|array $text
* The link text for the anchor tag as a translated string or render array.
* @param string $path
* The internal path or external URL being linked to, such as "node/34" or
* "http://example.com/foo". After the url() function is called to construct
* the URL from $path and $options, the resulting URL is passed through
* \Drupal\Component\Utility\String::checkPlain() before it is inserted into
* the HTML anchor tag, to ensure well-formed HTML. See url() for more
* information and notes.
* @param array $options
* An associative array of additional options. Defaults to an empty array. It
* may contain the following elements.
* - 'attributes': An associative array of HTML attributes to apply to the
* anchor tag. If element 'class' is included, it must be an array; 'title'
* must be a string; other elements are more flexible, as they just need
* to work as an argument for the constructor of the class
* Drupal\Core\Template\Attribute($options['attributes']).
* - 'html' (default FALSE): Whether $text is HTML or just plain-text. For
* example, to make an image tag into a link, this must be set to TRUE, or
* you will see the escaped HTML image tag. $text is not sanitized if
* 'html' is TRUE. The calling function must ensure that $text is already
* safe.
* - 'language': An optional language object. If the path being linked to is
* internal to the site, $options['language'] is used to determine whether
* the link is "active", or pointing to the current page (the language as
* well as the path must match). This element is also used by url().
* - 'set_active_class': Whether l() should compare the $path, language and
* query options to the current URL to determine whether the link is
* "active". Defaults to FALSE. If TRUE, an "active" class will be applied
* to the link. It is important to use this sparingly since it is usually
* unnecessary and requires extra processing.
* For anonymous users, the "active" class will be calculated on the server,
* because most sites serve each anonymous user the same cached page anyway.
* For authenticated users, the "active" class will be calculated on the
* client (through JavaScript), only data- attributes are added to links to
* prevent breaking the render cache. The JavaScript is added in
* system_page_attachments().
* - Additional $options elements used by the url() function.
*
* @return string
* An HTML string containing a link to the given path.
*
* @see _url()
* @see system_page_attachments()
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal::l($text, $url) where $url is an instance of
* \Drupal\Core\Url. To build a \Drupal\Core\Url object for internal paths
* served by Drupal controllers use \Drupal\Core\Url::fromRoute(). For
* external paths or non-controller or sub-domain URIs such as
* core/install.php use \Drupal\Core\Url::fromUri(). Note that
* \Drupal\Core\Url::fromUri() expects a valid URI including the scheme. URIs
* from the same sub-domain that are not handled by Drupal controllers should
* be prepended with base://. For example:
* @code
* $installer_url = \Drupal\Core\Url::fromUri('base://core/install.php')->toString();
* $installer_link = \Drupal::l($text, $installer_url);
* $external_url = \Drupal\Core\Url::fromUri('http://example.com', ['query' => ['foo' => 'bar']])->toString();
* $external_link = \Drupal::l($text, $external_url);
* $internal_url = \Drupal\Core\Url::fromRoute('system.admin')->toString();
* $internal_link = \Drupal::l($text, $internal_url);
* @endcode
*/
function _l($text, $path, array $options = array()) {
// Start building a structured representation of our link to be altered later.
$variables = array(
'text' => is_array($text) ? drupal_render($text) : $text,
'path' => $path,
'options' => $options,
);
// Merge in default options.
$variables['options'] += array(
'attributes' => array(),
'query' => array(),
'html' => FALSE,
'language' => NULL,
'set_active_class' => FALSE,
);
// Add a hreflang attribute if we know the language of this link's url and
// hreflang has not already been set.
if (!empty($variables['options']['language']) && !isset($variables['options']['attributes']['hreflang'])) {
$variables['options']['attributes']['hreflang'] = $variables['options']['language']->getId();
}
// Set the "active" class if the 'set_active_class' option is not empty.
if (!empty($variables['options']['set_active_class'])) {
// Add a "data-drupal-link-query" attribute to let the drupal.active-link
// library know the query in a standardized manner.
if (!empty($variables['options']['query'])) {
$query = $variables['options']['query'];
ksort($query);
$variables['options']['attributes']['data-drupal-link-query'] = Json::encode($query);
}
// Add a "data-drupal-link-system-path" attribute to let the
// drupal.active-link library know the path in a standardized manner.
if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
$variables['options']['attributes']['data-drupal-link-system-path'] = \Drupal::service('path.alias_manager')->getPathByAlias($path);
}
}
// Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags()
// only when a quick strpos() gives suspicion tags are present.
if (isset($variables['options']['attributes']['title']) && strpos($variables['options']['attributes']['title'], '<') !== FALSE) {
$variables['options']['attributes']['title'] = strip_tags($variables['options']['attributes']['title']);
}
// Allow other modules to modify the structure of the link.
\Drupal::moduleHandler()->alter('link', $variables);
// Move attributes out of options. url() doesn't need them.
$attributes = new Attribute($variables['options']['attributes']);
unset($variables['options']['attributes']);
// The result of url() is a plain-text URL. Because we are using it here
// in an HTML argument context, we need to encode it properly.
$url = String::checkPlain(_url($variables['path'], $variables['options']));
// Sanitize the link text if necessary.
$text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
return SafeMarkup::set('' . $text . '');
}
/**
* Attempts to set the PHP maximum execution time.
*
* This function is a wrapper around the PHP function set_time_limit().
* When called, set_time_limit() restarts the timeout counter from zero.
* In other words, if the timeout is the default 30 seconds, and 25 seconds
* into script execution a call such as set_time_limit(20) is made, the
* script will run for a total of 45 seconds before timing out.
*
* If the current time limit is not unlimited it is possible to decrease the
* total time limit if the sum of the new time limit and the current time spent
* running the script is inferior to the original time limit. It is inherent to
* the way set_time_limit() works, it should rather be called with an
* appropriate value every time you need to allocate a certain amount of time
* to execute a task than only once at the beginning of the script.
*
* Before calling set_time_limit(), we check if this function is available
* because it could be disabled by the server administrator. We also hide all
* the errors that could occur when calling set_time_limit(), because it is
* not possible to reliably ensure that PHP or a security extension will
* not issue a warning/error if they prevent the use of this function.
*
* @param $time_limit
* An integer specifying the new time limit, in seconds. A value of 0
* indicates unlimited execution time.
*
* @ingroup php_wrappers
*/
function drupal_set_time_limit($time_limit) {
if (function_exists('set_time_limit')) {
$current = ini_get('max_execution_time');
// Do not set time limit if it is currently unlimited.
if ($current != 0) {
@set_time_limit($time_limit);
}
}
}
/**
* Returns the base URL path (i.e., directory) of the Drupal installation.
*
* base_path() adds a "/" to the beginning and end of the returned path if the
* path is not empty. At the very least, this will return "/".
*
* Examples:
* - http://example.com returns "/" because the path is empty.
* - http://example.com/drupal/folder returns "/drupal/folder/".
*/
function base_path() {
return $GLOBALS['base_path'];
}
/**
* Adds a LINK tag with a distinct 'rel' attribute to the page's HEAD.
*
* This function can be called as long the HTML header hasn't been sent, which
* on normal pages is up through the preprocess step of _theme('html'). Adding
* a link will overwrite a prior link with the exact same 'rel' and 'href'
* attributes.
*
* @param $attributes
* Associative array of element attributes including 'href' and 'rel'.
* @param $header
* Optional flag to determine if a HTTP 'Link:' header should be sent.
*
* @deprecated in Drupal 8.0.x, will be removed before Drupal 8.0.0
* Use #attached on render arrays.
*/
function _drupal_add_html_head_link($attributes, $header = FALSE) {
$element = array(
'#tag' => 'link',
'#attributes' => $attributes,
);
$href = $attributes['href'];
if ($header) {
// Also add a HTTP header "Link:".
$href = '<' . String::checkPlain($attributes['href']) . '>;';
unset($attributes['href']);
$element['#attached']['http_header'][] = array('Link', $href . drupal_http_header_attributes($attributes), TRUE);
}
_drupal_add_html_head($element, 'html_head_link:' . $attributes['rel'] . ':' . $href);
}
/**
* Deletes old cached CSS files.
*
* @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* Use \Drupal\Core\Asset\AssetCollectionOptimizerInterface::deleteAll().
*/
function drupal_clear_css_cache() {
\Drupal::service('asset.css.collection_optimizer')->deleteAll();
}
/**
* Prepares a string for use as a valid HTML ID and guarantees uniqueness.
*
* This function ensures that each passed HTML ID value only exists once on the
* page. By tracking the already returned ids, this function enables forms,
* blocks, and other content to be output multiple times on the same page,
* without breaking (X)HTML validation.
*
* For already existing IDs, a counter is appended to the ID string. Therefore,
* JavaScript and CSS code should not rely on any value that was generated by
* this function and instead should rely on manually added CSS classes or
* similarly reliable constructs.
*
* Two consecutive hyphens separate the counter from the original ID. To manage
* uniqueness across multiple Ajax requests on the same page, Ajax requests
* POST an array of all IDs currently present on the page, which are used to
* prime this function's cache upon first invocation.
*
* To allow reverse-parsing of IDs submitted via Ajax, any multiple consecutive
* hyphens in the originally passed $id are replaced with a single hyphen.
*
* @param $id
* The ID to clean.
*
* @return
* The cleaned ID.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal\Component\Utility\Html::getUniqueId()
*/
function drupal_html_id($id) {
return Html::getUniqueId($id);
}
/**
* Prepares a string for use as a valid HTML ID.
*
* Only use this function when you want to intentionally skip the uniqueness
* guarantee of drupal_html_id().
*
* @param string $id
* The ID to clean.
*
* @return string
* The cleaned ID.
*
* @see drupal_html_id()
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal\Component\Utility\Html::getId()
*/
function drupal_clean_id_identifier($id) {
return Html::getId($id);
}
/**
* Constructs an array of the defaults that are used for JavaScript assets.
*
* @param $data
* (optional) The default data parameter for the JavaScript asset array.
*
* @see hook_js_alter()
*/
function drupal_js_defaults($data = NULL) {
return array(
'type' => 'file',
'group' => JS_DEFAULT,
'every_page' => FALSE,
'weight' => 0,
'scope' => 'header',
'cache' => TRUE,
'preprocess' => TRUE,
'attributes' => array(),
'version' => NULL,
'data' => $data,
'browsers' => array(),
);
}
/**
* Merges two #attached arrays.
*
* The values under the 'drupalSettings' key are merged in a special way, to
* match the behavior of
*
* @code
* jQuery.extend(true, {}, $settings_items[0], $settings_items[1], ...)
* @endcode
*
* This means integer indices are preserved just like string indices are,
* rather than re-indexed as is common in PHP array merging.
*
* Example:
* @code
* function module1_page_attachments(&$page) {
* $page['a']['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c'];
* }
* function module2_page_attachments(&$page) {
* $page['#attached']['drupalSettings']['foo'] = ['d'];
* }
* // When the page is rendered after the above code, and the browser runs the
* // resulting