security update core+modules
This commit is contained in:
parent
2f45ea820a
commit
7c96373038
392
CHANGELOG.txt
392
CHANGELOG.txt
@ -1,5 +1,395 @@
|
||||
|
||||
Drupal 7.20, 2013-02-20 - test
|
||||
Drupal 7.36, 2015-04-01
|
||||
-----------------------
|
||||
- Added a 'file_public_schema' variable which allows modules that define
|
||||
publicly-accessible streams in hook_stream_wrappers() to bypass file download
|
||||
access checks when processing managed file upload fields.
|
||||
- Fixed a bug that caused database query tags not to be added to search-related
|
||||
database queries under many circumstances, and which prevented the
|
||||
corresponding hook_query_TAG_alter() implementations from being called.
|
||||
- Fixed the "for" attribute on managed file upload field labels to improve
|
||||
accessibility (minor markup change).
|
||||
- Added a 'javascript_always_use_jquery' variable which can be set to FALSE by
|
||||
sites that may not need jQuery loaded on all pages, and a 'requires_jquery'
|
||||
option to drupal_add_js() which modules can set to FALSE when adding
|
||||
JavaScript files that have no dependency on jQuery (API addition:
|
||||
https://www.drupal.org/node/2462717).
|
||||
- Fixed incorrect foreign keys in the User module's role_permission and
|
||||
users_roles database tables.
|
||||
- Changed permission descriptions throughout Drupal core to consistently link
|
||||
to relevant administrative pages, regardless of whether the user viewing the
|
||||
Permissions page can view the page being linked to (minor UI change).
|
||||
- Fixed the drupal_add_region_content() function so that it actually adds
|
||||
content to the page.
|
||||
- Added an 'image_suppress_itok_output' variable to allow sites already using
|
||||
the existing 'image_allow_insecure_derivatives' variable to also prevent
|
||||
security tokens from appearing in image derivative URLs.
|
||||
- Fixed double-escaping of theme names in the Block module administrative
|
||||
interface (minor string change).
|
||||
- Added basic support for Xdebug when running automated tests.
|
||||
- Fixed a bug which caused previewing a node to remove elements from the node
|
||||
being edited. With this fix, calling node_preview() will no longer modify the
|
||||
passed-in node object (minor API change).
|
||||
- Added a user_has_role() function to check whether a user has a particular
|
||||
role (API addition: https://www.drupal.org/node/2462411).
|
||||
- Fixed installation failures when an opcode cache is enabled.
|
||||
- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused private
|
||||
files to be inaccessible.
|
||||
- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused user
|
||||
pictures to be lost.
|
||||
- Fixed missing language code in hook_field_attach_view_alter() when it is
|
||||
invoked from field_view_field().
|
||||
- Stopped sending ETag and Last-Modified headers for uncached page requests,
|
||||
since they break caching for certain Varnish and Nginx configurations.
|
||||
- Changed the Simpletest module to allow PSR-4 test classes to be used in
|
||||
Drupal 7.
|
||||
- Fixed a fatal error that occurred when using the Comment module's "Unpublish
|
||||
comment containing keyword(s)" action.
|
||||
- Changed the "lang" attribute on language links to "xml:lang" so it validates
|
||||
as XHTML (minor markup change).
|
||||
- Prevented the form API from allowing arrays to be submitted for various form
|
||||
elements, such as textfields, textareas, and password fields (API change:
|
||||
https://www.drupal.org/node/2462723).
|
||||
- Fixed a bug in the Contact module which caused the global user object to have
|
||||
the incorrect name and e-mail address during the remainder of the page
|
||||
request after the contact form is submitted.
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.35, 2015-03-18
|
||||
----------------------
|
||||
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2015-001.
|
||||
|
||||
Drupal 7.34, 2014-11-19
|
||||
----------------------
|
||||
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-006.
|
||||
|
||||
Drupal 7.33, 2014-11-07
|
||||
-----------------------
|
||||
- Began storing the file modification time of each module and theme in the
|
||||
{system} database table so that contributed modules can use it to identify
|
||||
recently changed modules and themes (minor data structure change to the
|
||||
return value of system_get_info() and other related functions).
|
||||
- Added a "Did you mean?" feature to the run-tests.sh script for running
|
||||
automated tests from the command line, to help developers who are attempting
|
||||
to run a particular test class or group.
|
||||
- Changed the date format used in various HTTP headers output by Drupal core
|
||||
from RFC 1123 format to RFC 7231 format.
|
||||
- Added a "block_cache_bypass_node_grants" variable to allow sites which have
|
||||
node access modules enabled to use the block cache if desired (API addition).
|
||||
- Made image derivative generation HTTP requests return a 404 error (rather
|
||||
than a 500 error) when the source image does not exist.
|
||||
- Fixed a bug which caused user pictures to be removed from the user object
|
||||
after saving, and resulted in data loss if the user account was subsequently
|
||||
re-saved.
|
||||
- Fixed a bug in which field_has_data() did not return TRUE for fields that
|
||||
only had data in older entity revisions, leading to loss of the field's data
|
||||
when the field configuration was edited.
|
||||
- Fixed a bug which caused the Ajax progress throbber to appear misaligned in
|
||||
many situatons (minor styling change).
|
||||
- Prevented the Bartik theme from lower-casing the "Permalink" link on
|
||||
comments, for improved multilingual support (minor UI change).
|
||||
- Added a "preferred_menu_links" tag to the database query that is used by
|
||||
menu_link_get_preferred() to find the preferred menu link for a given path,
|
||||
to make it easier to alter.
|
||||
- Increased the maximum allowed length of block titles to 255 characters
|
||||
(database schema change to the {block} table).
|
||||
- Removed the Field module's field_modules_uninstalled() function, since it did
|
||||
not do anything when it was invoked.
|
||||
- Added a "theme_hook_original" variable to templates and theme functions and
|
||||
an optional sitewide theme debug mode, to provide contextual information in
|
||||
the page's HTML to theme developers. The theme debug mode is based on the one
|
||||
used with Twig in Drupal 8 and can be accessed by setting the "theme_debug"
|
||||
variable to TRUE (API addition).
|
||||
- Added an entity_view_mode_prepare() API function to allow entity-defining
|
||||
modules to properly invoke hook_entity_view_mode_alter(), and used it
|
||||
throughout Drupal core to fix bugs with the invocation of that hook (API
|
||||
change: https://www.drupal.org/node/2369141).
|
||||
- Security improvement: Made the database API's orderBy() method sanitize the
|
||||
sort direction ("ASC" or "DESC") for queries built with db_select(), so that
|
||||
calling code does not have to.
|
||||
- Changed the RDF module to consistently output RDF metadata for nodes and
|
||||
comments near where the node is rendered in the HTML (minor markup and data
|
||||
structure change).
|
||||
- Added an HTML class to RDFa metatags throughout Drupal to prevent them from
|
||||
accidentally affecting the site appearance (minor markup change).
|
||||
- Fixed a bug in the Unicode requirements check which prevented installing
|
||||
Drupal on PHP 5.6.
|
||||
- Fixed a bug which caused drupal_get_bootstrap_phase() to abort the bootstrap
|
||||
when called early in the page request.
|
||||
- Renamed the "Search result" view mode to "Search result highlighting input"
|
||||
to better reflect how it is used (UI change).
|
||||
- Improved database queries generated by EntityFieldQuery in the case where
|
||||
delta or language condition groups are used, to reduce the number of INNER
|
||||
JOINs (this is a minor data structure change affecting code which implements
|
||||
hook_query_alter() on these queries).
|
||||
- Removed special-case behavior for file uploads which allowed user #1 to
|
||||
bypass maximum file size and user quota limits.
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.32, 2014-10-15
|
||||
----------------------
|
||||
- Fixed security issues (SQL injection). See SA-CORE-2014-005.
|
||||
|
||||
Drupal 7.31, 2014-08-06
|
||||
----------------------
|
||||
- Fixed security issues (denial of service). See SA-CORE-2014-004.
|
||||
|
||||
Drupal 7.30, 2014-07-24
|
||||
-----------------------
|
||||
- Fixed a regression introduced in Drupal 7.29 that caused files or images
|
||||
attached to taxonomy terms to be deleted when the taxonomy term was edited
|
||||
and resaved (and other related bugs with contributed and custom modules).
|
||||
- Added a warning on the permissions page to recommend restricting access to
|
||||
the "View site reports" permission to trusted administrators. See
|
||||
DRUPAL-PSA-2014-002.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.29, 2014-07-16
|
||||
----------------------
|
||||
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-003.
|
||||
|
||||
Drupal 7.28, 2014-05-08
|
||||
-----------------------
|
||||
- Fixed a regression introduced in Drupal 7.27 that caused JavaScript to break
|
||||
on older browsers (such as Internet Explorer 8 and earlier) when Ajax was
|
||||
used.
|
||||
- Increased the timeout used by the Update Manager module when it fetches data
|
||||
from drupal.org (from 5 seconds to 30 seconds), to work around a problem
|
||||
which causes incomplete information about security updates to be presented to
|
||||
site administrators. This fix may lead to a performance slowdown on the
|
||||
Update Manager administration pages, when installing Drupal distributions,
|
||||
and (for sites that use the automated cron feature) on occasional page loads
|
||||
by site visitors.
|
||||
- Fixed the behavior of the token system's "[node:summary]" token when the body
|
||||
field does not have a manual summary.
|
||||
- Changed the behavior of db_query_temporary() so that it works on SELECT
|
||||
queries even when they have leading comments/whitespace. A side effect of
|
||||
this fix is that db_query_temporary() will now fail with an error if it is
|
||||
ever used on non-SELECT queries.
|
||||
- Added a "node_admin_filter" tag to the database query used to build the list
|
||||
of nodes on the content administration page, to make it easier to alter.
|
||||
- Made the cron queue system log any exceptions that are thrown while an item
|
||||
in the queue is being processed, rather than stopping the entire PHP request.
|
||||
- Improved screen reader support by adding an aria-live HTML attribute to file
|
||||
upload fields when there is an error uploading the file (minor markup
|
||||
change).
|
||||
- Made the pager on the Tracker module listing pages show the same number of
|
||||
items as other pagers throughout Drupal core (minor UI change).
|
||||
- Fixed a bug which caused caches not to be properly cleared when a file entity
|
||||
was saved or deleted.
|
||||
- Added several missing countries to the default list returned by
|
||||
country_get_list() (string change).
|
||||
- Replaced the term "weight" with "influence" in the content ranking settings
|
||||
for search, and added help text for administrators (string change).
|
||||
- Fixed untranslatable text strings in the administrative interface for the
|
||||
"Crop" effect provided by the Image module (minor string change).
|
||||
- Fixed a bug in the Taxonomy module update function introduced in Drupal 7.26
|
||||
that caused memory and CPU problems on sites with very large numbers of
|
||||
unpublished nodes.
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.27, 2014-04-16
|
||||
----------------------
|
||||
- Fixed security issues (information disclosure). See SA-CORE-2014-002.
|
||||
|
||||
Drupal 7.26, 2014-01-15
|
||||
----------------------
|
||||
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-001.
|
||||
|
||||
Drupal 7.25, 2014-01-02
|
||||
-----------------------
|
||||
- Fixed a bug in node_save() which prevented the saved node from being updated
|
||||
in hook_node_insert() and other similar hooks.
|
||||
- Added a meta tag to install.php to prevent it from being indexed by search
|
||||
engines even when Drupal is installed in a subfolder (minor markup change).
|
||||
- Fixed a bug in the database API that caused frequent deadlock errors when
|
||||
running merge queries on some servers.
|
||||
- Performance improvement: Prevented block rehashing from writing blocks to the
|
||||
database on every cache clear and cron run when the blocks have not changed.
|
||||
This fix results in an extra 'saved' key which is added and set to TRUE for
|
||||
each block returned by _block_rehash() that actually is saved to the database
|
||||
(data structure change).
|
||||
- Added an optional 'skip on cron' parameter to hook_cron_queue_info() to allow
|
||||
queues to avoid being automatically processed on cron runs (API addition).
|
||||
- Fixed a bug which caused hook_block_view_MODULE_DELTA_alter() to never be
|
||||
invoked if the block delta had a hyphen in it. To implement the hook when the
|
||||
block delta has a hyphen, modules should now replace hyphens with underscores
|
||||
when constructing the function name for the hook implementation.
|
||||
- Fixed a bug which caused cached pages to sometimes be sent to the browser
|
||||
with incorrect compression. The fix adds a new 'page_compressed' key to the
|
||||
$cache->data array returned by drupal_page_get_cache() (minor data structure
|
||||
change).
|
||||
- Fixed broken tests on PHP 5.5.
|
||||
- Made the File and Image modules more robust when saving entities that have
|
||||
deleted files attached. The code in file_field_presave() will now remove the
|
||||
record of the deleted file from the entity before saving (minor data
|
||||
structure change).
|
||||
- Standardized menu callback functions throughout Drupal core to return
|
||||
MENU_NOT_FOUND and MENU_ACCESS_DENIED rather than printing their own "page
|
||||
not found" or "access denied" pages (minor API change in the return value of
|
||||
these functions under some circumstances).
|
||||
- Fixed a bug in which caches were not properly cleared when a node was deleted
|
||||
via the administrative interface.
|
||||
- Changed the Bartik theme to render content contained in <pre>, <code> and
|
||||
similar tags in a larger font size, so it is easier to read.
|
||||
- Fixed a bug in the Search module that caused exceptions to be thrown during
|
||||
searches if the server was not configured to represent decimal points as a
|
||||
period.
|
||||
- Fixed a regression in the Image module that made image_style_url() not work
|
||||
when a relative path (rather than a complete file URI) was passed to it.
|
||||
- Added an optional feature to the Statistics module to allow node views to be
|
||||
tracked by Ajax requests rather than during the server-side generation of the
|
||||
page. This allows the node counter to work on sites that use external page
|
||||
caches (string change and new administrative option:
|
||||
https://drupal.org/node/2164069).
|
||||
- Added a link to the drupal.org documentation page for cron to the Cron
|
||||
settings page (string change).
|
||||
- Added a 'drupal_anonymous_user_object' variable to allow the anonymous user
|
||||
object returned by drupal_anonymous_user() to be overridden with a classed
|
||||
object (API addition).
|
||||
- Changed the database API to allow inserts based on a SELECT * query to work
|
||||
correctly.
|
||||
- Changed the database schema of the {file_managed} table to allow Drupal to
|
||||
manage files larger than 4 GB.
|
||||
- Changed the File module's hook_field_load() implementation to prevent file
|
||||
entity properties which have the same name as file or image field properties
|
||||
from overwriting the field properties (minor API change).
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.24, 2013-11-20
|
||||
----------------------
|
||||
- Fixed security issues (multiple vulnerabilities), see SA-CORE-2013-003.
|
||||
|
||||
Drupal 7.23, 2013-08-07
|
||||
-----------------------
|
||||
- Fixed a fatal error on PostgreSQL databases when updating the Taxonomy module
|
||||
from Drupal 6 to Drupal 7.
|
||||
- Fixed the default ordering of CSS files for sites using right-to-left
|
||||
languages, to consistently place the right-to-left override file immediately
|
||||
after the CSS it is overriding (API change: https://drupal.org/node/2058463).
|
||||
- Added a drupal_check_memory_limit() API function to allow the memory limit to
|
||||
be checked consistently (API addition).
|
||||
- Changed the default web.config file for IIS servers to allow favicon.ico
|
||||
files which are present in the filesystem to be accessed.
|
||||
- Fixed inconsistent support for the 'tel' protocol in Drupal's URL filtering
|
||||
functions.
|
||||
- Performance improvement: Allowed all hooks to be included in the
|
||||
module_implements() cache, even those that are only invoked on HTTP POST
|
||||
requests.
|
||||
- Made the database system replace truncate queries with delete queries when
|
||||
inside a transaction, to fix issues with PostgreSQL and other databases.
|
||||
- Fixed a bug which caused nested contextual links to display improperly.
|
||||
- Fixed a bug which prevented cached image derivatives from being flushed for
|
||||
private files and other non-default file schemes.
|
||||
- Fixed drupal_render() to always return an empty string when there is no
|
||||
output, rather than sometimes returning NULL (minor API change).
|
||||
- Added protection to cache_clear_all() to ensure that non-cache tables cannot
|
||||
be truncated (API addition: a new isValidBin() method has been added to the
|
||||
default database cache implementation).
|
||||
- Changed the default .htaccess file to support HTTP authorization in CGI
|
||||
environments.
|
||||
- Changed the password reset form to pre-fill the username when requested via a
|
||||
URL query parameter, and used this in the error message that appears after a
|
||||
failed login attempt (minor data structure and behavior change).
|
||||
- Fixed broken support for foreign keys in the field API.
|
||||
- Fixed "No active batch" error when a user cancels their own account.
|
||||
- Added a description to the "access content overview" permission on the
|
||||
permissions page (string change).
|
||||
- Added a drupal_array_diff_assoc_recursive() function to allow associative
|
||||
arrays to be compared recursively (API addition).
|
||||
- Added human-readable labels to image styles, in addition to the existing
|
||||
machine-readable name (API change: https://drupal.org/node/2058503).
|
||||
- Moved the drupal_get_hash_salt() function to bootstrap.inc and used it in
|
||||
additional places in the code, for added security in the case where there is
|
||||
no hash salt in settings.php.
|
||||
- Fixed a regression in Drupal 7.22 that caused internal server errors for
|
||||
sites running on very old Apache 1.x web servers.
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.22, 2013-04-03
|
||||
-----------------------
|
||||
- Allowed the drupal_http_request() function to be overridden so that
|
||||
additional HTTP request capabilities can be added by contributed modules.
|
||||
- Changed the Simpletest module to allow PSR-0 test classes to be used in
|
||||
Drupal 7.
|
||||
- Removed an unnecessary "Content-Disposition" header from private file
|
||||
downloads; it prevented many private files from being viewed inline in a web
|
||||
browser.
|
||||
- Changed various field API functions to allow them to optionally act on a
|
||||
single field within an entity (API addition: http://drupal.org/node/1825844).
|
||||
- Fixed a bug which prevented Drupal's file transfer functionality from working
|
||||
on some PHP 5.4 systems.
|
||||
- Fixed incorrect log message when theme() is called for a theme hook that does
|
||||
not exist (minor string change).
|
||||
- Fixed Drupal's token-replacement system to allow spaces in the token value.
|
||||
- Changed the default behavior after a user creates a node they do not have
|
||||
access to view. The user will now be redirected to the front page rather than
|
||||
an access denied page.
|
||||
- Fixed a bug which prevented empty HTTP headers (such as "0") from being set.
|
||||
(Minor behavior change: Callers of drupal_add_http_header() must now set
|
||||
FALSE explicitly to prevent a header from being sent at all; this was already
|
||||
indicated in the function's documentation.)
|
||||
- Fixed OpenID errors when more than one module implements hook_openid(). The
|
||||
behavior is now changed so that if more than one module tries to set the same
|
||||
parameter, the last module's change takes effect.
|
||||
- Fixed a serious documentation bug: The $name variable in the
|
||||
taxonomy-term.tpl.php theme template was incorrectly documented as being
|
||||
sanitized when in fact it is not.
|
||||
- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
|
||||
duplicate permission names in the User module's database tables.
|
||||
- Added an empty "datatype" attribute to taxonomy term and username links to
|
||||
make the RDFa markup upward compatible with RDFa 1.1 (minor markup addition).
|
||||
- Fixed a bug which caused the denial-of-service protection added in Drupal
|
||||
7.20 to break certain valid image URLs that had an extra slash in them.
|
||||
- Fixed a bug with update queries in the SQLite database driver that prevented
|
||||
Drupal from being installed with SQLite on PHP 5.4.
|
||||
- Fixed enforced dependencies errors updating to recent versions of Drupal 7 on
|
||||
certain non-MySQL databases.
|
||||
- Refactored the Field module's caching behavior to obtain large improvements
|
||||
in memory usage for sites with many fields and instances (API addition:
|
||||
http://drupal.org/node/1915646).
|
||||
- Fixed entity argument not being passed to implementations of
|
||||
hook_file_download_access_alter(). The fix adds an additional context
|
||||
parameter that can be passed when calling drupal_alter() for any hook (API
|
||||
change: http://drupal.org/node/1882722).
|
||||
- Fixed broken support for translatable comment fields (API change:
|
||||
http://drupal.org/node/1874724).
|
||||
- Added an assertThemeOutput() method to Simpletest to allow tests to check
|
||||
that themed output matches an expected HTML string (API addition).
|
||||
- Added a link to "Install another module" after a module has been successfully
|
||||
downloaded via the Update Manager (UI change).
|
||||
- Added an optional "exclusive" flag to installation profile .info files which
|
||||
allows Drupal distributions to force a profile to be selected during
|
||||
installation (API addition: http://drupal.org/node/1961012).
|
||||
- Fixed a bug which caused the database API to not properly close database
|
||||
connections.
|
||||
- Added a link to the URL for running cron from outside the site to the Cron
|
||||
settings page (UI change).
|
||||
- Fixed a bug which prevented image styles from being reverted on PHP 5.4.
|
||||
- Made the default .htaccess rules protocol sensitive to improve security for
|
||||
sites which use HTTPS and redirect between "www" and non-"www" versions of
|
||||
the page.
|
||||
- Numerous small bug fixes.
|
||||
- Numerous API documentation improvements.
|
||||
- Additional automated test coverage.
|
||||
|
||||
Drupal 7.21, 2013-03-06
|
||||
-----------------------
|
||||
- Allowed sites using the 'image_allow_insecure_derivatives' variable to still
|
||||
have partial protection from the security issues fixed in Drupal 7.20.
|
||||
|
||||
Drupal 7.20, 2013-02-20
|
||||
-----------------------
|
||||
- Fixed security issues (denial of service). See SA-CORE-2013-002.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
All Drupal code is Copyright 2001 - 2012 by the original authors.
|
||||
All Drupal code is Copyright 2001 - 2013 by the original authors.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,18 +20,21 @@ initial database files. Next you must log in and set the access database rights:
|
||||
Again, you will be asked for the 'username' database password. At the MySQL
|
||||
prompt, enter the following command:
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
|
||||
ON databasename.*
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
|
||||
CREATE TEMPORARY TABLES ON databasename.*
|
||||
TO 'username'@'localhost' IDENTIFIED BY 'password';
|
||||
|
||||
where
|
||||
where:
|
||||
|
||||
'databasename' is the name of your database
|
||||
'username@localhost' is the username of your MySQL account
|
||||
'username' is the username of your MySQL account
|
||||
'localhost' is the web server host where Drupal is installed
|
||||
'password' is the password required for that username
|
||||
|
||||
Note: Unless your database user has all of the privileges listed above, you will
|
||||
not be able to run Drupal.
|
||||
Note: Unless the database user/host combination for your Drupal installation
|
||||
has all of the privileges listed above (except possibly CREATE TEMPORARY TABLES,
|
||||
which is currently only used by Drupal core automated tests and some
|
||||
contributed modules), you will not be able to install or run Drupal.
|
||||
|
||||
If successful, MySQL will reply with:
|
||||
|
||||
|
@ -20,6 +20,8 @@ Drupal requires:
|
||||
- MySQL 5.0.15 (or greater) (http://www.mysql.com/).
|
||||
- MariaDB 5.1.44 (or greater) (http://mariadb.org/). MariaDB is a fully
|
||||
compatible drop-in replacement for MySQL.
|
||||
- Percona Server 5.1.70 (or greater) (http://www.percona.com/). Percona
|
||||
Server is a backwards-compatible replacement for MySQL.
|
||||
- PostgreSQL 8.3 (or greater) (http://www.postgresql.org/).
|
||||
- SQLite 3.4.2 (or greater) (http://www.sqlite.org/).
|
||||
|
||||
|
14
LICENSE.txt
14
LICENSE.txt
@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
|
@ -27,7 +27,6 @@ Ajax system
|
||||
- Earl Miles 'merlinofchaos' http://drupal.org/user/26979
|
||||
|
||||
Base system
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
|
||||
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
|
||||
|
||||
@ -39,7 +38,6 @@ Cache system
|
||||
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
|
||||
|
||||
Cron system
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
- Derek Wright 'dww' http://drupal.org/user/46549
|
||||
|
||||
Database system
|
||||
@ -55,10 +53,8 @@ Database system
|
||||
|
||||
- Sqlite driver
|
||||
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
|
||||
Database update system
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
- Ashok Modi 'BTMash' http://drupal.org/user/60422
|
||||
|
||||
Entity system
|
||||
@ -71,7 +67,6 @@ File system
|
||||
- Aaron Winborn 'aaron' http://drupal.org/user/33420
|
||||
|
||||
Form system
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
- Alex Bronstein 'effulgentsia' http://drupal.org/user/78040
|
||||
- Wolfgang Ziegler 'fago' http://drupal.org/user/16747
|
||||
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
|
||||
@ -105,7 +100,6 @@ Markup
|
||||
|
||||
Menu system
|
||||
- Peter Wolanin 'pwolanin' http://drupal.org/user/49851
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
|
||||
Path system
|
||||
- Dave Reid 'davereid' http://drupal.org/user/53892
|
||||
@ -139,9 +133,6 @@ Accessibility
|
||||
Documentation
|
||||
- Jennifer Hodgdon 'jhodgdon' http://drupal.org/user/155601
|
||||
|
||||
Security
|
||||
- Greg Knaddison 'greggles' http://drupal.org/user/36762
|
||||
|
||||
Translations
|
||||
- Gerhard Killesreiter 'killes' http://drupal.org/user/83
|
||||
|
||||
@ -154,6 +145,20 @@ Node Access
|
||||
- Ken Rickard 'agentrickard' http://drupal.org/user/20975
|
||||
- Jess Myrbo 'xjm' http://drupal.org/user/65776
|
||||
|
||||
|
||||
Security team
|
||||
-----------------
|
||||
|
||||
To report a security issue, see: https://drupal.org/security-team/report-issue
|
||||
|
||||
The Drupal security team provides Security Advisories for vulnerabilities,
|
||||
assists developers in resolving security issues, and provides security
|
||||
documentation. See http://drupal.org/security-team for more information. The
|
||||
security team lead is:
|
||||
|
||||
- Michael Hess 'mlhess' https://drupal.org/user/102818
|
||||
|
||||
|
||||
Module maintainers
|
||||
------------------
|
||||
|
||||
@ -250,7 +255,6 @@ Shortcut module
|
||||
|
||||
Simpletest module
|
||||
- Jimmy Berry 'boombatower' http://drupal.org/user/214218
|
||||
- Károly Négyesi 'chx' http://drupal.org/user/9446
|
||||
|
||||
Statistics module
|
||||
- Tim Millwood 'timmillwood' http://drupal.org/user/227849
|
||||
|
12
README.txt
12
README.txt
@ -71,12 +71,12 @@ profiles/your_site_profile/themes respectively to restrict their usage to only
|
||||
sites that were installed with that specific profile.
|
||||
|
||||
More about installation profiles and distributions:
|
||||
* Read about the difference between installation profiles and distributions:
|
||||
http://drupal.org/node/1089736
|
||||
* Download contributed installation profiles and distributions:
|
||||
http://drupal.org/project/distributions
|
||||
* Develop your own installation profile or distribution:
|
||||
http://drupal.org/developing/distributions
|
||||
* Read about the difference between installation profiles and distributions:
|
||||
http://drupal.org/node/1089736
|
||||
* Download contributed installation profiles and distributions:
|
||||
http://drupal.org/project/distributions
|
||||
* Develop your own installation profile or distribution:
|
||||
http://drupal.org/developing/distributions
|
||||
|
||||
APPEARANCE
|
||||
----------
|
||||
|
@ -4,16 +4,16 @@
|
||||
* @file
|
||||
* Administrative script for running authorized file operations.
|
||||
*
|
||||
* Using this script, the site owner (the user actually owning the files on
|
||||
* the webserver) can authorize certain file-related operations to proceed
|
||||
* with elevated privileges, for example to deploy and upgrade modules or
|
||||
* themes. Users should not visit this page directly, but instead use an
|
||||
* administrative user interface which knows how to redirect the user to this
|
||||
* script as part of a multistep process. This script actually performs the
|
||||
* selected operations without loading all of Drupal, to be able to more
|
||||
* gracefully recover from errors. Access to the script is controlled by a
|
||||
* global killswitch in settings.php ('allow_authorize_operations') and via
|
||||
* the 'administer software updates' permission.
|
||||
* Using this script, the site owner (the user actually owning the files on the
|
||||
* webserver) can authorize certain file-related operations to proceed with
|
||||
* elevated privileges, for example to deploy and upgrade modules or themes.
|
||||
* Users should not visit this page directly, but instead use an administrative
|
||||
* user interface which knows how to redirect the user to this script as part of
|
||||
* a multistep process. This script actually performs the selected operations
|
||||
* without loading all of Drupal, to be able to more gracefully recover from
|
||||
* errors. Access to the script is controlled by a global killswitch in
|
||||
* settings.php ('allow_authorize_operations') and via the 'administer software
|
||||
* updates' permission.
|
||||
*
|
||||
* There are helper functions for setting up an operation to run via this
|
||||
* system in modules/system/system.module. For more information, see:
|
||||
@ -21,16 +21,17 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Root directory of Drupal installation.
|
||||
* Defines the root directory of the Drupal installation.
|
||||
*/
|
||||
define('DRUPAL_ROOT', getcwd());
|
||||
|
||||
/**
|
||||
* Global flag to identify update.php and authorize.php runs, and so
|
||||
* avoid various unwanted operations, such as hook_init() and
|
||||
* hook_exit() invokes, css/js preprocessing and translation, and
|
||||
* solve some theming issues. This flag is checked on several places
|
||||
* in Drupal code (not just authorize.php).
|
||||
* Global flag to identify update.php and authorize.php runs.
|
||||
*
|
||||
* Identifies update.php and authorize.php runs, avoiding unwanted operations
|
||||
* such as hook_init() and hook_exit() invokes, css/js preprocessing and
|
||||
* translation, and solves some theming issues. The flag is checked in other
|
||||
* places in Drupal code (not just authorize.php).
|
||||
*/
|
||||
define('MAINTENANCE_MODE', 'update');
|
||||
|
||||
@ -51,7 +52,7 @@ function authorize_access_denied_page() {
|
||||
* have access to the 'administer software updates' permission.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the current user can run authorize.php, otherwise FALSE.
|
||||
* TRUE if the current user can run authorize.php, and FALSE if not.
|
||||
*/
|
||||
function authorize_access_allowed() {
|
||||
return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
|
||||
|
@ -211,7 +211,7 @@
|
||||
*
|
||||
* When returning an Ajax command array, it is often useful to have
|
||||
* status messages rendered along with other tasks in the command array.
|
||||
* In that case the the Ajax commands array may be constructed like this:
|
||||
* In that case the Ajax commands array may be constructed like this:
|
||||
* @code
|
||||
* $commands = array();
|
||||
* $commands[] = ajax_command_replace(NULL, $output);
|
||||
@ -251,8 +251,8 @@ function ajax_render($commands = array()) {
|
||||
// reliably diffed with array_diff_key(), since the number can change
|
||||
// due to factors unrelated to the inline content, so for now, we strip
|
||||
// the inline items from Ajax responses, and can add support for them
|
||||
// when drupal_add_css() and drupal_add_js() are changed to using md5()
|
||||
// or some other hash of the inline content.
|
||||
// when drupal_add_css() and drupal_add_js() are changed to use a hash
|
||||
// of the inline content as the array key.
|
||||
foreach ($items[$type] as $key => $item) {
|
||||
if (is_numeric($key)) {
|
||||
unset($items[$type][$key]);
|
||||
@ -276,7 +276,7 @@ function ajax_render($commands = array()) {
|
||||
|
||||
$extra_commands = array();
|
||||
if (!empty($styles)) {
|
||||
$extra_commands[] = ajax_command_prepend('head', $styles);
|
||||
$extra_commands[] = ajax_command_add_css($styles);
|
||||
}
|
||||
if (!empty($scripts_header)) {
|
||||
$extra_commands[] = ajax_command_prepend('head', $scripts_header);
|
||||
@ -292,7 +292,7 @@ function ajax_render($commands = array()) {
|
||||
$scripts = drupal_add_js();
|
||||
if (!empty($scripts['settings'])) {
|
||||
$settings = $scripts['settings'];
|
||||
array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
|
||||
array_unshift($commands, ajax_command_settings(drupal_array_merge_deep_array($settings['data']), TRUE));
|
||||
}
|
||||
|
||||
// Allow modules to alter any Ajax response.
|
||||
@ -308,10 +308,11 @@ function ajax_render($commands = array()) {
|
||||
* pulls the form info from $_POST.
|
||||
*
|
||||
* @return
|
||||
* An array containing the $form and $form_state. Use the list() function
|
||||
* to break these apart:
|
||||
* An array containing the $form, $form_state, $form_id, $form_build_id and an
|
||||
* initial list of Ajax $commands. Use the list() function to break these
|
||||
* apart:
|
||||
* @code
|
||||
* list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
|
||||
* list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
|
||||
* @endcode
|
||||
*/
|
||||
function ajax_get_form() {
|
||||
@ -331,6 +332,17 @@ function ajax_get_form() {
|
||||
drupal_exit();
|
||||
}
|
||||
|
||||
// When a page level cache is enabled, the form-build id might have been
|
||||
// replaced from within form_get_cache. If this is the case, it is also
|
||||
// necessary to update it in the browser by issuing an appropriate Ajax
|
||||
// command.
|
||||
$commands = array();
|
||||
if (isset($form['#build_id_old']) && $form['#build_id_old'] != $form['#build_id']) {
|
||||
// If the form build ID has changed, issue an Ajax command to update it.
|
||||
$commands[] = ajax_command_update_build_id($form);
|
||||
$form_build_id = $form['#build_id'];
|
||||
}
|
||||
|
||||
// Since some of the submit handlers are run, redirects need to be disabled.
|
||||
$form_state['no_redirect'] = TRUE;
|
||||
|
||||
@ -345,7 +357,7 @@ function ajax_get_form() {
|
||||
$form_state['input'] = $_POST;
|
||||
$form_id = $form['#form_id'];
|
||||
|
||||
return array($form, $form_state, $form_id, $form_build_id);
|
||||
return array($form, $form_state, $form_id, $form_build_id, $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,7 +378,7 @@ function ajax_get_form() {
|
||||
* @see system_menu()
|
||||
*/
|
||||
function ajax_form_callback() {
|
||||
list($form, $form_state) = ajax_get_form();
|
||||
list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
|
||||
drupal_process_form($form['#form_id'], $form, $form_state);
|
||||
|
||||
// We need to return the part of the form (or some other content) that needs
|
||||
@ -379,7 +391,19 @@ function ajax_form_callback() {
|
||||
$callback = $form_state['triggering_element']['#ajax']['callback'];
|
||||
}
|
||||
if (!empty($callback) && function_exists($callback)) {
|
||||
return $callback($form, $form_state);
|
||||
$result = $callback($form, $form_state);
|
||||
|
||||
if (!(is_array($result) && isset($result['#type']) && $result['#type'] == 'ajax')) {
|
||||
// Turn the response into a #type=ajax array if it isn't one already.
|
||||
$result = array(
|
||||
'#type' => 'ajax',
|
||||
'#commands' => ajax_prepare_response($result),
|
||||
);
|
||||
}
|
||||
|
||||
$result['#commands'] = array_merge($commands, $result['#commands']);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -836,7 +860,8 @@ function ajax_command_insert($selector, $html, $settings = NULL) {
|
||||
* @return
|
||||
* An array suitable for use with the ajax_render() function.
|
||||
*
|
||||
* See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
|
||||
* See
|
||||
* @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
|
||||
*/
|
||||
function ajax_command_replace($selector, $html, $settings = NULL) {
|
||||
return array(
|
||||
@ -1209,3 +1234,49 @@ function ajax_command_restripe($selector) {
|
||||
'selector' => $selector,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Drupal Ajax 'update_build_id' command.
|
||||
*
|
||||
* This command updates the value of a hidden form_build_id input element on a
|
||||
* form. It requires the form passed in to have keys for both the old build ID
|
||||
* in #build_id_old and the new build ID in #build_id.
|
||||
*
|
||||
* The primary use case for this Ajax command is to serve a new build ID to a
|
||||
* form served from the cache to an anonymous user, preventing one anonymous
|
||||
* user from accessing the form state of another anonymous users on Ajax enabled
|
||||
* forms.
|
||||
*
|
||||
* @param $form
|
||||
* The form array representing the form whose build ID should be updated.
|
||||
*/
|
||||
function ajax_command_update_build_id($form) {
|
||||
return array(
|
||||
'command' => 'updateBuildId',
|
||||
'old' => $form['#build_id_old'],
|
||||
'new' => $form['#build_id'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Drupal Ajax 'add_css' command.
|
||||
*
|
||||
* This method will add css via ajax in a cross-browser compatible way.
|
||||
*
|
||||
* This command is implemented by Drupal.ajax.prototype.commands.add_css()
|
||||
* defined in misc/ajax.js.
|
||||
*
|
||||
* @param $styles
|
||||
* A string that contains the styles to be added.
|
||||
*
|
||||
* @return
|
||||
* An array suitable for use with the ajax_render() function.
|
||||
*
|
||||
* @see misc/ajax.js
|
||||
*/
|
||||
function ajax_command_add_css($styles) {
|
||||
return array(
|
||||
'command' => 'add_css',
|
||||
'data' => $styles,
|
||||
);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
/**
|
||||
* The current system version.
|
||||
*/
|
||||
define('VERSION', '7.20');
|
||||
define('VERSION', '7.36');
|
||||
|
||||
/**
|
||||
* Core API compatibility.
|
||||
@ -218,12 +218,16 @@ define('LANGUAGE_RTL', 1);
|
||||
define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
|
||||
|
||||
/**
|
||||
* Flag for drupal_set_title(); text is not sanitized, so run check_plain().
|
||||
* Flag used to indicate that text is not sanitized, so run check_plain().
|
||||
*
|
||||
* @see drupal_set_title()
|
||||
*/
|
||||
define('CHECK_PLAIN', 0);
|
||||
|
||||
/**
|
||||
* Flag for drupal_set_title(); text has already been sanitized.
|
||||
* Flag used to indicate that text has already been sanitized.
|
||||
*
|
||||
* @see drupal_set_title()
|
||||
*/
|
||||
define('PASS_THROUGH', -1);
|
||||
|
||||
@ -240,10 +244,19 @@ define('REGISTRY_WRITE_LOOKUP_CACHE', 2);
|
||||
/**
|
||||
* Regular expression to match PHP function names.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.functions.php
|
||||
* @see http://php.net/manual/language.functions.php
|
||||
*/
|
||||
define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*');
|
||||
|
||||
/**
|
||||
* A RFC7231 Compliant date.
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc7231#section-7.1.1.1
|
||||
*
|
||||
* Example: Sun, 06 Nov 1994 08:49:37 GMT
|
||||
*/
|
||||
define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
|
||||
|
||||
/**
|
||||
* Provides a caching wrapper to be used in place of large array structures.
|
||||
*
|
||||
@ -274,7 +287,7 @@ define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
|
||||
* error, and $var will be populated with the contents of $object['foo'], but
|
||||
* that data will be passed by value, not reference. For more information on
|
||||
* the PHP limitation, see the note in the official PHP documentation at·
|
||||
* http://php.net/manual/en/arrayaccess.offsetget.php on
|
||||
* http://php.net/manual/arrayaccess.offsetget.php on
|
||||
* ArrayAccess::offsetGet().
|
||||
*
|
||||
* By default, the class accounts for caches where calling functions might
|
||||
@ -380,11 +393,11 @@ abstract class DrupalCacheArray implements ArrayAccess {
|
||||
* without necessarily writing back to the persistent cache at the end.
|
||||
*
|
||||
* @param $offset
|
||||
* The array offset that was request.
|
||||
* The array offset that was requested.
|
||||
* @param $persist
|
||||
* Optional boolean to specify whether the offset should be persisted or
|
||||
* not, defaults to TRUE. When called with $persist = FALSE the offset will
|
||||
* be unflagged so that it will not written at the end of the request.
|
||||
* be unflagged so that it will not be written at the end of the request.
|
||||
*/
|
||||
protected function persist($offset, $persist = TRUE) {
|
||||
$this->keysToPersist[$offset] = $persist;
|
||||
@ -516,9 +529,8 @@ function timer_stop($name) {
|
||||
* Returns the appropriate configuration directory.
|
||||
*
|
||||
* Returns the configuration path based on the site's hostname, port, and
|
||||
* pathname. Uses find_conf_path() to find the current configuration directory.
|
||||
* See default.settings.php for examples on how the URL is converted to a
|
||||
* directory.
|
||||
* pathname. See default.settings.php for examples on how the URL is converted
|
||||
* to a directory.
|
||||
*
|
||||
* @param bool $require_settings
|
||||
* Only configuration directories with an existing settings.php file
|
||||
@ -679,7 +691,8 @@ function drupal_environment_initialize() {
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
ini_set('session.use_trans_sid', '0');
|
||||
// Don't send HTTP headers using PHP's session handler.
|
||||
ini_set('session.cache_limiter', 'none');
|
||||
// An empty string is used here to disable the cache limiter.
|
||||
ini_set('session.cache_limiter', '');
|
||||
// Use httponly session cookies.
|
||||
ini_set('session.cookie_httponly', '1');
|
||||
|
||||
@ -695,7 +708,14 @@ function drupal_environment_initialize() {
|
||||
* TRUE if only containing valid characters, or FALSE otherwise.
|
||||
*/
|
||||
function drupal_valid_http_host($host) {
|
||||
return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
|
||||
// Limit the length of the host name to 1000 bytes to prevent DoS attacks with
|
||||
// long host names.
|
||||
return strlen($host) <= 1000
|
||||
// Limit the number of subdomains and port separators to prevent DoS attacks
|
||||
// in conf_path().
|
||||
&& substr_count($host, '.') <= 100
|
||||
&& substr_count($host, ':') <= 100
|
||||
&& preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -716,7 +736,6 @@ function drupal_settings_initialize() {
|
||||
if (isset($base_url)) {
|
||||
// Parse fixed base URL from settings.php.
|
||||
$parts = parse_url($base_url);
|
||||
$http_protocol = $parts['scheme'];
|
||||
if (!isset($parts['path'])) {
|
||||
$parts['path'] = '';
|
||||
}
|
||||
@ -792,7 +811,7 @@ function drupal_settings_initialize() {
|
||||
*
|
||||
* This function plays a key role in allowing Drupal's resources (modules
|
||||
* and themes) to be located in different places depending on a site's
|
||||
* configuration. For example, a module 'foo' may legally be be located
|
||||
* configuration. For example, a module 'foo' may legally be located
|
||||
* in any of these three places:
|
||||
*
|
||||
* modules/foo/foo.module
|
||||
@ -803,7 +822,7 @@ function drupal_settings_initialize() {
|
||||
* the above, depending on where the module is located.
|
||||
*
|
||||
* @param $type
|
||||
* The type of the item (i.e. theme, theme_engine, module, profile).
|
||||
* The type of the item (theme, theme_engine, module, profile).
|
||||
* @param $name
|
||||
* The name of the item for which the filename is requested.
|
||||
* @param $filename
|
||||
@ -811,7 +830,7 @@ function drupal_settings_initialize() {
|
||||
* than by consulting the database.
|
||||
*
|
||||
* @return
|
||||
* The filename of the requested item.
|
||||
* The filename of the requested item or NULL if the item is not found.
|
||||
*/
|
||||
function drupal_get_filename($type, $name, $filename = NULL) {
|
||||
// The location of files will not change during the request, so do not use
|
||||
@ -841,7 +860,7 @@ function drupal_get_filename($type, $name, $filename = NULL) {
|
||||
try {
|
||||
if (function_exists('db_query')) {
|
||||
$file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
|
||||
if (file_exists(DRUPAL_ROOT . '/' . $file)) {
|
||||
if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) {
|
||||
$files[$type][$name] = $file;
|
||||
}
|
||||
}
|
||||
@ -1186,10 +1205,11 @@ function _drupal_set_preferred_header_name($name = NULL) {
|
||||
* Headers are set in drupal_add_http_header(). Default headers are not set
|
||||
* if they have been replaced or unset using drupal_add_http_header().
|
||||
*
|
||||
* @param $default_headers
|
||||
* An array of headers as name/value pairs.
|
||||
* @param $single
|
||||
* If TRUE and headers have already be sent, send only the specified header.
|
||||
* @param array $default_headers
|
||||
* (optional) An array of headers as name/value pairs.
|
||||
* @param bool $only_default
|
||||
* (optional) If TRUE and headers have already been sent, send only the
|
||||
* specified headers.
|
||||
*/
|
||||
function drupal_send_headers($default_headers = array(), $only_default = FALSE) {
|
||||
$headers_sent = &drupal_static(__FUNCTION__, FALSE);
|
||||
@ -1212,7 +1232,7 @@ function drupal_send_headers($default_headers = array(), $only_default = FALSE)
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value);
|
||||
}
|
||||
// Skip headers that have been unset.
|
||||
elseif ($value) {
|
||||
elseif ($value !== FALSE) {
|
||||
header($header_names[$name_lower] . ': ' . $value);
|
||||
}
|
||||
}
|
||||
@ -1225,23 +1245,10 @@ function drupal_send_headers($default_headers = array(), $only_default = FALSE)
|
||||
* fresh page on every request. This prevents authenticated users from seeing
|
||||
* locally cached pages.
|
||||
*
|
||||
* Also give each page a unique ETag. This will force clients to include both
|
||||
* an If-Modified-Since header and an If-None-Match header when doing
|
||||
* conditional requests for the page (required by RFC 2616, section 13.3.4),
|
||||
* making the validation more robust. This is a workaround for a bug in Mozilla
|
||||
* Firefox that is triggered when Drupal's caching is enabled and the user
|
||||
* accesses Drupal via an HTTP proxy (see
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an authenticated
|
||||
* user requests a page, and then logs out and requests the same page again,
|
||||
* Firefox may send a conditional request based on the page that was cached
|
||||
* locally when the user was logged in. If this page did not have an ETag
|
||||
* header, the request only contains an If-Modified-Since header. The date will
|
||||
* be recent, because with authenticated users the Last-Modified header always
|
||||
* refers to the time of the request. If the user accesses Drupal via a proxy
|
||||
* server, and the proxy already has a cached copy of the anonymous page with an
|
||||
* older Last-Modified date, the proxy may respond with 304 Not Modified, making
|
||||
* the client think that the anonymous and authenticated pageviews are
|
||||
* identical.
|
||||
* ETag and Last-Modified headers are not set per default for authenticated
|
||||
* users so that browsers do not send If-Modified-Since headers from
|
||||
* authenticated user pages. drupal_serve_page_from_cache() will set appropriate
|
||||
* ETag and Last-Modified headers for cached pages.
|
||||
*
|
||||
* @see drupal_page_set_cache()
|
||||
*/
|
||||
@ -1254,9 +1261,7 @@ function drupal_page_header() {
|
||||
|
||||
$default_headers = array(
|
||||
'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME),
|
||||
'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
|
||||
'ETag' => '"' . REQUEST_TIME . '"',
|
||||
);
|
||||
drupal_send_headers($default_headers);
|
||||
}
|
||||
@ -1274,7 +1279,7 @@ function drupal_page_header() {
|
||||
*/
|
||||
function drupal_serve_page_from_cache(stdClass $cache) {
|
||||
// Negotiate whether to use compression.
|
||||
$page_compression = variable_get('page_compression', TRUE) && extension_loaded('zlib');
|
||||
$page_compression = !empty($cache->data['page_compressed']);
|
||||
$return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE;
|
||||
|
||||
// Get headers set in hook_boot(). Keys are lower-case.
|
||||
@ -1324,7 +1329,7 @@ function drupal_serve_page_from_cache(stdClass $cache) {
|
||||
drupal_add_http_header($name, $value);
|
||||
}
|
||||
|
||||
$default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created);
|
||||
$default_headers['Last-Modified'] = gmdate(DATE_RFC7231, $cache->created);
|
||||
|
||||
// HTTP/1.0 proxies does not support the Vary header, so prevent any caching
|
||||
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
|
||||
@ -1405,6 +1410,7 @@ function drupal_unpack($obj, $field = 'data') {
|
||||
* more information, including recommendations on how to break up or not
|
||||
* break up strings for translation.
|
||||
*
|
||||
* @section sec_translating_vars Translating Variables
|
||||
* You should never use t() to translate variables, such as calling
|
||||
* @code t($text); @endcode, unless the text that the variable holds has been
|
||||
* passed through t() elsewhere (e.g., $text is one of several translated
|
||||
@ -1420,9 +1426,11 @@ function drupal_unpack($obj, $field = 'data') {
|
||||
* Basically, you can put variables like @name into your string, and t() will
|
||||
* substitute their sanitized values at translation time. (See the
|
||||
* Localization API pages referenced above and the documentation of
|
||||
* format_string() for details.) Translators can then rearrange the string as
|
||||
* necessary for the language (e.g., in Spanish, it might be "blog de @name").
|
||||
* format_string() for details about how to define variables in your string.)
|
||||
* Translators can then rearrange the string as necessary for the language
|
||||
* (e.g., in Spanish, it might be "blog de @name").
|
||||
*
|
||||
* @section sec_alt_funcs_install Use During Installation Phase
|
||||
* During the Drupal installation phase, some resources used by t() wil not be
|
||||
* available to code that needs localization. See st() and get_t() for
|
||||
* alternatives.
|
||||
@ -1484,21 +1492,34 @@ function t($string, array $args = array(), array $options = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders with sanitized values in a string.
|
||||
* Formats a string for HTML display by replacing variable placeholders.
|
||||
*
|
||||
* This function replaces variable placeholders in a string with the requested
|
||||
* values and escapes the values so they can be safely displayed as HTML. It
|
||||
* should be used on any unknown text that is intended to be printed to an HTML
|
||||
* page (especially text that may have come from untrusted users, since in that
|
||||
* case it prevents cross-site scripting and other security problems).
|
||||
*
|
||||
* In most cases, you should use t() rather than calling this function
|
||||
* directly, since it will translate the text (on non-English-only sites) in
|
||||
* addition to formatting it.
|
||||
*
|
||||
* @param $string
|
||||
* A string containing placeholders.
|
||||
* @param $args
|
||||
* An associative array of replacements to make. Occurrences in $string of
|
||||
* any key in $args are replaced with the corresponding value, after
|
||||
* sanitization. The sanitization function depends on the first character of
|
||||
* the key:
|
||||
* - !variable: Inserted as is. Use this for text that has already been
|
||||
* sanitized.
|
||||
* - @variable: Escaped to HTML using check_plain(). Use this for anything
|
||||
* displayed on a page on the site.
|
||||
* - %variable: Escaped as a placeholder for user-submitted content using
|
||||
* drupal_placeholder(), which shows up as <em>emphasized</em> text.
|
||||
* any key in $args are replaced with the corresponding value, after optional
|
||||
* sanitization and formatting. The type of sanitization and formatting
|
||||
* depends on the first character of the key:
|
||||
* - @variable: Escaped to HTML using check_plain(). Use this as the default
|
||||
* choice for anything displayed on a page on the site.
|
||||
* - %variable: Escaped to HTML and formatted using drupal_placeholder(),
|
||||
* which makes it display as <em>emphasized</em> text.
|
||||
* - !variable: Inserted as is, with no sanitization or formatting. Only use
|
||||
* this for text that has already been prepared for HTML display (for
|
||||
* example, user-supplied text that has already been run through
|
||||
* check_plain() previously, or is expected to contain some limited HTML
|
||||
* tags and has already been run through filter_xss() previously).
|
||||
*
|
||||
* @see t()
|
||||
* @ingroup sanitization
|
||||
@ -1531,12 +1552,13 @@ function format_string($string, array $args = array()) {
|
||||
* Also validates strings as UTF-8 to prevent cross site scripting attacks on
|
||||
* Internet Explorer 6.
|
||||
*
|
||||
* @param $text
|
||||
* @param string $text
|
||||
* The text to be checked or processed.
|
||||
*
|
||||
* @return
|
||||
* An HTML safe version of $text, or an empty string if $text is not
|
||||
* valid UTF-8.
|
||||
* @return string
|
||||
* An HTML safe version of $text. If $text is not valid UTF-8, an empty string
|
||||
* is returned and, on PHP < 5.4, a warning may be issued depending on server
|
||||
* configuration (see @link https://bugs.php.net/bug.php?id=47494 @endlink).
|
||||
*
|
||||
* @see drupal_validate_utf8()
|
||||
* @ingroup sanitization
|
||||
@ -1621,14 +1643,14 @@ function request_uri() {
|
||||
* information about the passed-in exception is used.
|
||||
* @param $variables
|
||||
* Array of variables to replace in the message on display. Defaults to the
|
||||
* return value of drupal_decode_exception().
|
||||
* return value of _drupal_decode_exception().
|
||||
* @param $severity
|
||||
* The severity of the message, as per RFC 3164.
|
||||
* @param $link
|
||||
* A link to associate with the message.
|
||||
*
|
||||
* @see watchdog()
|
||||
* @see drupal_decode_exception()
|
||||
* @see _drupal_decode_exception()
|
||||
*/
|
||||
function watchdog_exception($type, Exception $exception, $message = NULL, $variables = array(), $severity = WATCHDOG_ERROR, $link = NULL) {
|
||||
|
||||
@ -1912,6 +1934,33 @@ function drupal_block_denied($ip) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL-safe, base64 encoded string of highly randomized bytes (over the full 8-bit range).
|
||||
*
|
||||
* @param $byte_count
|
||||
* The number of random bytes to fetch and base64 encode.
|
||||
*
|
||||
* @return string
|
||||
* The base64 encoded result will have a length of up to 4 * $byte_count.
|
||||
*/
|
||||
function drupal_random_key($byte_count = 32) {
|
||||
return drupal_base64_encode(drupal_random_bytes($byte_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL-safe, base64 encoded version of the supplied string.
|
||||
*
|
||||
* @param $string
|
||||
* The string to convert to base64.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function drupal_base64_encode($string) {
|
||||
$data = base64_encode($string);
|
||||
// Modify the output so it's safe to use in URLs.
|
||||
return strtr($data, array('+' => '-', '/' => '_', '=' => ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of highly randomized bytes (over the full 8-bit range).
|
||||
*
|
||||
@ -1925,38 +1974,34 @@ function drupal_block_denied($ip) {
|
||||
*/
|
||||
function drupal_random_bytes($count) {
|
||||
// $random_state does not use drupal_static as it stores random bytes.
|
||||
static $random_state, $bytes, $php_compatible;
|
||||
// Initialize on the first call. The contents of $_SERVER includes a mix of
|
||||
// user-specific and system information that varies a little with each page.
|
||||
if (!isset($random_state)) {
|
||||
$random_state = print_r($_SERVER, TRUE);
|
||||
if (function_exists('getmypid')) {
|
||||
// Further initialize with the somewhat random PHP process ID.
|
||||
$random_state .= getmypid();
|
||||
}
|
||||
$bytes = '';
|
||||
}
|
||||
if (strlen($bytes) < $count) {
|
||||
static $random_state, $bytes, $has_openssl;
|
||||
|
||||
$missing_bytes = $count - strlen($bytes);
|
||||
|
||||
if ($missing_bytes > 0) {
|
||||
// PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
|
||||
// locking on Windows and rendered it unusable.
|
||||
if (!isset($php_compatible)) {
|
||||
$php_compatible = version_compare(PHP_VERSION, '5.3.4', '>=');
|
||||
if (!isset($has_openssl)) {
|
||||
$has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
|
||||
}
|
||||
// /dev/urandom is available on many *nix systems and is considered the
|
||||
// best commonly available pseudo-random source.
|
||||
if ($fh = @fopen('/dev/urandom', 'rb')) {
|
||||
|
||||
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
|
||||
// way.
|
||||
if ($has_openssl) {
|
||||
$bytes .= openssl_random_pseudo_bytes($missing_bytes);
|
||||
}
|
||||
|
||||
// Else, read directly from /dev/urandom, which is available on many *nix
|
||||
// systems and is considered cryptographically secure.
|
||||
elseif ($fh = @fopen('/dev/urandom', 'rb')) {
|
||||
// PHP only performs buffered reads, so in reality it will always read
|
||||
// at least 4096 bytes. Thus, it costs nothing extra to read and store
|
||||
// that much so as to speed any additional invocations.
|
||||
$bytes .= fread($fh, max(4096, $count));
|
||||
$bytes .= fread($fh, max(4096, $missing_bytes));
|
||||
fclose($fh);
|
||||
}
|
||||
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
|
||||
// way.
|
||||
elseif ($php_compatible && function_exists('openssl_random_pseudo_bytes')) {
|
||||
$bytes .= openssl_random_pseudo_bytes($count - strlen($bytes));
|
||||
}
|
||||
// If /dev/urandom is not available or returns no bytes, this loop will
|
||||
|
||||
// If we couldn't get enough entropy, this simple hash-based PRNG will
|
||||
// generate a good set of pseudo-random bytes on any system.
|
||||
// Note that it may be important that our $random_state is passed
|
||||
// through hash() prior to being rolled into $output, that the two hash()
|
||||
@ -1964,9 +2009,23 @@ function drupal_random_bytes($count) {
|
||||
// the microtime() - is prepended rather than appended. This is to avoid
|
||||
// directly leaking $random_state via the $output stream, which could
|
||||
// allow for trivial prediction of further "random" numbers.
|
||||
while (strlen($bytes) < $count) {
|
||||
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
|
||||
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
|
||||
if (strlen($bytes) < $count) {
|
||||
// Initialize on the first call. The contents of $_SERVER includes a mix of
|
||||
// user-specific and system information that varies a little with each page.
|
||||
if (!isset($random_state)) {
|
||||
$random_state = print_r($_SERVER, TRUE);
|
||||
if (function_exists('getmypid')) {
|
||||
// Further initialize with the somewhat random PHP process ID.
|
||||
$random_state .= getmypid();
|
||||
}
|
||||
$bytes = '';
|
||||
}
|
||||
|
||||
do {
|
||||
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
|
||||
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
|
||||
}
|
||||
while (strlen($bytes) < $count);
|
||||
}
|
||||
}
|
||||
$output = substr($bytes, 0, $count);
|
||||
@ -1977,17 +2036,21 @@ function drupal_random_bytes($count) {
|
||||
/**
|
||||
* Calculates a base-64 encoded, URL-safe sha-256 hmac.
|
||||
*
|
||||
* @param $data
|
||||
* @param string $data
|
||||
* String to be validated with the hmac.
|
||||
* @param $key
|
||||
* @param string $key
|
||||
* A secret string key.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
|
||||
* any = padding characters removed.
|
||||
*/
|
||||
function drupal_hmac_base64($data, $key) {
|
||||
$hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
|
||||
// Casting $data and $key to strings here is necessary to avoid empty string
|
||||
// results of the hash function if they are not scalar values. As this
|
||||
// function is used in security-critical contexts like token validation it is
|
||||
// important that it never returns an empty string.
|
||||
$hmac = base64_encode(hash_hmac('sha256', (string) $data, (string) $key, TRUE));
|
||||
// Modify the hmac so it's safe to use in URLs.
|
||||
return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
|
||||
}
|
||||
@ -2088,7 +2151,7 @@ function drupal_array_merge_deep_array($arrays) {
|
||||
* @return Object - the user object.
|
||||
*/
|
||||
function drupal_anonymous_user() {
|
||||
$user = new stdClass();
|
||||
$user = variable_get('drupal_anonymous_user_object', new stdClass);
|
||||
$user->uid = 0;
|
||||
$user->hostname = ip_address();
|
||||
$user->roles = array();
|
||||
@ -2107,7 +2170,7 @@ function drupal_anonymous_user() {
|
||||
* drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
||||
* @endcode
|
||||
*
|
||||
* @param $phase
|
||||
* @param int $phase
|
||||
* A constant telling which phase to bootstrap to. When you bootstrap to a
|
||||
* particular phase, all earlier phases are run automatically. Possible
|
||||
* values:
|
||||
@ -2120,11 +2183,11 @@ function drupal_anonymous_user() {
|
||||
* - DRUPAL_BOOTSTRAP_LANGUAGE: Finds out the language of the page.
|
||||
* - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
|
||||
* data.
|
||||
* @param $new_phase
|
||||
* @param boolean $new_phase
|
||||
* A boolean, set to FALSE if calling drupal_bootstrap from inside a
|
||||
* function called from drupal_bootstrap (recursion).
|
||||
*
|
||||
* @return
|
||||
* @return int
|
||||
* The most recently completed phase.
|
||||
*/
|
||||
function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
|
||||
@ -2146,12 +2209,13 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
|
||||
// bootstrap state.
|
||||
static $stored_phase = -1;
|
||||
|
||||
// When not recursing, store the phase name so it's not forgotten while
|
||||
// recursing.
|
||||
if ($new_phase) {
|
||||
$final_phase = $phase;
|
||||
}
|
||||
if (isset($phase)) {
|
||||
// When not recursing, store the phase name so it's not forgotten while
|
||||
// recursing but take care of not going backwards.
|
||||
if ($new_phase && $phase >= $stored_phase) {
|
||||
$final_phase = $phase;
|
||||
}
|
||||
|
||||
// Call a phase if it has not been called before and is below the requested
|
||||
// phase.
|
||||
while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
|
||||
@ -2218,6 +2282,19 @@ function drupal_get_user_timezone() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a salt useful for hardening against SQL injection.
|
||||
*
|
||||
* @return
|
||||
* A salt based on information in settings.php, not in the database.
|
||||
*/
|
||||
function drupal_get_hash_salt() {
|
||||
global $drupal_hash_salt, $databases;
|
||||
// If the $drupal_hash_salt variable is empty, a hash of the serialized
|
||||
// database credentials is used as a fallback salt.
|
||||
return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides custom PHP error handling.
|
||||
*
|
||||
@ -2404,6 +2481,26 @@ function _drupal_bootstrap_variables() {
|
||||
// Load bootstrap modules.
|
||||
require_once DRUPAL_ROOT . '/includes/module.inc';
|
||||
module_load_all(TRUE);
|
||||
|
||||
// Sanitize the destination parameter (which is often used for redirects) to
|
||||
// prevent open redirect attacks leading to other domains. Sanitize both
|
||||
// $_GET['destination'] and $_REQUEST['destination'] to protect code that
|
||||
// relies on either, but do not sanitize $_POST to avoid interfering with
|
||||
// unrelated form submissions. The sanitization happens here because
|
||||
// url_is_external() requires the variable system to be available.
|
||||
if (isset($_GET['destination']) || isset($_REQUEST['destination'])) {
|
||||
require_once DRUPAL_ROOT . '/includes/common.inc';
|
||||
// If the destination is an external URL, remove it.
|
||||
if (isset($_GET['destination']) && url_is_external($_GET['destination'])) {
|
||||
unset($_GET['destination']);
|
||||
unset($_REQUEST['destination']);
|
||||
}
|
||||
// If there's still something in $_REQUEST['destination'] that didn't come
|
||||
// from $_GET, check it too.
|
||||
if (isset($_REQUEST['destination']) && (!isset($_GET['destination']) || $_REQUEST['destination'] != $_GET['destination']) && url_is_external($_REQUEST['destination'])) {
|
||||
unset($_REQUEST['destination']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2426,7 +2523,7 @@ function _drupal_bootstrap_page_header() {
|
||||
* @see drupal_bootstrap()
|
||||
*/
|
||||
function drupal_get_bootstrap_phase() {
|
||||
return drupal_bootstrap();
|
||||
return drupal_bootstrap(NULL, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2438,7 +2535,6 @@ function drupal_get_bootstrap_phase() {
|
||||
* HMAC and timestamp.
|
||||
*/
|
||||
function drupal_valid_test_ua() {
|
||||
global $drupal_hash_salt;
|
||||
// No reason to reset this.
|
||||
static $test_prefix;
|
||||
|
||||
@ -2452,7 +2548,7 @@ function drupal_valid_test_ua() {
|
||||
// We use the salt from settings.php to make the HMAC key, since
|
||||
// the database is not yet initialized and we can't access any Drupal variables.
|
||||
// The file properties add more entropy not easily accessible to others.
|
||||
$key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
|
||||
$key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
|
||||
$time_diff = REQUEST_TIME - $time;
|
||||
// Since we are making a local request a 5 second time window is allowed,
|
||||
// and the HMAC must match.
|
||||
@ -2470,14 +2566,13 @@ function drupal_valid_test_ua() {
|
||||
* Generates a user agent string with a HMAC and timestamp for simpletest.
|
||||
*/
|
||||
function drupal_generate_test_ua($prefix) {
|
||||
global $drupal_hash_salt;
|
||||
static $key;
|
||||
|
||||
if (!isset($key)) {
|
||||
// We use the salt from settings.php to make the HMAC key, since
|
||||
// the database is not yet initialized and we can't access any Drupal variables.
|
||||
// The file properties add more entropy not easily accessible to others.
|
||||
$key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
|
||||
$key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
|
||||
}
|
||||
// Generate a moderately secure HMAC based on the database credentials.
|
||||
$salt = uniqid('', TRUE);
|
||||
@ -2542,7 +2637,7 @@ function drupal_installation_attempted() {
|
||||
*
|
||||
* This would include implementations of hook_install(), which could run
|
||||
* during the Drupal installation phase, and might also be run during
|
||||
* non-installation time, such as while installing the module from the the
|
||||
* non-installation time, such as while installing the module from the
|
||||
* module administration page.
|
||||
*
|
||||
* Example usage:
|
||||
@ -3071,10 +3166,13 @@ function _registry_check_code($type, $name = NULL) {
|
||||
// This function may get called when the default database is not active, but
|
||||
// there is no reason we'd ever want to not use the default database for
|
||||
// this query.
|
||||
$file = Database::getConnection('default', 'default')->query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array(
|
||||
':name' => $name,
|
||||
':type' => $type,
|
||||
))
|
||||
$file = Database::getConnection('default', 'default')
|
||||
->select('registry', 'r', array('target' => 'default'))
|
||||
->fields('r', array('filename'))
|
||||
// Use LIKE here to make the query case-insensitive.
|
||||
->condition('r.name', db_like($name), 'LIKE')
|
||||
->condition('r.type', $type)
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// Flag that we've run a lookup query and need to update the cache.
|
||||
@ -3222,8 +3320,8 @@ function registry_update() {
|
||||
* However, the above line of code does not work, because PHP only allows static
|
||||
* variables to be initializied by literal values, and does not allow static
|
||||
* variables to be assigned to references.
|
||||
* - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static
|
||||
* - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.references
|
||||
* - http://php.net/manual/language.variables.scope.php#language.variables.scope.static
|
||||
* - http://php.net/manual/language.variables.scope.php#language.variables.scope.references
|
||||
* The example below shows the syntax needed to work around both limitations.
|
||||
* For benchmarks and more information, see http://drupal.org/node/619666.
|
||||
*
|
||||
@ -3248,11 +3346,9 @@ function registry_update() {
|
||||
* @param $default_value
|
||||
* Optional default value.
|
||||
* @param $reset
|
||||
* TRUE to reset a specific named variable, or all variables if $name is NULL.
|
||||
* Resetting every variable should only be used, for example, for running
|
||||
* unit tests with a clean environment. Should be used only though via
|
||||
* function drupal_static_reset() and the return value should not be used in
|
||||
* this case.
|
||||
* TRUE to reset one or all variables(s). This parameter is only used
|
||||
* internally and should not be passed in; use drupal_static_reset() instead.
|
||||
* (This function's return value should not be used when TRUE is passed in.)
|
||||
*
|
||||
* @return
|
||||
* Returns a variable by reference.
|
||||
@ -3297,6 +3393,8 @@ function &drupal_static($name, $default_value = NULL, $reset = FALSE) {
|
||||
*
|
||||
* @param $name
|
||||
* Name of the static variable to reset. Omit to reset all variables.
|
||||
* Resetting all variables should only be used, for example, for running unit
|
||||
* tests with a clean environment.
|
||||
*/
|
||||
function drupal_static_reset($name = NULL) {
|
||||
drupal_static($name, NULL, TRUE);
|
||||
@ -3383,3 +3481,63 @@ function _drupal_shutdown_function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the memory required for an operation to the available memory.
|
||||
*
|
||||
* @param $required
|
||||
* The memory required for the operation, expressed as a number of bytes with
|
||||
* optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8bytes,
|
||||
* 9mbytes).
|
||||
* @param $memory_limit
|
||||
* (optional) The memory limit for the operation, expressed as a number of
|
||||
* bytes with optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G,
|
||||
* 6GiB, 8bytes, 9mbytes). If no value is passed, the current PHP
|
||||
* memory_limit will be used. Defaults to NULL.
|
||||
*
|
||||
* @return
|
||||
* TRUE if there is sufficient memory to allow the operation, or FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
function drupal_check_memory_limit($required, $memory_limit = NULL) {
|
||||
if (!isset($memory_limit)) {
|
||||
$memory_limit = ini_get('memory_limit');
|
||||
}
|
||||
|
||||
// There is sufficient memory if:
|
||||
// - No memory limit is set.
|
||||
// - The memory limit is set to unlimited (-1).
|
||||
// - The memory limit is greater than the memory required for the operation.
|
||||
return ((!$memory_limit) || ($memory_limit == -1) || (parse_size($memory_limit) >= parse_size($required)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates a PHP file from any active opcode caches.
|
||||
*
|
||||
* If the opcode cache does not support the invalidation of individual files,
|
||||
* the entire cache will be flushed.
|
||||
*
|
||||
* @param string $filepath
|
||||
* The absolute path of the PHP file to invalidate.
|
||||
*/
|
||||
function drupal_clear_opcode_cache($filepath) {
|
||||
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
|
||||
// Below PHP 5.3, clearstatcache does not accept any function parameters.
|
||||
clearstatcache();
|
||||
}
|
||||
else {
|
||||
clearstatcache(TRUE, $filepath);
|
||||
}
|
||||
|
||||
// Zend OPcache.
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($filepath, TRUE);
|
||||
}
|
||||
// APC.
|
||||
if (function_exists('apc_delete_file')) {
|
||||
// apc_delete_file() throws a PHP warning in case the specified file was
|
||||
// not compiled yet.
|
||||
// @see http://php.net/apc-delete-file
|
||||
@apc_delete_file($filepath);
|
||||
}
|
||||
}
|
||||
|
@ -80,43 +80,15 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
|
||||
* same name. Other implementations might want to store several bins in data
|
||||
* structures that get flushed together. While it is not a problem for most
|
||||
* cache bins if the entries in them are flushed before their expire time, some
|
||||
* might break functionality or are extremely expensive to recalculate. These
|
||||
* will be marked with a (*). The other bins expired automatically by core.
|
||||
* Contributed modules can add additional bins and get them expired
|
||||
* automatically by implementing hook_flush_caches().
|
||||
*
|
||||
* - cache: Generic cache storage bin (used for variables, theme registry,
|
||||
* locale date, list of simpletest tests etc).
|
||||
*
|
||||
* - cache_block: Stores the content of various blocks.
|
||||
*
|
||||
* - cache field: Stores the field data belonging to a given object.
|
||||
*
|
||||
* - cache_filter: Stores filtered pieces of content.
|
||||
*
|
||||
* - cache_form(*): Stores multistep forms. Flushing this bin means that some
|
||||
* forms displayed to users lose their state and the data already submitted
|
||||
* to them.
|
||||
*
|
||||
* - cache_menu: Stores the structure of visible navigation menus per page.
|
||||
*
|
||||
* - cache_page: Stores generated pages for anonymous users. It is flushed
|
||||
* very often, whenever a page changes, at least for every ode and comment
|
||||
* submission. This is the only bin affected by the page cache setting on
|
||||
* the administrator panel.
|
||||
*
|
||||
* - cache path: Stores the system paths that have an alias.
|
||||
*
|
||||
* - cache update(*): Stores available releases. The update server (for
|
||||
* example, drupal.org) needs to produce the relevant XML for every project
|
||||
* installed on the current site. As this is different for (almost) every
|
||||
* site, it's very expensive to recalculate for the update server.
|
||||
* might break functionality or are extremely expensive to recalculate. The
|
||||
* other bins are expired automatically by core. Contributed modules can add
|
||||
* additional bins and get them expired automatically by implementing
|
||||
* hook_flush_caches().
|
||||
*
|
||||
* The reasons for having several bins are as follows:
|
||||
*
|
||||
* - smaller bins mean smaller database tables and allow for faster selects and
|
||||
* inserts
|
||||
* - we try to put fast changing cache items and rather static ones into
|
||||
* - Smaller bins mean smaller database tables and allow for faster selects and
|
||||
* inserts.
|
||||
* - We try to put fast changing cache items and rather static ones into
|
||||
* different bins. The effect is that only the fast changing bins will need a
|
||||
* lot of writes to disk. The more static bins will also be better cacheable
|
||||
* with MySQL's query cache.
|
||||
@ -125,15 +97,31 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
|
||||
* The cache ID of the data to store.
|
||||
* @param $data
|
||||
* The data to store in the cache. Complex data types will be automatically
|
||||
* serialized before insertion.
|
||||
* Strings will be stored as plain text and not serialized.
|
||||
* serialized before insertion. Strings will be stored as plain text and are
|
||||
* not serialized. Some storage engines only allow objects up to a maximum of
|
||||
* 1MB in size to be stored by default. When caching large arrays or similar,
|
||||
* take care to ensure $data does not exceed this size.
|
||||
* @param $bin
|
||||
* The cache bin to store the data in. Valid core values are 'cache_block',
|
||||
* 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
|
||||
* 'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default
|
||||
* cache.
|
||||
* (optional) The cache bin to store the data in. Valid core values are:
|
||||
* - cache: (default) Generic cache storage bin (used for theme registry,
|
||||
* locale date, list of simpletest tests, etc.).
|
||||
* - cache_block: Stores the content of various blocks.
|
||||
* - cache_bootstrap: Stores the class registry, the system list of modules,
|
||||
* the list of which modules implement which hooks, and the Drupal variable
|
||||
* list.
|
||||
* - cache_field: Stores the field data belonging to a given object.
|
||||
* - cache_filter: Stores filtered pieces of content.
|
||||
* - cache_form: Stores multistep forms. Flushing this bin means that some
|
||||
* forms displayed to users lose their state and the data already submitted
|
||||
* to them. This bin should not be flushed before its expired time.
|
||||
* - cache_menu: Stores the structure of visible navigation menus per page.
|
||||
* - cache_page: Stores generated pages for anonymous users. It is flushed
|
||||
* very often, whenever a page changes, at least for every node and comment
|
||||
* submission. This is the only bin affected by the page cache setting on
|
||||
* the administrator panel.
|
||||
* - cache_path: Stores the system paths that have an alias.
|
||||
* @param $expire
|
||||
* One of the following values:
|
||||
* (optional) One of the following values:
|
||||
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
|
||||
* explicitly told to using cache_clear_all() with a cache ID.
|
||||
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
|
||||
@ -141,6 +129,7 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
|
||||
* - A Unix timestamp: Indicates that the item should be kept at least until
|
||||
* the given time, after which it behaves like CACHE_TEMPORARY.
|
||||
*
|
||||
* @see _update_cache_set()
|
||||
* @see cache_get()
|
||||
*/
|
||||
function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
|
||||
@ -150,18 +139,20 @@ function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
|
||||
/**
|
||||
* Expires data from the cache.
|
||||
*
|
||||
* If called without arguments, expirable entries will be cleared from the
|
||||
* cache_page and cache_block bins.
|
||||
* If called with the arguments $cid and $bin set to NULL or omitted, then
|
||||
* expirable entries will be cleared from the cache_page and cache_block bins,
|
||||
* and the $wildcard argument is ignored.
|
||||
*
|
||||
* @param $cid
|
||||
* If set, the cache ID to delete. Otherwise, all cache entries that can
|
||||
* expire are deleted.
|
||||
* If set, the cache ID or an array of cache IDs. Otherwise, all cache entries
|
||||
* that can expire are deleted. The $wildcard argument will be ignored if set
|
||||
* to NULL.
|
||||
* @param $bin
|
||||
* If set, the cache bin to delete from. Mandatory argument if $cid is set.
|
||||
* @param $wildcard
|
||||
* If TRUE, cache IDs starting with $cid are deleted in addition to the
|
||||
* exact cache ID specified by $cid. If $wildcard is TRUE and $cid is '*',
|
||||
* the entire cache bin is emptied.
|
||||
* If TRUE, the $cid argument must contain a string value and cache IDs
|
||||
* starting with $cid are deleted in addition to the exact cache ID specified
|
||||
* by $cid. If $wildcard is TRUE and $cid is '*', the entire cache is emptied.
|
||||
*/
|
||||
function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
|
||||
if (!isset($cid) && !isset($bin)) {
|
||||
@ -230,13 +221,6 @@ function cache_is_empty($bin) {
|
||||
* @see DrupalDatabaseCache
|
||||
*/
|
||||
interface DrupalCacheInterface {
|
||||
/**
|
||||
* Constructs a new cache interface.
|
||||
*
|
||||
* @param $bin
|
||||
* The cache bin for which the object is created.
|
||||
*/
|
||||
function __construct($bin);
|
||||
|
||||
/**
|
||||
* Returns data from the persistent cache.
|
||||
@ -272,10 +256,12 @@ interface DrupalCacheInterface {
|
||||
* The cache ID of the data to store.
|
||||
* @param $data
|
||||
* The data to store in the cache. Complex data types will be automatically
|
||||
* serialized before insertion.
|
||||
* Strings will be stored as plain text and not serialized.
|
||||
* serialized before insertion. Strings will be stored as plain text and not
|
||||
* serialized. Some storage engines only allow objects up to a maximum of
|
||||
* 1MB in size to be stored by default. When caching large arrays or
|
||||
* similar, take care to ensure $data does not exceed this size.
|
||||
* @param $expire
|
||||
* One of the following values:
|
||||
* (optional) One of the following values:
|
||||
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
|
||||
* explicitly told to using cache_clear_all() with a cache ID.
|
||||
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
|
||||
@ -293,12 +279,14 @@ interface DrupalCacheInterface {
|
||||
* cache_page and cache_block bins.
|
||||
*
|
||||
* @param $cid
|
||||
* If set, the cache ID to delete. Otherwise, all cache entries that can
|
||||
* expire are deleted.
|
||||
* If set, the cache ID or an array of cache IDs. Otherwise, all cache
|
||||
* entries that can expire are deleted. The $wildcard argument will be
|
||||
* ignored if set to NULL.
|
||||
* @param $wildcard
|
||||
* If set to TRUE, the $cid is treated as a substring
|
||||
* to match rather than a complete ID. The match is a right hand
|
||||
* match. If '*' is given as $cid, the bin $bin will be emptied.
|
||||
* If TRUE, the $cid argument must contain a string value and cache IDs
|
||||
* starting with $cid are deleted in addition to the exact cache ID
|
||||
* specified by $cid. If $wildcard is TRUE and $cid is '*', the entire
|
||||
* cache is emptied.
|
||||
*/
|
||||
function clear($cid = NULL, $wildcard = FALSE);
|
||||
|
||||
@ -324,7 +312,10 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
||||
protected $bin;
|
||||
|
||||
/**
|
||||
* Constructs a new DrupalDatabaseCache object.
|
||||
* Constructs a DrupalDatabaseCache object.
|
||||
*
|
||||
* @param $bin
|
||||
* The cache bin for which the object is created.
|
||||
*/
|
||||
function __construct($bin) {
|
||||
$this->bin = $bin;
|
||||
@ -518,7 +509,16 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
||||
else {
|
||||
if ($wildcard) {
|
||||
if ($cid == '*') {
|
||||
db_truncate($this->bin)->execute();
|
||||
// Check if $this->bin is a cache table before truncating. Other
|
||||
// cache_clear_all() operations throw a PDO error in this situation,
|
||||
// so we don't need to verify them first. This ensures that non-cache
|
||||
// tables cannot be truncated accidentally.
|
||||
if ($this->isValidBin()) {
|
||||
db_truncate($this->bin)->execute();
|
||||
}
|
||||
else {
|
||||
throw new Exception(t('Invalid or missing cache bin specified: %bin', array('%bin' => $this->bin)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
db_delete($this->bin)
|
||||
@ -555,4 +555,25 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
|
||||
->fetchField();
|
||||
return empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if $this->bin represents a valid cache table.
|
||||
*
|
||||
* This check is required to ensure that non-cache tables are not truncated
|
||||
* accidentally when calling cache_clear_all().
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function isValidBin() {
|
||||
if ($this->bin == 'cache' || substr($this->bin, 0, 6) == 'cache_') {
|
||||
// Skip schema check for bins with standard table names.
|
||||
return TRUE;
|
||||
}
|
||||
// These fields are required for any cache table.
|
||||
$fields = array('cid', 'data', 'expire', 'created', 'serialized');
|
||||
// Load the table schema.
|
||||
$schema = drupal_get_schema($this->bin);
|
||||
// Confirm that all fields are present.
|
||||
return isset($schema['fields']) && !array_diff($fields, array_keys($schema['fields']));
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ function drupal_get_rdf_namespaces() {
|
||||
/**
|
||||
* Adds output to the HEAD tag of the HTML page.
|
||||
*
|
||||
* This function can be called as long the headers aren't sent. Pass no
|
||||
* 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
|
||||
@ -458,7 +458,7 @@ function drupal_get_query_array($query) {
|
||||
$result = array();
|
||||
if (!empty($query)) {
|
||||
foreach (explode('&', $query) as $param) {
|
||||
$param = explode('=', $param);
|
||||
$param = explode('=', $param, 2);
|
||||
$result[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
|
||||
}
|
||||
}
|
||||
@ -544,37 +544,32 @@ function drupal_get_destination() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a system URL string into an associative array suitable for url().
|
||||
* Parses a URL string into its path, query, and fragment components.
|
||||
*
|
||||
* 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.
|
||||
* This function splits both internal paths like @code node?b=c#d @endcode and
|
||||
* external URLs like @code https://example.com/a?b=c#d @endcode into their
|
||||
* component parts. See
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-3 RFC 3986 @endlink for an
|
||||
* explanation of what the component parts are.
|
||||
*
|
||||
* 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
|
||||
* Note that, unlike the RFC, when passed an external URL, this function
|
||||
* groups the scheme, authority, and path together into the path component.
|
||||
*
|
||||
* 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 string $url
|
||||
* The internal path or external URL string to parse.
|
||||
*
|
||||
* @param $url
|
||||
* The URL string to parse, f.e. $_GET['destination'].
|
||||
* @return array
|
||||
* An associative array containing:
|
||||
* - path: The path component of $url. If $url is an external URL, this
|
||||
* includes the scheme, authority, and path.
|
||||
* - query: An array of query parameters from $url, if they exist.
|
||||
* - fragment: The fragment component from $url, if it exists.
|
||||
*
|
||||
* @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()
|
||||
* @see drupal_goto()
|
||||
* @see l()
|
||||
* @see url()
|
||||
* @see http://tools.ietf.org/html/rfc3986
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
function drupal_parse_url($url) {
|
||||
@ -641,7 +636,7 @@ function drupal_encode_path($path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the user to a different Drupal page.
|
||||
* Sends the user to a different page.
|
||||
*
|
||||
* This issues an on-site HTTP redirect. The function makes sure the redirected
|
||||
* URL is formatted correctly.
|
||||
@ -785,6 +780,13 @@ function drupal_access_denied() {
|
||||
* - data: A string containing the response body that was received.
|
||||
*/
|
||||
function drupal_http_request($url, array $options = array()) {
|
||||
// Allow an alternate HTTP client library to replace Drupal's default
|
||||
// implementation.
|
||||
$override_function = variable_get('drupal_http_request_function', FALSE);
|
||||
if (!empty($override_function) && function_exists($override_function)) {
|
||||
return $override_function($url, $options);
|
||||
}
|
||||
|
||||
$result = new stdClass();
|
||||
|
||||
// Parse the URL and make sure we can handle the schema.
|
||||
@ -922,7 +924,7 @@ function drupal_http_request($url, array $options = array()) {
|
||||
|
||||
// If the server URL has a user then attempt to use basic authentication.
|
||||
if (isset($uri['user'])) {
|
||||
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ''));
|
||||
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':'));
|
||||
}
|
||||
|
||||
// If the database prefix is being used by SimpleTest to run the tests in a copied
|
||||
@ -983,9 +985,10 @@ function drupal_http_request($url, array $options = array()) {
|
||||
$response = preg_split("/\r\n|\n|\r/", $response);
|
||||
|
||||
// Parse the response status line.
|
||||
list($protocol, $code, $status_message) = explode(' ', trim(array_shift($response)), 3);
|
||||
$result->protocol = $protocol;
|
||||
$result->status_message = $status_message;
|
||||
$response_status_array = _drupal_parse_response_status(trim(array_shift($response)));
|
||||
$result->protocol = $response_status_array['http_version'];
|
||||
$result->status_message = $response_status_array['reason_phrase'];
|
||||
$code = $response_status_array['response_code'];
|
||||
|
||||
$result->headers = array();
|
||||
|
||||
@ -1076,12 +1079,43 @@ function drupal_http_request($url, array $options = array()) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$result->error = $status_message;
|
||||
$result->error = $result->status_message;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits an HTTP response status line into components.
|
||||
*
|
||||
* See the @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html status line definition @endlink
|
||||
* in RFC 2616.
|
||||
*
|
||||
* @param string $respone
|
||||
* The response status line, for example 'HTTP/1.1 500 Internal Server Error'.
|
||||
*
|
||||
* @return array
|
||||
* Keyed array containing the component parts. If the response is malformed,
|
||||
* all possible parts will be extracted. 'reason_phrase' could be empty.
|
||||
* Possible keys:
|
||||
* - 'http_version'
|
||||
* - 'response_code'
|
||||
* - 'reason_phrase'
|
||||
*/
|
||||
function _drupal_parse_response_status($response) {
|
||||
$response_array = explode(' ', trim($response), 3);
|
||||
// Set up empty values.
|
||||
$result = array(
|
||||
'reason_phrase' => '',
|
||||
);
|
||||
$result['http_version'] = $response_array[0];
|
||||
$result['response_code'] = $response_array[1];
|
||||
if (isset($response_array[2])) {
|
||||
$result['reason_phrase'] = $response_array[2];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for determining hosts excluded from needing a proxy.
|
||||
*
|
||||
@ -1127,7 +1161,7 @@ function _fix_gpc_magic(&$item) {
|
||||
* @param $key
|
||||
* The key for the item within $_FILES.
|
||||
*
|
||||
* @see http://php.net/manual/en/features.file-upload.php#42280
|
||||
* @see http://php.net/manual/features.file-upload.php#42280
|
||||
*/
|
||||
function _fix_gpc_magic_files(&$item, $key) {
|
||||
if ($key != 'tmp_name') {
|
||||
@ -1167,7 +1201,8 @@ function fix_gpc_magic() {
|
||||
/**
|
||||
* Verifies the syntax of the given e-mail address.
|
||||
*
|
||||
* See @link http://tools.ietf.org/html/rfc5321 RFC 5321 @endlink for details.
|
||||
* This uses the
|
||||
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
|
||||
*
|
||||
* @param $mail
|
||||
* A string containing an e-mail address.
|
||||
@ -1418,7 +1453,6 @@ function filter_xss_admin($string) {
|
||||
* valid UTF-8.
|
||||
*
|
||||
* @see drupal_validate_utf8()
|
||||
* @ingroup sanitization
|
||||
*/
|
||||
function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
|
||||
// Only operate on valid UTF-8 strings. This is necessary to prevent cross
|
||||
@ -1942,7 +1976,7 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) {
|
||||
* get interpreted as date format characters.
|
||||
* @param $timezone
|
||||
* (optional) Time zone identifier, as described at
|
||||
* http://php.net/manual/en/timezones.php Defaults to the time zone used to
|
||||
* 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
|
||||
@ -2078,6 +2112,9 @@ function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
|
||||
/**
|
||||
* Format a username.
|
||||
*
|
||||
* This is also the label callback implementation of
|
||||
* callback_entity_info_label() for user_entity_info().
|
||||
*
|
||||
* By default, the passed-in object's 'name' property is used if it exists, or
|
||||
* else, the site-defined value for the 'anonymous' variable. However, a module
|
||||
* may override this by implementing hook_username_alter(&$name, $account).
|
||||
@ -2177,14 +2214,20 @@ function url($path = NULL, array $options = array()) {
|
||||
'prefix' => ''
|
||||
);
|
||||
|
||||
// A duplicate of the code from url_is_external() to avoid needing another
|
||||
// function call, since performance inside url() is critical.
|
||||
if (!isset($options['external'])) {
|
||||
// Return an external link if $path contains an allowed absolute URL. Only
|
||||
// call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
|
||||
// before any / ? or #. Note: we could use url_is_external($path) here, but
|
||||
// that would require another function call, and performance inside url() is
|
||||
// critical.
|
||||
// Return an external link if $path contains an allowed absolute URL. Avoid
|
||||
// calling drupal_strip_dangerous_protocols() if there is any slash (/),
|
||||
// hash (#) or question_mark (?) before the colon (:) occurrence - if any -
|
||||
// as this would clearly mean it is not a URL. If the path starts with 2
|
||||
// slashes then it is always considered an external URL without an explicit
|
||||
// protocol part.
|
||||
$colonpos = strpos($path, ':');
|
||||
$options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path);
|
||||
$options['external'] = (strpos($path, '//') === 0)
|
||||
|| ($colonpos !== FALSE
|
||||
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
|
||||
&& drupal_strip_dangerous_protocols($path) == $path);
|
||||
}
|
||||
|
||||
// Preserve the original path before altering or aliasing.
|
||||
@ -2222,6 +2265,11 @@ function url($path = NULL, array $options = array()) {
|
||||
return $path . $options['fragment'];
|
||||
}
|
||||
|
||||
// Strip leading slashes from internal paths to prevent them becoming external
|
||||
// URLs without protocol. /example.com should not be turned into
|
||||
// //example.com.
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
global $base_url, $base_secure_url, $base_insecure_url;
|
||||
|
||||
// The base_url might be rewritten from the language rewrite in domain mode.
|
||||
@ -2299,10 +2347,15 @@ function url($path = NULL, array $options = array()) {
|
||||
*/
|
||||
function url_is_external($path) {
|
||||
$colonpos = strpos($path, ':');
|
||||
// Avoid calling drupal_strip_dangerous_protocols() if there is any
|
||||
// slash (/), hash (#) or question_mark (?) before the colon (:)
|
||||
// occurrence - if any - as this would clearly mean it is not a URL.
|
||||
return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path;
|
||||
// Avoid calling drupal_strip_dangerous_protocols() if there is any slash (/),
|
||||
// hash (#) or question_mark (?) before the colon (:) occurrence - if any - as
|
||||
// this would clearly mean it is not a URL. If the path starts with 2 slashes
|
||||
// then it is always considered an external URL without an explicit protocol
|
||||
// part.
|
||||
return (strpos($path, '//') === 0)
|
||||
|| ($colonpos !== FALSE
|
||||
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
|
||||
&& drupal_strip_dangerous_protocols($path) == $path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2379,6 +2432,14 @@ function drupal_attributes(array $attributes = array()) {
|
||||
* 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 <a href="@url">settings</a> page', array('@url' => url('admin')));
|
||||
* @endcode
|
||||
* This keeps the context of the link title ('settings' in the example) for
|
||||
* translators.
|
||||
*
|
||||
* @param string $text
|
||||
* The translated link text for the anchor tag.
|
||||
* @param string $path
|
||||
@ -2591,7 +2652,10 @@ function drupal_deliver_html_page($page_callback_result) {
|
||||
|
||||
// Keep old path for reference, and to allow forms to redirect to it.
|
||||
if (!isset($_GET['destination'])) {
|
||||
$_GET['destination'] = $_GET['q'];
|
||||
// Make sure that the current path is not interpreted as external URL.
|
||||
if (!url_is_external($_GET['q'])) {
|
||||
$_GET['destination'] = $_GET['q'];
|
||||
}
|
||||
}
|
||||
|
||||
$path = drupal_get_normal_path(variable_get('site_404', ''));
|
||||
@ -2620,7 +2684,10 @@ function drupal_deliver_html_page($page_callback_result) {
|
||||
|
||||
// Keep old path for reference, and to allow forms to redirect to it.
|
||||
if (!isset($_GET['destination'])) {
|
||||
$_GET['destination'] = $_GET['q'];
|
||||
// Make sure that the current path is not interpreted as external URL.
|
||||
if (!url_is_external($_GET['q'])) {
|
||||
$_GET['destination'] = $_GET['q'];
|
||||
}
|
||||
}
|
||||
|
||||
$path = drupal_get_normal_path(variable_get('site_403', ''));
|
||||
@ -2779,7 +2846,7 @@ function drupal_set_time_limit($time_limit) {
|
||||
* The name of the item for which the path is requested.
|
||||
*
|
||||
* @return
|
||||
* The path to the requested item.
|
||||
* The path to the requested item or an empty string if the item is not found.
|
||||
*/
|
||||
function drupal_get_path($type, $name) {
|
||||
return dirname(drupal_get_filename($type, $name));
|
||||
@ -3429,7 +3496,11 @@ function drupal_pre_render_styles($elements) {
|
||||
$import_batch = array_slice($import, 0, 31);
|
||||
$import = array_slice($import, 31);
|
||||
$element = $style_element_defaults;
|
||||
$element['#value'] = implode("\n", $import_batch);
|
||||
// This simplifies the JavaScript regex, allowing each line
|
||||
// (separated by \n) to be treated as a completely different string.
|
||||
// This means that we can use ^ and $ on one line at a time, and not
|
||||
// worry about style tags since they'll never match the regex.
|
||||
$element['#value'] = "\n" . implode("\n", $import_batch) . "\n";
|
||||
$element['#attributes']['media'] = $group['media'];
|
||||
$element['#browsers'] = $group['browsers'];
|
||||
$elements[] = $element;
|
||||
@ -3654,17 +3725,23 @@ function drupal_load_stylesheet($file, $optimize = NULL, $reset_basepath = TRUE)
|
||||
if ($basepath && !file_uri_scheme($file)) {
|
||||
$file = $basepath . '/' . $file;
|
||||
}
|
||||
// Store the parent base path to restore it later.
|
||||
$parent_base_path = $basepath;
|
||||
// Set the current base path to process possible child imports.
|
||||
$basepath = dirname($file);
|
||||
|
||||
// Load the CSS stylesheet. We suppress errors because themes may specify
|
||||
// stylesheets in their .info file that don't exist in the theme's path,
|
||||
// but are merely there to disable certain module CSS files.
|
||||
$content = '';
|
||||
if ($contents = @file_get_contents($file)) {
|
||||
// Return the processed stylesheet.
|
||||
return drupal_load_stylesheet_content($contents, $_optimize);
|
||||
$content = drupal_load_stylesheet_content($contents, $_optimize);
|
||||
}
|
||||
|
||||
return '';
|
||||
// Restore the parent base path as the file and its childen are processed.
|
||||
$basepath = $parent_base_path;
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3681,7 +3758,7 @@ function drupal_load_stylesheet($file, $optimize = NULL, $reset_basepath = TRUE)
|
||||
*/
|
||||
function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
|
||||
// Remove multiple charset declarations for standards compliance (and fixing Safari problems).
|
||||
$contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
|
||||
$contents = preg_replace('/^@charset\s+[\'"](\S*?)\b[\'"];/i', '', $contents);
|
||||
|
||||
if ($optimize) {
|
||||
// Perform some safe CSS optimizations.
|
||||
@ -3700,7 +3777,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
|
||||
// Remove certain whitespace.
|
||||
// There are different conditions for removing leading and trailing
|
||||
// whitespace.
|
||||
// @see http://php.net/manual/en/regexp.reference.subpatterns.php
|
||||
// @see http://php.net/manual/regexp.reference.subpatterns.php
|
||||
$contents = preg_replace('<
|
||||
# Strip leading and trailing whitespace.
|
||||
\s*([@{};,])\s*
|
||||
@ -3749,7 +3826,7 @@ function _drupal_load_stylesheet($matches) {
|
||||
// Alter all internal url() paths. Leave external paths alone. We don't need
|
||||
// to normalize absolute paths here (i.e. remove folder/... segments) because
|
||||
// that will be done later.
|
||||
return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)/i', 'url(\1'. $directory, $file);
|
||||
return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)([^\'")]+)([\'"]?)\s*\)/i', 'url(\1' . $directory . '\2\3)', $file);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3814,7 +3891,14 @@ function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_
|
||||
* The cleaned class name.
|
||||
*/
|
||||
function drupal_html_class($class) {
|
||||
return drupal_clean_css_identifier(drupal_strtolower($class));
|
||||
// The output of this function will never change, so this uses a normal
|
||||
// static instead of drupal_static().
|
||||
static $classes = array();
|
||||
|
||||
if (!isset($classes[$class])) {
|
||||
$classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
|
||||
}
|
||||
return $classes[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3869,7 +3953,16 @@ function drupal_html_id($id) {
|
||||
// requested id. $_POST['ajax_html_ids'] contains the ids as they were
|
||||
// returned by this function, potentially with the appended counter, so
|
||||
// we parse that to reconstruct the $seen_ids array.
|
||||
foreach ($_POST['ajax_html_ids'] as $seen_id) {
|
||||
if (isset($_POST['ajax_html_ids'][0]) && strpos($_POST['ajax_html_ids'][0], ',') === FALSE) {
|
||||
$ajax_html_ids = $_POST['ajax_html_ids'];
|
||||
}
|
||||
else {
|
||||
// jquery.form.js may send the server a comma-separated string as the
|
||||
// first element of an array (see http://drupal.org/node/1575060), so
|
||||
// we need to convert it to an array in that case.
|
||||
$ajax_html_ids = explode(',', $_POST['ajax_html_ids'][0]);
|
||||
}
|
||||
foreach ($ajax_html_ids as $seen_id) {
|
||||
// We rely on '--' being used solely for separating a base id from the
|
||||
// counter, which this function ensures when returning an id.
|
||||
$parts = explode('--', $seen_id, 2);
|
||||
@ -4069,7 +4162,14 @@ function drupal_region_class($region) {
|
||||
* else being the same, JavaScript added by a call to drupal_add_js() that
|
||||
* happened later in the page request gets added to the page after one for
|
||||
* which drupal_add_js() happened earlier in the page request.
|
||||
* - defer: If set to TRUE, the defer attribute is set on the <script>
|
||||
* - requires_jquery: Set this to FALSE if the JavaScript you are adding does
|
||||
* not have a dependency on jQuery. Defaults to TRUE, except for JavaScript
|
||||
* settings where it defaults to FALSE. This is used on sites that have the
|
||||
* 'javascript_always_use_jquery' variable set to FALSE; on those sites, if
|
||||
* all the JavaScript added to the page by drupal_add_js() does not have a
|
||||
* dependency on jQuery, then for improved front-end performance Drupal
|
||||
* will not add jQuery and related libraries and settings to the page.
|
||||
* - defer: If set to TRUE, the defer attribute is set on the <script>
|
||||
* tag. Defaults to FALSE.
|
||||
* - cache: If set to FALSE, the JavaScript file is loaded anew on every page
|
||||
* call; in other words, it is not cached. Used only when 'type' references
|
||||
@ -4086,6 +4186,14 @@ function drupal_region_class($region) {
|
||||
*/
|
||||
function drupal_add_js($data = NULL, $options = NULL) {
|
||||
$javascript = &drupal_static(__FUNCTION__, array());
|
||||
$jquery_added = &drupal_static(__FUNCTION__ . ':jquery_added', FALSE);
|
||||
|
||||
// If the $javascript variable has been reset with drupal_static_reset(),
|
||||
// jQuery and related files will have been removed from the list, so set the
|
||||
// variable back to FALSE to indicate they have not yet been added.
|
||||
if (empty($javascript)) {
|
||||
$jquery_added = FALSE;
|
||||
}
|
||||
|
||||
// Construct the options, taking the defaults into consideration.
|
||||
if (isset($options)) {
|
||||
@ -4096,6 +4204,9 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
||||
else {
|
||||
$options = array();
|
||||
}
|
||||
if (isset($options['type']) && $options['type'] == 'setting') {
|
||||
$options += array('requires_jquery' => FALSE);
|
||||
}
|
||||
$options += drupal_js_defaults($data);
|
||||
|
||||
// Preprocess can only be set if caching is enabled.
|
||||
@ -4106,14 +4217,18 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
||||
$options['weight'] += count($javascript) / 1000;
|
||||
|
||||
if (isset($data)) {
|
||||
// Add jquery.js and drupal.js, as well as the basePath setting, the
|
||||
// first time a JavaScript file is added.
|
||||
if (empty($javascript)) {
|
||||
// Add jquery.js, drupal.js, and related files and settings if they have
|
||||
// not been added yet. However, if the 'javascript_always_use_jquery'
|
||||
// variable is set to FALSE (indicating that the site does not want jQuery
|
||||
// automatically added on all pages) then only add it if a file or setting
|
||||
// that requires jQuery is being added also.
|
||||
if (!$jquery_added && (variable_get('javascript_always_use_jquery', TRUE) || $options['requires_jquery'])) {
|
||||
$jquery_added = TRUE;
|
||||
// url() generates the prefix using hook_url_outbound_alter(). Instead of
|
||||
// running the hook_url_outbound_alter() again here, extract the prefix
|
||||
// from url().
|
||||
url('', array('prefix' => &$prefix));
|
||||
$javascript = array(
|
||||
$default_javascript = array(
|
||||
'settings' => array(
|
||||
'data' => array(
|
||||
array('basePath' => base_path()),
|
||||
@ -4132,11 +4247,13 @@ function drupal_add_js($data = NULL, $options = NULL) {
|
||||
'group' => JS_LIBRARY,
|
||||
'every_page' => TRUE,
|
||||
'weight' => -1,
|
||||
'requires_jquery' => TRUE,
|
||||
'preprocess' => TRUE,
|
||||
'cache' => TRUE,
|
||||
'defer' => FALSE,
|
||||
),
|
||||
);
|
||||
$javascript = drupal_array_merge_deep($javascript, $default_javascript);
|
||||
// Register all required libraries.
|
||||
drupal_add_library('system', 'jquery', TRUE);
|
||||
drupal_add_library('system', 'jquery.once', TRUE);
|
||||
@ -4177,6 +4294,7 @@ function drupal_js_defaults($data = NULL) {
|
||||
'group' => JS_DEFAULT,
|
||||
'every_page' => FALSE,
|
||||
'weight' => 0,
|
||||
'requires_jquery' => TRUE,
|
||||
'scope' => 'header',
|
||||
'cache' => TRUE,
|
||||
'defer' => FALSE,
|
||||
@ -4223,7 +4341,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
|
||||
if (!isset($javascript)) {
|
||||
$javascript = drupal_add_js();
|
||||
}
|
||||
if (empty($javascript)) {
|
||||
|
||||
// If no JavaScript items have been added, or if the only JavaScript items
|
||||
// that have been added are JavaScript settings (which don't do anything
|
||||
// without any JavaScript code to use them), then no JavaScript code should
|
||||
// be added to the page.
|
||||
if (empty($javascript) || (isset($javascript['settings']) && count($javascript) == 1)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -4377,8 +4500,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
|
||||
*
|
||||
* Libraries, JavaScript, CSS and other types of custom structures are attached
|
||||
* to elements using the #attached property. The #attached property is an
|
||||
* associative array, where the keys are the the attachment types and the values
|
||||
* are the attached data. For example:
|
||||
* associative array, where the keys are the attachment types and the values are
|
||||
* the attached data. For example:
|
||||
* @code
|
||||
* $build['#attached'] = array(
|
||||
* 'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
|
||||
@ -5006,19 +5129,6 @@ function drupal_json_output($var = NULL) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a salt useful for hardening against SQL injection.
|
||||
*
|
||||
* @return
|
||||
* A salt based on information in settings.php, not in the database.
|
||||
*/
|
||||
function drupal_get_hash_salt() {
|
||||
global $drupal_hash_salt, $databases;
|
||||
// If the $drupal_hash_salt variable is empty, a hash of the serialized
|
||||
// database credentials is used as a fallback salt.
|
||||
return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the private key variable used to generate tokens is set.
|
||||
*
|
||||
@ -5027,7 +5137,7 @@ function drupal_get_hash_salt() {
|
||||
*/
|
||||
function drupal_get_private_key() {
|
||||
if (!($key = variable_get('drupal_private_key', 0))) {
|
||||
$key = drupal_hash_base64(drupal_random_bytes(55));
|
||||
$key = drupal_random_key();
|
||||
variable_set('drupal_private_key', $key);
|
||||
}
|
||||
return $key;
|
||||
@ -5038,6 +5148,18 @@ function drupal_get_private_key() {
|
||||
*
|
||||
* @param $value
|
||||
* An additional value to base the token on.
|
||||
*
|
||||
* The generated token is based on the session ID of the current user. Normally,
|
||||
* anonymous users do not have a session, so the generated token will be
|
||||
* different on every page request. To generate a token for users without a
|
||||
* session, manually start a session prior to calling this function.
|
||||
*
|
||||
* @return string
|
||||
* A 43-character URL-safe token for validation, based on the user session ID,
|
||||
* the hash salt provided from drupal_get_hash_salt(), and the
|
||||
* 'drupal_private_key' configuration variable.
|
||||
*
|
||||
* @see drupal_get_hash_salt()
|
||||
*/
|
||||
function drupal_get_token($value = '') {
|
||||
return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
|
||||
@ -5059,7 +5181,7 @@ function drupal_get_token($value = '') {
|
||||
*/
|
||||
function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
|
||||
global $user;
|
||||
return (($skip_anonymous && $user->uid == 0) || ($token == drupal_get_token($value)));
|
||||
return (($skip_anonymous && $user->uid == 0) || ($token === drupal_get_token($value)));
|
||||
}
|
||||
|
||||
function _drupal_bootstrap_full() {
|
||||
@ -5092,6 +5214,10 @@ function _drupal_bootstrap_full() {
|
||||
module_load_all();
|
||||
// Make sure all stream wrappers are registered.
|
||||
file_get_stream_wrappers();
|
||||
// Ensure mt_rand is reseeded, to prevent random values from one page load
|
||||
// being exploited to predict random values in subsequent page loads.
|
||||
$seed = unpack("L", drupal_random_bytes(4));
|
||||
mt_srand($seed[1]);
|
||||
|
||||
$test_info = &$GLOBALS['drupal_test_info'];
|
||||
if (!empty($test_info['in_child_site'])) {
|
||||
@ -5129,7 +5255,7 @@ function _drupal_bootstrap_full() {
|
||||
* client without gzip support.
|
||||
*
|
||||
* Page compression requires the PHP zlib extension
|
||||
* (http://php.net/manual/en/ref.zlib.php).
|
||||
* (http://php.net/manual/ref.zlib.php).
|
||||
*
|
||||
* @see drupal_page_header()
|
||||
*/
|
||||
@ -5137,6 +5263,10 @@ function drupal_page_set_cache() {
|
||||
global $base_root;
|
||||
|
||||
if (drupal_page_is_cacheable()) {
|
||||
|
||||
// Check whether the current page might be compressed.
|
||||
$page_compressed = variable_get('page_compression', TRUE) && extension_loaded('zlib');
|
||||
|
||||
$cache = (object) array(
|
||||
'cid' => $base_root . request_uri(),
|
||||
'data' => array(
|
||||
@ -5144,6 +5274,9 @@ function drupal_page_set_cache() {
|
||||
'body' => ob_get_clean(),
|
||||
'title' => drupal_get_title(),
|
||||
'headers' => array(),
|
||||
// We need to store whether page was compressed or not,
|
||||
// because by the time it is read, the configuration might change.
|
||||
'page_compressed' => $page_compressed,
|
||||
),
|
||||
'expire' => CACHE_TEMPORARY,
|
||||
'created' => REQUEST_TIME,
|
||||
@ -5161,7 +5294,7 @@ function drupal_page_set_cache() {
|
||||
}
|
||||
|
||||
if ($cache->data['body']) {
|
||||
if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
|
||||
if ($page_compressed) {
|
||||
$cache->data['body'] = gzencode($cache->data['body'], 9, FORCE_GZIP);
|
||||
}
|
||||
cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire);
|
||||
@ -5210,8 +5343,6 @@ function drupal_cron_run() {
|
||||
foreach ($queues as $queue_name => $info) {
|
||||
DrupalQueue::get($queue_name)->createQueue();
|
||||
}
|
||||
// Register shutdown callback.
|
||||
drupal_register_shutdown_function('drupal_cron_cleanup');
|
||||
|
||||
// Iterate through the modules calling their cron handlers (if any):
|
||||
foreach (module_implements('cron') as $module) {
|
||||
@ -5236,12 +5367,23 @@ function drupal_cron_run() {
|
||||
}
|
||||
|
||||
foreach ($queues as $queue_name => $info) {
|
||||
if (!empty($info['skip on cron'])) {
|
||||
// Do not run if queue wants to skip.
|
||||
continue;
|
||||
}
|
||||
$function = $info['worker callback'];
|
||||
$end = time() + (isset($info['time']) ? $info['time'] : 15);
|
||||
$queue = DrupalQueue::get($queue_name);
|
||||
while (time() < $end && ($item = $queue->claimItem())) {
|
||||
$function($item->data);
|
||||
$queue->deleteItem($item);
|
||||
try {
|
||||
$function($item->data);
|
||||
$queue->deleteItem($item);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// In case of exception log it and leave the item in the queue
|
||||
// to be processed again later.
|
||||
watchdog_exception('cron', $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore the user.
|
||||
@ -5252,10 +5394,13 @@ function drupal_cron_run() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown function: Performs cron cleanup.
|
||||
* DEPRECATED: Shutdown function: Performs cron cleanup.
|
||||
*
|
||||
* @see drupal_cron_run()
|
||||
* @see drupal_register_shutdown_function()
|
||||
* This function is deprecated because the 'cron_semaphore' variable it
|
||||
* references no longer exists. It is therefore no longer used as a shutdown
|
||||
* function by Drupal core.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
function drupal_cron_cleanup() {
|
||||
// See if the semaphore is still locked.
|
||||
@ -5568,7 +5713,7 @@ function drupal_pre_render_link($element) {
|
||||
* @code
|
||||
* $node->content['links'] = array(
|
||||
* '#theme' => 'links__node',
|
||||
* '#pre_render' = array('drupal_pre_render_links'),
|
||||
* '#pre_render' => array('drupal_pre_render_links'),
|
||||
* 'comment' => array(
|
||||
* '#theme' => 'links__node__comment',
|
||||
* '#links' => array(
|
||||
@ -5773,23 +5918,23 @@ function drupal_render_page($page) {
|
||||
* array to be rendered independently and prevents them from being rendered
|
||||
* more than once on subsequent calls to drupal_render() (e.g., as part of a
|
||||
* larger array). If the same array or array element is passed more than once
|
||||
* to drupal_render(), it simply returns a NULL value.
|
||||
* to drupal_render(), it simply returns an empty string.
|
||||
*
|
||||
* @param $elements
|
||||
* @param array $elements
|
||||
* The structured array describing the data to be rendered.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The rendered HTML.
|
||||
*/
|
||||
function drupal_render(&$elements) {
|
||||
// Early-return nothing if user does not have access.
|
||||
if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
// Do not print elements twice.
|
||||
if (!empty($elements['#printed'])) {
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
// Try to fetch the element's markup from cache and return.
|
||||
@ -5825,7 +5970,7 @@ function drupal_render(&$elements) {
|
||||
|
||||
// Allow #pre_render to abort rendering.
|
||||
if (!empty($elements['#printed'])) {
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the children of the element, sorted by weight.
|
||||
@ -5896,14 +6041,16 @@ function drupal_render(&$elements) {
|
||||
/**
|
||||
* Renders children of an element and concatenates them.
|
||||
*
|
||||
* This renders all children of an element using drupal_render() and then
|
||||
* joins them together into a single string.
|
||||
*
|
||||
* @param $element
|
||||
* @param array $element
|
||||
* The structured array whose children shall be rendered.
|
||||
* @param $children_keys
|
||||
* If the keys of the element's children are already known, they can be passed
|
||||
* in to save another run of element_children().
|
||||
* @param array $children_keys
|
||||
* (optional) If the keys of the element's children are already known, they
|
||||
* can be passed in to save another run of element_children().
|
||||
*
|
||||
* @return string
|
||||
* The rendered HTML of all children of the element.
|
||||
|
||||
* @see drupal_render()
|
||||
*/
|
||||
function drupal_render_children(&$element, $children_keys = NULL) {
|
||||
if ($children_keys === NULL) {
|
||||
@ -6447,6 +6594,44 @@ function element_set_attributes(array &$element, array $map) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively computes the difference of arrays with additional index check.
|
||||
*
|
||||
* This is a version of array_diff_assoc() that supports multidimensional
|
||||
* arrays.
|
||||
*
|
||||
* @param array $array1
|
||||
* The array to compare from.
|
||||
* @param array $array2
|
||||
* The array to compare to.
|
||||
*
|
||||
* @return array
|
||||
* Returns an array containing all the values from array1 that are not present
|
||||
* in array2.
|
||||
*/
|
||||
function drupal_array_diff_assoc_recursive($array1, $array2) {
|
||||
$difference = array();
|
||||
|
||||
foreach ($array1 as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
if (!array_key_exists($key, $array2) || !is_array($array2[$key])) {
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
else {
|
||||
$new_diff = drupal_array_diff_assoc_recursive($value, $array2[$key]);
|
||||
if (!empty($new_diff)) {
|
||||
$difference[$key] = $new_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $difference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value in a nested array with variable depth.
|
||||
*
|
||||
@ -6540,10 +6725,10 @@ function drupal_array_set_nested_value(array &$array, array $parents, $value, $f
|
||||
* $value = drupal_array_get_nested_value($form, $parents);
|
||||
* @endcode
|
||||
*
|
||||
* The return value will be NULL, regardless of whether the actual value is NULL
|
||||
* or whether the requested key does not exist. If it is required to know
|
||||
* whether the nested array key actually exists, pass a third argument that is
|
||||
* altered by reference:
|
||||
* A return value of NULL is ambiguous, and can mean either that the requested
|
||||
* key does not exist, or that the actual value is NULL. If it is required to
|
||||
* know whether the nested array key actually exists, pass a third argument that
|
||||
* is altered by reference:
|
||||
* @code
|
||||
* $key_exists = NULL;
|
||||
* $value = drupal_array_get_nested_value($form, $parents, $key_exists);
|
||||
@ -7739,7 +7924,10 @@ function entity_load_unchanged($entity_type, $id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity controller class for an entity type.
|
||||
* Gets the entity controller for an entity type.
|
||||
*
|
||||
* @return DrupalEntityControllerInterface
|
||||
* The entity controller object for the specified entity type.
|
||||
*/
|
||||
function entity_get_controller($entity_type) {
|
||||
$controllers = &drupal_static(__FUNCTION__, array());
|
||||
@ -7799,6 +7987,56 @@ function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke hook_entity_view_mode_alter().
|
||||
*
|
||||
* If adding a new entity similar to nodes, comments or users, you should invoke
|
||||
* this function during the ENTITY_build_content() or ENTITY_view_multiple()
|
||||
* phases of rendering to allow other modules to alter the view mode during this
|
||||
* phase. This function needs to be called before field_attach_prepare_view() to
|
||||
* ensure that the correct content is loaded by field API.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The type of entity, i.e. 'node', 'user'.
|
||||
* @param $entities
|
||||
* The entity objects which are being prepared for view, keyed by object ID.
|
||||
* @param $view_mode
|
||||
* The original view mode e.g. 'full', 'teaser'...
|
||||
* @param $langcode
|
||||
* (optional) A language code to be used for rendering. Defaults to the global
|
||||
* content language of the current request.
|
||||
* @return
|
||||
* An associative array with arrays of entities keyed by view mode.
|
||||
*
|
||||
* @see hook_entity_view_mode_alter()
|
||||
*/
|
||||
function entity_view_mode_prepare($entity_type, $entities, $view_mode, $langcode = NULL) {
|
||||
if (!isset($langcode)) {
|
||||
$langcode = $GLOBALS['language_content']->language;
|
||||
}
|
||||
|
||||
// To ensure hooks are never run after field_attach_prepare_view() only
|
||||
// process items without the entity_view_prepared flag.
|
||||
$entities_by_view_mode = array();
|
||||
foreach ($entities as $id => $entity) {
|
||||
$entity_view_mode = $view_mode;
|
||||
if (empty($entity->entity_view_prepared)) {
|
||||
|
||||
// Allow modules to change the view mode.
|
||||
$context = array(
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity,
|
||||
'langcode' => $langcode,
|
||||
);
|
||||
drupal_alter('entity_view_mode', $entity_view_mode, $context);
|
||||
}
|
||||
|
||||
$entities_by_view_mode[$entity_view_mode][$id] = $entity;
|
||||
}
|
||||
|
||||
return $entities_by_view_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI elements of an entity.
|
||||
*
|
||||
|
@ -28,18 +28,21 @@
|
||||
* Most Drupal database SELECT queries are performed by a call to db_query() or
|
||||
* db_query_range(). Module authors should also consider using the PagerDefault
|
||||
* Extender for queries that return results that need to be presented on
|
||||
* multiple pages, and the Tablesort Extender for generating appropriate queries
|
||||
* for sortable tables.
|
||||
* multiple pages (see https://drupal.org/node/508796), and the TableSort
|
||||
* Extender for generating appropriate queries for sortable tables
|
||||
* (see https://drupal.org/node/1848372).
|
||||
*
|
||||
* For example, one might wish to return a list of the most recent 10 nodes
|
||||
* authored by a given user. Instead of directly issuing the SQL query
|
||||
* @code
|
||||
* SELECT n.nid, n.title, n.created FROM node n WHERE n.uid = $uid LIMIT 0, 10;
|
||||
* SELECT n.nid, n.title, n.created FROM node n WHERE n.uid = $uid
|
||||
* ORDER BY n.created DESC LIMIT 0, 10;
|
||||
* @endcode
|
||||
* one would instead call the Drupal functions:
|
||||
* @code
|
||||
* $result = db_query_range('SELECT n.nid, n.title, n.created
|
||||
* FROM {node} n WHERE n.uid = :uid', 0, 10, array(':uid' => $uid));
|
||||
* FROM {node} n WHERE n.uid = :uid
|
||||
* ORDER BY n.created DESC', 0, 10, array(':uid' => $uid));
|
||||
* foreach ($result as $record) {
|
||||
* // Perform operations on $record->title, etc. here.
|
||||
* }
|
||||
@ -167,7 +170,7 @@
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @link http://drupal.org/developing/api/database @endlink
|
||||
* @see http://drupal.org/developing/api/database
|
||||
*/
|
||||
|
||||
|
||||
@ -179,7 +182,7 @@
|
||||
* concrete implementation of it to support special handling required by that
|
||||
* database.
|
||||
*
|
||||
* @see http://php.net/manual/en/book.pdo.php
|
||||
* @see http://php.net/manual/book.pdo.php
|
||||
*/
|
||||
abstract class DatabaseConnection extends PDO {
|
||||
|
||||
@ -194,7 +197,7 @@ abstract class DatabaseConnection extends PDO {
|
||||
|
||||
/**
|
||||
* The key representing this connection.
|
||||
*
|
||||
*
|
||||
* The key is a unique string which identifies a database connection. A
|
||||
* connection can be a single server or a cluster of master and slaves (use
|
||||
* target to pick between master and slave).
|
||||
@ -303,12 +306,28 @@ abstract class DatabaseConnection extends PDO {
|
||||
// Call PDO::__construct and PDO::setAttribute.
|
||||
parent::__construct($dsn, $username, $password, $driver_options);
|
||||
|
||||
// Set a specific PDOStatement class if the driver requires that.
|
||||
// Set a Statement class, unless the driver opted out.
|
||||
if (!empty($this->statementClass)) {
|
||||
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this Connection object.
|
||||
*
|
||||
* PHP does not destruct an object if it is still referenced in other
|
||||
* variables. In case of PDO database connection objects, PHP only closes the
|
||||
* connection when the PDO object is destructed, so any references to this
|
||||
* object may cause the number of maximum allowed connections to be exceeded.
|
||||
*/
|
||||
public function destroy() {
|
||||
// Destroy all references to this connection by setting them to NULL.
|
||||
// The Statement class attribute only accepts a new value that presents a
|
||||
// proper callable, so we reset it to PDOStatement.
|
||||
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
|
||||
$this->schema = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default query options for any given query.
|
||||
*
|
||||
@ -717,7 +736,7 @@ abstract class DatabaseConnection extends PDO {
|
||||
// to expand it out into a comma-delimited set of placeholders.
|
||||
foreach (array_filter($args, 'is_array') as $key => $data) {
|
||||
$new_keys = array();
|
||||
foreach ($data as $i => $value) {
|
||||
foreach (array_values($data) as $i => $value) {
|
||||
// This assumes that there are no other placeholders that use the same
|
||||
// name. For example, if the array placeholder is defined as :example
|
||||
// and there is already an :example_2 placeholder, this will generate
|
||||
@ -1627,8 +1646,8 @@ abstract class Database {
|
||||
*/
|
||||
final public static function removeConnection($key) {
|
||||
if (isset(self::$databaseInfo[$key])) {
|
||||
self::closeConnection(NULL, $key);
|
||||
unset(self::$databaseInfo[$key]);
|
||||
unset(self::$connections[$key]);
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
@ -1694,11 +1713,24 @@ abstract class Database {
|
||||
if (!isset($key)) {
|
||||
$key = self::$activeKey;
|
||||
}
|
||||
// To close the connection, we need to unset the static variable.
|
||||
// To close a connection, it needs to be set to NULL and removed from the
|
||||
// static variable. In all cases, closeConnection() might be called for a
|
||||
// connection that was not opened yet, in which case the key is not defined
|
||||
// yet and we just ensure that the connection key is undefined.
|
||||
if (isset($target)) {
|
||||
if (isset(self::$connections[$key][$target])) {
|
||||
self::$connections[$key][$target]->destroy();
|
||||
self::$connections[$key][$target] = NULL;
|
||||
}
|
||||
unset(self::$connections[$key][$target]);
|
||||
}
|
||||
else {
|
||||
if (isset(self::$connections[$key])) {
|
||||
foreach (self::$connections[$key] as $target => $connection) {
|
||||
self::$connections[$key][$target]->destroy();
|
||||
self::$connections[$key][$target] = NULL;
|
||||
}
|
||||
}
|
||||
unset(self::$connections[$key]);
|
||||
}
|
||||
}
|
||||
@ -1852,8 +1884,8 @@ class DatabaseTransaction {
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
public function __construct(DatabaseConnection &$connection, $name = NULL) {
|
||||
$this->connection = &$connection;
|
||||
public function __construct(DatabaseConnection $connection, $name = NULL) {
|
||||
$this->connection = $connection;
|
||||
// If there is no transaction depth, then no transaction has started. Name
|
||||
// the transaction 'drupal_transaction'.
|
||||
if (!$depth = $connection->transactionDepth()) {
|
||||
@ -1957,7 +1989,7 @@ interface DatabaseStatementInterface extends Traversable {
|
||||
/**
|
||||
* Sets the default fetch mode for this statement.
|
||||
*
|
||||
* See http://php.net/manual/en/pdo.constants.php for the definition of the
|
||||
* See http://php.net/manual/pdo.constants.php for the definition of the
|
||||
* constants used.
|
||||
*
|
||||
* @param $mode
|
||||
@ -1976,7 +2008,7 @@ interface DatabaseStatementInterface extends Traversable {
|
||||
/**
|
||||
* Fetches the next row from a result set.
|
||||
*
|
||||
* See http://php.net/manual/en/pdo.constants.php for the definition of the
|
||||
* See http://php.net/manual/pdo.constants.php for the definition of the
|
||||
* constants used.
|
||||
*
|
||||
* @param $mode
|
||||
@ -2351,14 +2383,14 @@ function db_query_range($query, $from, $count, array $args = array(), array $opt
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query string and saves the result set to a temporary table.
|
||||
* Executes a SELECT query string and saves the result set to a temporary table.
|
||||
*
|
||||
* The execution of the query string happens against the active database.
|
||||
*
|
||||
* @param $query
|
||||
* The prepared statement query to run. Although it will accept both named and
|
||||
* unnamed placeholders, named placeholders are strongly preferred as they are
|
||||
* more self-documenting.
|
||||
* The prepared SELECT statement query to run. Although it will accept both
|
||||
* named and unnamed placeholders, named placeholders are strongly preferred
|
||||
* as they are more self-documenting.
|
||||
* @param $args
|
||||
* An array of values to substitute into the query. If the query uses named
|
||||
* placeholders, this is an associative array in any order. If the query uses
|
||||
@ -2800,7 +2832,7 @@ function db_drop_table($table) {
|
||||
* will be set to the value of the key in all rows. This is most useful for
|
||||
* creating NOT NULL columns with no default value in existing tables.
|
||||
* @param $keys_new
|
||||
* Optional keys and indexes specification to be created on the table along
|
||||
* (optional) Keys and indexes specification to be created on the table along
|
||||
* with adding the field. The format is the same as a table specification, but
|
||||
* without the 'fields' element. If you are adding a type 'serial' field, you
|
||||
* MUST specify at least one key or index including it in this array. See
|
||||
@ -2980,7 +3012,7 @@ function db_drop_index($table, $name) {
|
||||
* @param $spec
|
||||
* The field specification for the new field.
|
||||
* @param $keys_new
|
||||
* Optional keys and indexes specification to be created on the table along
|
||||
* (optional) Keys and indexes specification to be created on the table along
|
||||
* with changing the field. The format is the same as a table specification
|
||||
* but without the 'fields' element.
|
||||
*/
|
||||
|
@ -13,11 +13,11 @@
|
||||
class DatabaseConnection_mysql extends DatabaseConnection {
|
||||
|
||||
/**
|
||||
* Flag to indicate if we have registered the nextID cleanup function.
|
||||
* Flag to indicate if the cleanup function in __destruct() should run.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $shutdownRegistered = FALSE;
|
||||
protected $needsCleanup = FALSE;
|
||||
|
||||
public function __construct(array $connection_options = array()) {
|
||||
// This driver defaults to transaction support, except if explicitly passed FALSE.
|
||||
@ -36,6 +36,10 @@ class DatabaseConnection_mysql extends DatabaseConnection {
|
||||
// Default to TCP connection on port 3306.
|
||||
$dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
|
||||
}
|
||||
// Character set is added to dsn to ensure PDO uses the proper character
|
||||
// set when escaping. This has security implications. See
|
||||
// https://www.drupal.org/node/1201452 for further discussion.
|
||||
$dsn .= ';charset=utf8';
|
||||
$dsn .= ';dbname=' . $connection_options['database'];
|
||||
// Allow PDO options to be overridden.
|
||||
$connection_options += array(
|
||||
@ -78,13 +82,19 @@ class DatabaseConnection_mysql extends DatabaseConnection {
|
||||
$this->exec(implode('; ', $connection_options['init_commands']));
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if ($this->needsCleanup) {
|
||||
$this->nextIdDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
|
||||
return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
|
||||
}
|
||||
|
||||
public function queryTemporary($query, array $args = array(), array $options = array()) {
|
||||
$tablename = $this->generateTemporaryTableName();
|
||||
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY SELECT', $query), $args, $options);
|
||||
$this->query('CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY ' . $query, $args, $options);
|
||||
return $tablename;
|
||||
}
|
||||
|
||||
@ -115,12 +125,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
|
||||
$this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
|
||||
$new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
|
||||
}
|
||||
if (!$this->shutdownRegistered) {
|
||||
// Use register_shutdown_function() here to keep the database system
|
||||
// independent of Drupal.
|
||||
register_shutdown_function(array($this, 'nextIdDelete'));
|
||||
$shutdownRegistered = TRUE;
|
||||
}
|
||||
$this->needsCleanup = TRUE;
|
||||
return $new_id;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,8 @@ class InsertQuery_mysql extends InsertQuery {
|
||||
// If we're selecting from a SelectQuery, finish building the query and
|
||||
// pass it back, as any remaining options are irrelevant.
|
||||
if (!empty($this->fromQuery)) {
|
||||
return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
|
||||
$insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
|
||||
return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
|
||||
}
|
||||
|
||||
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
|
||||
@ -86,21 +87,7 @@ class InsertQuery_mysql extends InsertQuery {
|
||||
}
|
||||
}
|
||||
|
||||
class TruncateQuery_mysql extends TruncateQuery {
|
||||
public function __toString() {
|
||||
// TRUNCATE is actually a DDL statement on MySQL, and DDL statements are
|
||||
// not transactional, and result in an implicit COMMIT. When we are in a
|
||||
// transaction, fallback to the slower, but transactional, DELETE.
|
||||
if ($this->connection->inTransaction()) {
|
||||
// Create a comment string to prepend to the query.
|
||||
$comments = $this->connection->makeComment($this->comments);
|
||||
return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
|
||||
}
|
||||
else {
|
||||
return parent::__toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
class TruncateQuery_mysql extends TruncateQuery { }
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup database".
|
||||
|
@ -40,7 +40,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
}
|
||||
else {
|
||||
$db_info = Database::getConnectionInfo();
|
||||
$info['database'] = $db_info['default']['database'];
|
||||
$info['database'] = $db_info[$this->connection->getTarget()]['database'];
|
||||
$info['table'] = $table;
|
||||
}
|
||||
return $info;
|
||||
@ -301,10 +301,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function renameTable($table, $new_name) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
if ($this->tableExists($new_name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
|
||||
$info = $this->getPrefixInfo($new_name);
|
||||
@ -322,10 +322,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function addField($table, $field, $spec, $keys_new = array()) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
if ($this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
|
||||
$fixnull = FALSE;
|
||||
@ -361,7 +361,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function fieldSetDefault($table, $field, $default) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
if (!isset($default)) {
|
||||
@ -376,7 +376,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function fieldSetNoDefault($table, $field) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
|
||||
@ -391,10 +391,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function addPrimaryKey($table, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
|
||||
}
|
||||
if ($this->indexExists($table, 'PRIMARY')) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
|
||||
@ -411,10 +411,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function addUniqueKey($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->indexExists($table, $name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
|
||||
@ -431,10 +431,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function addIndex($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->indexExists($table, $name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
|
||||
@ -451,10 +451,10 @@ class DatabaseSchema_mysql extends DatabaseSchema {
|
||||
|
||||
public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
|
||||
}
|
||||
if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", array('@table' => $table, '@name' => $field, '@name_new' => $field_new)));
|
||||
}
|
||||
|
||||
$sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec));
|
||||
|
@ -146,7 +146,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
|
||||
|
||||
public function queryTemporary($query, array $args = array(), array $options = array()) {
|
||||
$tablename = $this->generateTemporaryTableName();
|
||||
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} AS SELECT', $query), $args, $options);
|
||||
$this->query('CREATE TEMPORARY TABLE {' . $tablename . '} AS ' . $query, $args, $options);
|
||||
return $tablename;
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,8 @@ class InsertQuery_pgsql extends InsertQuery {
|
||||
// If we're selecting from a SelectQuery, finish building the query and
|
||||
// pass it back, as any remaining options are irrelevant.
|
||||
if (!empty($this->fromQuery)) {
|
||||
return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
|
||||
$insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
|
||||
return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
|
||||
}
|
||||
|
||||
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
|
||||
|
@ -314,10 +314,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
function renameTable($table, $new_name) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
if ($this->tableExists($new_name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
|
||||
// Get the schema and tablename for the old table.
|
||||
@ -351,10 +351,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function addField($table, $field, $spec, $new_keys = array()) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
if ($this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
|
||||
$fixnull = FALSE;
|
||||
@ -393,7 +393,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function fieldSetDefault($table, $field, $default) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
if (!isset($default)) {
|
||||
@ -408,7 +408,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function fieldSetNoDefault($table, $field) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
|
||||
@ -435,10 +435,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function addPrimaryKey($table, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
|
||||
}
|
||||
if ($this->constraintExists($table, 'pkey')) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')');
|
||||
@ -455,10 +455,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
function addUniqueKey($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->constraintExists($table, $name . '_key')) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
|
||||
@ -475,10 +475,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function addIndex($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->indexExists($table, $name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$this->connection->query($this->_createIndexSql($table, $name, $fields));
|
||||
@ -495,10 +495,10 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||
|
||||
public function changeField($table, $field, $field_new, $spec, $new_keys = array()) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
|
||||
}
|
||||
if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", array('@table' => $table, '@name' => $field, '@name_new' => $field_new)));
|
||||
}
|
||||
|
||||
$spec = $this->processField($spec);
|
||||
|
@ -83,7 +83,7 @@ interface QueryConditionInterface {
|
||||
|
||||
/**
|
||||
* Sets a condition that the specified subquery returns values.
|
||||
*
|
||||
*
|
||||
* @param SelectQueryInterface $select
|
||||
* The subquery that must contain results.
|
||||
*
|
||||
@ -91,10 +91,10 @@ interface QueryConditionInterface {
|
||||
* The called object.
|
||||
*/
|
||||
public function exists(SelectQueryInterface $select);
|
||||
|
||||
|
||||
/**
|
||||
* Sets a condition that the specified subquery returns no values.
|
||||
*
|
||||
*
|
||||
* @param SelectQueryInterface $select
|
||||
* The subquery that must not contain results.
|
||||
*
|
||||
@ -102,7 +102,7 @@ interface QueryConditionInterface {
|
||||
* The called object.
|
||||
*/
|
||||
public function notExists(SelectQueryInterface $select);
|
||||
|
||||
|
||||
/**
|
||||
* Gets a complete list of all conditions in this conditional clause.
|
||||
*
|
||||
@ -283,14 +283,14 @@ abstract class Query implements QueryPlaceholderInterface {
|
||||
|
||||
/**
|
||||
* The target of the connection object.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connectionTarget;
|
||||
|
||||
/**
|
||||
* The key of the connection object.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connectionKey;
|
||||
@ -710,10 +710,11 @@ class InsertQuery extends Query {
|
||||
// first call to fields() does have an effect.
|
||||
$this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions())));
|
||||
}
|
||||
|
||||
// Don't execute query without fields.
|
||||
if (count($this->insertFields) + count($this->defaultFields) == 0) {
|
||||
throw new NoFieldsException('There are no fields available to insert with.');
|
||||
else {
|
||||
// Don't execute query without fields.
|
||||
if (count($this->insertFields) + count($this->defaultFields) == 0) {
|
||||
throw new NoFieldsException('There are no fields available to insert with.');
|
||||
}
|
||||
}
|
||||
|
||||
// If no values have been added, silently ignore this query. This can happen
|
||||
@ -804,7 +805,7 @@ class DeleteQuery extends Query implements QueryConditionInterface {
|
||||
$this->condition->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements QueryConditionInterface::conditions().
|
||||
*/
|
||||
@ -942,7 +943,17 @@ class TruncateQuery extends Query {
|
||||
// Create a sanitized comment string to prepend to the query.
|
||||
$comments = $this->connection->makeComment($this->comments);
|
||||
|
||||
return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
|
||||
// In most cases, TRUNCATE is not a transaction safe statement as it is a
|
||||
// DDL statement which results in an implicit COMMIT. When we are in a
|
||||
// transaction, fallback to the slower, but transactional, DELETE.
|
||||
// PostgreSQL also locks the entire table for a TRUNCATE strongly reducing
|
||||
// the concurrency with other transactions.
|
||||
if ($this->connection->inTransaction()) {
|
||||
return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
|
||||
}
|
||||
else {
|
||||
return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1053,7 +1064,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
|
||||
$this->condition->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements QueryConditionInterface::conditions().
|
||||
*/
|
||||
@ -1545,7 +1556,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
|
||||
$this->condition->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements QueryConditionInterface::conditions().
|
||||
*/
|
||||
@ -1595,55 +1606,43 @@ class MergeQuery extends Query implements QueryConditionInterface {
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
// Wrap multiple queries in a transaction, if the database supports it.
|
||||
$transaction = $this->connection->startTransaction();
|
||||
try {
|
||||
if (!count($this->condition)) {
|
||||
throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
|
||||
if (!count($this->condition)) {
|
||||
throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
|
||||
}
|
||||
$select = $this->connection->select($this->conditionTable)
|
||||
->condition($this->condition);
|
||||
$select->addExpression('1');
|
||||
if (!$select->execute()->fetchField()) {
|
||||
try {
|
||||
$insert = $this->connection->insert($this->table)->fields($this->insertFields);
|
||||
if ($this->defaultFields) {
|
||||
$insert->useDefaults($this->defaultFields);
|
||||
}
|
||||
$insert->execute();
|
||||
return self::STATUS_INSERT;
|
||||
}
|
||||
$select = $this->connection->select($this->conditionTable)
|
||||
->condition($this->condition)
|
||||
->forUpdate();
|
||||
$select->addExpression('1');
|
||||
if (!$select->execute()->fetchField()) {
|
||||
try {
|
||||
$insert = $this->connection->insert($this->table)->fields($this->insertFields);
|
||||
if ($this->defaultFields) {
|
||||
$insert->useDefaults($this->defaultFields);
|
||||
}
|
||||
$insert->execute();
|
||||
return MergeQuery::STATUS_INSERT;
|
||||
catch (Exception $e) {
|
||||
// The insert query failed, maybe it's because a racing insert query
|
||||
// beat us in inserting the same row. Retry the select query, if it
|
||||
// returns a row, ignore the error and continue with the update
|
||||
// query below.
|
||||
if (!$select->execute()->fetchField()) {
|
||||
throw $e;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// The insert query failed, maybe it's because a racing insert query
|
||||
// beat us in inserting the same row. Retry the select query, if it
|
||||
// returns a row, ignore the error and continue with the update
|
||||
// query below.
|
||||
if (!$select->execute()->fetchField()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->needsUpdate) {
|
||||
$update = $this->connection->update($this->table)
|
||||
->fields($this->updateFields)
|
||||
->condition($this->condition);
|
||||
if ($this->expressionFields) {
|
||||
foreach ($this->expressionFields as $field => $data) {
|
||||
$update->expression($field, $data['expression'], $data['arguments']);
|
||||
}
|
||||
}
|
||||
$update->execute();
|
||||
return MergeQuery::STATUS_UPDATE;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// Something really wrong happened here, bubble up the exception to the
|
||||
// caller.
|
||||
$transaction->rollback();
|
||||
throw $e;
|
||||
}
|
||||
// Transaction commits here where $transaction looses scope.
|
||||
if ($this->needsUpdate) {
|
||||
$update = $this->connection->update($this->table)
|
||||
->fields($this->updateFields)
|
||||
->condition($this->condition);
|
||||
if ($this->expressionFields) {
|
||||
foreach ($this->expressionFields as $field => $data) {
|
||||
$update->expression($field, $data['expression'], $data['arguments']);
|
||||
}
|
||||
}
|
||||
$update->execute();
|
||||
return self::STATUS_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1695,7 +1694,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
|
||||
* Implements Countable::count().
|
||||
*
|
||||
* Returns the size of this conditional. The size of the conditional is the
|
||||
* size of its conditional array minus one, because one element is the the
|
||||
* size of its conditional array minus one, because one element is the
|
||||
* conjunction.
|
||||
*/
|
||||
public function count() {
|
||||
@ -1762,14 +1761,14 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
|
||||
public function exists(SelectQueryInterface $select) {
|
||||
return $this->condition('', $select, 'EXISTS');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements QueryConditionInterface::notExists().
|
||||
*/
|
||||
public function notExists(SelectQueryInterface $select) {
|
||||
return $this->condition('', $select, 'NOT EXISTS');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements QueryConditionInterface::conditions().
|
||||
*/
|
||||
@ -1898,8 +1897,13 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
|
||||
function __clone() {
|
||||
$this->changed = TRUE;
|
||||
foreach ($this->conditions as $key => $condition) {
|
||||
if ($key !== '#conjunction' && $condition['field'] instanceOf QueryConditionInterface) {
|
||||
$this->conditions[$key]['field'] = clone($condition['field']);
|
||||
if ($key !== '#conjunction') {
|
||||
if ($condition['field'] instanceOf QueryConditionInterface) {
|
||||
$this->conditions[$key]['field'] = clone($condition['field']);
|
||||
}
|
||||
if ($condition['value'] instanceOf SelectQueryInterface) {
|
||||
$this->conditions[$key]['value'] = clone($condition['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
|
||||
* This is most useful for creating NOT NULL columns with no default
|
||||
* value in existing tables.
|
||||
* @param $keys_new
|
||||
* Optional keys and indexes specification to be created on the
|
||||
* (optional) Keys and indexes specification to be created on the
|
||||
* table along with adding the field. The format is the same as a
|
||||
* table specification but without the 'fields' element. If you are
|
||||
* adding a type 'serial' field, you MUST specify at least one key
|
||||
@ -630,7 +630,7 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
|
||||
* @param $spec
|
||||
* The field specification for the new field.
|
||||
* @param $keys_new
|
||||
* Optional keys and indexes specification to be created on the
|
||||
* (optional) Keys and indexes specification to be created on the
|
||||
* table along with changing the field. The format is the same as a
|
||||
* table specification but without the 'fields' element.
|
||||
*
|
||||
@ -654,7 +654,7 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
|
||||
*/
|
||||
public function createTable($name, $table) {
|
||||
if ($this->tableExists($name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t('Table @name already exists.', array('@name' => $name)));
|
||||
}
|
||||
$statements = $this->createTableSql($name, $table);
|
||||
foreach ($statements as $statement) {
|
||||
|
@ -377,7 +377,8 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
|
||||
* @param $field
|
||||
* The field on which to order.
|
||||
* @param $direction
|
||||
* The direction to sort. Legal values are "ASC" and "DESC".
|
||||
* The direction to sort. Legal values are "ASC" and "DESC". Any other value
|
||||
* will be converted to "ASC".
|
||||
* @return SelectQueryInterface
|
||||
* The called object.
|
||||
*/
|
||||
@ -596,7 +597,7 @@ class SelectQueryExtender implements SelectQueryInterface {
|
||||
|
||||
public function hasAnyTag() {
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array($this->query, 'hasAnyTags'), $args);
|
||||
return call_user_func_array(array($this->query, 'hasAnyTag'), $args);
|
||||
}
|
||||
|
||||
public function addMetaData($key, $object) {
|
||||
@ -1384,6 +1385,8 @@ class SelectQuery extends Query implements SelectQueryInterface {
|
||||
}
|
||||
|
||||
public function orderBy($field, $direction = 'ASC') {
|
||||
// Only allow ASC and DESC, default to ASC.
|
||||
$direction = strtoupper($direction) == 'DESC' ? 'DESC' : 'ASC';
|
||||
$this->order[$field] = $direction;
|
||||
return $this;
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
|
||||
$prefixes[$tablename] = '';
|
||||
$this->setPrefix($prefixes);
|
||||
|
||||
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', $query), $args, $options);
|
||||
$this->query('CREATE TEMPORARY TABLE ' . $tablename . ' AS ' . $query, $args, $options);
|
||||
return $tablename;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,8 @@ class InsertQuery_sqlite extends InsertQuery {
|
||||
// If we're selecting from a SelectQuery, finish building the query and
|
||||
// pass it back, as any remaining options are irrelevant.
|
||||
if (!empty($this->fromQuery)) {
|
||||
return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
|
||||
$insert_fields_string = $this->insertFields ? ' (' . implode(', ', $this->insertFields) . ') ' : ' ';
|
||||
return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
|
||||
}
|
||||
|
||||
return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
|
||||
@ -57,39 +58,18 @@ class InsertQuery_sqlite extends InsertQuery {
|
||||
* we don't select those rows.
|
||||
*
|
||||
* A query like this one:
|
||||
* UPDATE test SET name = 'newname' WHERE tid = 1
|
||||
* UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1
|
||||
* will become:
|
||||
* UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
|
||||
* UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1 AND (col1 <> 'newcol1' OR col2 <> 'newcol2')
|
||||
*/
|
||||
class UpdateQuery_sqlite extends UpdateQuery {
|
||||
/**
|
||||
* Helper function that removes the fields that are already in a condition.
|
||||
*
|
||||
* @param $fields
|
||||
* The fields.
|
||||
* @param QueryConditionInterface $condition
|
||||
* A database condition.
|
||||
*/
|
||||
protected function removeFieldsInCondition(&$fields, QueryConditionInterface $condition) {
|
||||
foreach ($condition->conditions() as $child_condition) {
|
||||
if ($child_condition['field'] instanceof QueryConditionInterface) {
|
||||
$this->removeFieldsInCondition($fields, $child_condition['field']);
|
||||
}
|
||||
else {
|
||||
unset($fields[$child_condition['field']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
|
||||
return parent::execute();
|
||||
}
|
||||
|
||||
// Get the fields used in the update query, and remove those that are already
|
||||
// in the condition.
|
||||
// Get the fields used in the update query.
|
||||
$fields = $this->expressionFields + $this->fields;
|
||||
$this->removeFieldsInCondition($fields, $this->condition);
|
||||
|
||||
// Add the inverse of the fields to the condition.
|
||||
$condition = new DatabaseCondition('OR');
|
||||
|
@ -232,10 +232,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function renameTable($table, $new_name) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
if ($this->tableExists($new_name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename @table to @table_new: table @table_new already exists.", array('@table' => $table, '@table_new' => $new_name)));
|
||||
}
|
||||
|
||||
$schema = $this->introspectSchema($table);
|
||||
@ -278,10 +278,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function addField($table, $field, $specification, $keys_new = array()) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
if ($this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add field @table.@field: field already exists.", array('@field' => $field, '@table' => $table)));
|
||||
}
|
||||
|
||||
// SQLite doesn't have a full-featured ALTER TABLE statement. It only
|
||||
@ -494,10 +494,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array('@table' => $table, '@name' => $field)));
|
||||
}
|
||||
if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", array('@table' => $table, '@name' => $field, '@name_new' => $field_new)));
|
||||
}
|
||||
|
||||
$old_schema = $this->introspectSchema($table);
|
||||
@ -559,10 +559,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function addIndex($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->indexExists($table, $name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add index @name to table @table: index already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$schema['indexes'][$name] = $fields;
|
||||
@ -591,10 +591,10 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function addUniqueKey($table, $name, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key @name to table @table: table doesn't exist.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
if ($this->indexExists($table, $name)) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name)));
|
||||
}
|
||||
|
||||
$schema['unique keys'][$name] = $fields;
|
||||
@ -617,14 +617,14 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function addPrimaryKey($table, $fields) {
|
||||
if (!$this->tableExists($table)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table @table: table doesn't exist.", array('@table' => $table)));
|
||||
}
|
||||
|
||||
$old_schema = $this->introspectSchema($table);
|
||||
$new_schema = $old_schema;
|
||||
|
||||
if (!empty($new_schema['primary key'])) {
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
|
||||
throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table)));
|
||||
}
|
||||
|
||||
$new_schema['primary key'] = $fields;
|
||||
@ -646,7 +646,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function fieldSetDefault($table, $field, $default) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
$old_schema = $this->introspectSchema($table);
|
||||
@ -658,7 +658,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
|
||||
|
||||
public function fieldSetNoDefault($table, $field) {
|
||||
if (!$this->fieldExists($table, $field)) {
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
|
||||
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field @table.@field: field doesn't exist.", array('@table' => $table, '@field' => $field)));
|
||||
}
|
||||
|
||||
$old_schema = $this->introspectSchema($table);
|
||||
|
@ -13,14 +13,6 @@
|
||||
*/
|
||||
interface DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param $entityType
|
||||
* The entity type for which the instance is created.
|
||||
*/
|
||||
public function __construct($entityType);
|
||||
|
||||
/**
|
||||
* Resets the internal, static entity cache.
|
||||
*
|
||||
@ -36,7 +28,9 @@ interface DrupalEntityControllerInterface {
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
* An array of conditions. Keys are field names on the entity's base table.
|
||||
* Values will be compared for equality. All the comparisons will be ANDed
|
||||
* together. This parameter is deprecated; use an EntityFieldQuery instead.
|
||||
*
|
||||
* @return
|
||||
* An array of entity objects indexed by their ids. When no results are
|
||||
@ -54,7 +48,7 @@ interface DrupalEntityControllerInterface {
|
||||
class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Static cache of entities.
|
||||
* Static cache of entities, keyed by entity ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@ -119,6 +113,9 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
|
||||
/**
|
||||
* Constructor: sets basic variables.
|
||||
*
|
||||
* @param $entityType
|
||||
* The entity type for which the instance is created.
|
||||
*/
|
||||
public function __construct($entityType) {
|
||||
$this->entityType = $entityType;
|
||||
@ -241,7 +238,9 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
* @param $ids
|
||||
* An array of entity IDs, or FALSE to load all entities.
|
||||
* @param $conditions
|
||||
* An array of conditions in the form 'field' => $value.
|
||||
* An array of conditions. Keys are field names on the entity's base table.
|
||||
* Values will be compared for equality. All the comparisons will be ANDed
|
||||
* together. This parameter is deprecated; use an EntityFieldQuery instead.
|
||||
* @param $revision_id
|
||||
* The ID of the revision to load, or FALSE if this query is asking for the
|
||||
* most current revision(s).
|
||||
@ -365,9 +364,23 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
|
||||
// This ensures the same behavior whether loading from memory or database.
|
||||
if ($conditions) {
|
||||
foreach ($entities as $entity) {
|
||||
$entity_values = (array) $entity;
|
||||
if (array_diff_assoc($conditions, $entity_values)) {
|
||||
unset($entities[$entity->{$this->idKey}]);
|
||||
// Iterate over all conditions and compare them to the entity
|
||||
// properties. We cannot use array_diff_assoc() here since the
|
||||
// conditions can be nested arrays, too.
|
||||
foreach ($conditions as $property_name => $condition) {
|
||||
if (is_array($condition)) {
|
||||
// Multiple condition values for one property are treated as OR
|
||||
// operation: only if the value is not at all in the condition array
|
||||
// we remove the entity.
|
||||
if (!in_array($entity->{$property_name}, $condition)) {
|
||||
unset($entities[$entity->{$this->idKey}]);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
elseif ($condition != $entity->{$property_name}) {
|
||||
unset($entities[$entity->{$this->idKey}]);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -634,7 +647,7 @@ class EntityFieldQuery {
|
||||
|
||||
/**
|
||||
* Adds a condition on field values.
|
||||
*
|
||||
*
|
||||
* Note that entities with empty field values will be excluded from the
|
||||
* EntityFieldQuery results when using this method.
|
||||
*
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Maps PHP error constants to watchdog severity levels.
|
||||
*
|
||||
* The error constants are documented at
|
||||
* http://php.net/manual/en/errorfunc.constants.php
|
||||
* http://php.net/manual/errorfunc.constants.php
|
||||
*
|
||||
* @ingroup logging_severity_levels
|
||||
*/
|
||||
@ -169,7 +169,7 @@ function error_displayable($error = NULL) {
|
||||
* TRUE if the error is fatal.
|
||||
*/
|
||||
function _drupal_log_error($error, $fatal = FALSE) {
|
||||
// Initialize a maintenance theme if the boostrap was not complete.
|
||||
// Initialize a maintenance theme if the bootstrap was not complete.
|
||||
// Do it early because drupal_set_message() triggers a drupal_theme_initialize().
|
||||
if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
|
||||
unset($GLOBALS['theme']);
|
||||
|
@ -89,7 +89,7 @@ define('FILE_STATUS_PERMANENT', 1);
|
||||
* wrappers that are appropriate for particular usage. For example, this returns
|
||||
* only stream wrappers that use local file storage:
|
||||
* @code
|
||||
* $local_stream_wrappers = file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL);
|
||||
* $local_stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
|
||||
* @endcode
|
||||
*
|
||||
* The $filter parameter can only filter to types containing a particular flag.
|
||||
@ -99,7 +99,7 @@ define('FILE_STATUS_PERMANENT', 1);
|
||||
* array_diff_key() function can be used to help with this. For example, this
|
||||
* returns only stream wrappers that do not use local file storage:
|
||||
* @code
|
||||
* $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL));
|
||||
* $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL));
|
||||
* @endcode
|
||||
*
|
||||
* @param $filter
|
||||
@ -282,10 +282,6 @@ function file_stream_wrapper_uri_normalize($uri) {
|
||||
$uri = $scheme . '://' . $target;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The default scheme is file://
|
||||
$url = 'file://' . $uri;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
@ -474,8 +470,11 @@ function file_ensure_htaccess() {
|
||||
* @param $private
|
||||
* FALSE indicates that $directory should be an open and public directory.
|
||||
* The default is TRUE which indicates a private and protected directory.
|
||||
* @param $force_overwrite
|
||||
* Set to TRUE to attempt to overwrite the existing .htaccess file if one is
|
||||
* already present. Defaults to FALSE.
|
||||
*/
|
||||
function file_create_htaccess($directory, $private = TRUE) {
|
||||
function file_create_htaccess($directory, $private = TRUE, $force_overwrite = FALSE) {
|
||||
if (file_uri_scheme($directory)) {
|
||||
$directory = file_stream_wrapper_uri_normalize($directory);
|
||||
}
|
||||
@ -484,19 +483,12 @@ function file_create_htaccess($directory, $private = TRUE) {
|
||||
}
|
||||
$htaccess_path = $directory . '/.htaccess';
|
||||
|
||||
if (file_exists($htaccess_path)) {
|
||||
if (file_exists($htaccess_path) && !$force_overwrite) {
|
||||
// Short circuit if the .htaccess file already exists.
|
||||
return;
|
||||
}
|
||||
|
||||
if ($private) {
|
||||
// Private .htaccess file.
|
||||
$htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks";
|
||||
}
|
||||
else {
|
||||
// Public .htaccess file.
|
||||
$htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
|
||||
}
|
||||
$htaccess_lines = file_htaccess_lines($private);
|
||||
|
||||
// Write the .htaccess file.
|
||||
if (file_put_contents($htaccess_path, $htaccess_lines)) {
|
||||
@ -508,6 +500,45 @@ function file_create_htaccess($directory, $private = TRUE) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard .htaccess lines that Drupal writes to file directories.
|
||||
*
|
||||
* @param $private
|
||||
* (Optional) Set to FALSE to return the .htaccess lines for an open and
|
||||
* public directory. The default is TRUE, which returns the .htaccess lines
|
||||
* for a private and protected directory.
|
||||
*
|
||||
* @return
|
||||
* A string representing the desired contents of the .htaccess file.
|
||||
*
|
||||
* @see file_create_htaccess()
|
||||
*/
|
||||
function file_htaccess_lines($private = TRUE) {
|
||||
$lines = <<<EOF
|
||||
# Turn off all options we don't need.
|
||||
Options None
|
||||
Options +FollowSymLinks
|
||||
|
||||
# Set the catch-all handler to prevent scripts from being executed.
|
||||
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
|
||||
<Files *>
|
||||
# Override the handler again if we're run later in the evaluation list.
|
||||
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
|
||||
</Files>
|
||||
|
||||
# If we know how to do it safely, disable the PHP engine entirely.
|
||||
<IfModule mod_php5.c>
|
||||
php_flag engine off
|
||||
</IfModule>
|
||||
EOF;
|
||||
|
||||
if ($private) {
|
||||
$lines = "Deny from all\n\n" . $lines;
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads file objects from the database.
|
||||
*
|
||||
@ -590,7 +621,11 @@ function file_save(stdClass $file) {
|
||||
module_invoke_all('entity_update', $file, 'file');
|
||||
}
|
||||
|
||||
// Clear internal properties.
|
||||
unset($file->original);
|
||||
// Clear the static loading cache.
|
||||
entity_get_controller('file')->resetCache(array($file->fid));
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
@ -723,10 +758,11 @@ function file_usage_delete(stdClass $file, $module, $type = NULL, $id = NULL, $c
|
||||
* stored in the database. This is a powerful function that in many ways
|
||||
* performs like an advanced version of copy().
|
||||
* - Checks if $source and $destination are valid and readable/writable.
|
||||
* - Checks that $source is not equal to $destination; if they are an error
|
||||
* is reported.
|
||||
* - If file already exists in $destination either the call will error out,
|
||||
* replace the file or rename the file based on the $replace parameter.
|
||||
* - If the $source and $destination are equal, the behavior depends on the
|
||||
* $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME
|
||||
* will rename the file until the $destination is unique.
|
||||
* - Adds the new file to the files database. If the source file is a
|
||||
* temporary file, the resulting file will also be a temporary file. See
|
||||
* file_save_upload() for details on temporary files.
|
||||
@ -821,10 +857,11 @@ function file_valid_uri($uri) {
|
||||
* This is a powerful function that in many ways performs like an advanced
|
||||
* version of copy().
|
||||
* - Checks if $source and $destination are valid and readable/writable.
|
||||
* - Checks that $source is not equal to $destination; if they are an error
|
||||
* is reported.
|
||||
* - If file already exists in $destination either the call will error out,
|
||||
* replace the file or rename the file based on the $replace parameter.
|
||||
* - If the $source and $destination are equal, the behavior depends on the
|
||||
* $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME
|
||||
* will rename the file until the $destination is unique.
|
||||
* - Provides a fallback using realpaths if the move fails using stream
|
||||
* wrappers. This can occur because PHP's copy() function does not properly
|
||||
* support streams if safe_mode or open_basedir are enabled. See
|
||||
@ -834,9 +871,8 @@ function file_valid_uri($uri) {
|
||||
* A string specifying the filepath or URI of the source file.
|
||||
* @param $destination
|
||||
* A URI containing the destination that $source should be copied to. The
|
||||
* URI may be a bare filepath (without a scheme) and in that case the default
|
||||
* scheme (file://) will be used. If this value is omitted, Drupal's default
|
||||
* files scheme will be used, usually "public://".
|
||||
* URI may be a bare filepath (without a scheme). If this value is omitted,
|
||||
* Drupal's default files scheme will be used, usually "public://".
|
||||
* @param $replace
|
||||
* Replace behavior when the destination file already exists:
|
||||
* - FILE_EXISTS_REPLACE - Replace the existing file.
|
||||
@ -892,7 +928,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
|
||||
$destination = file_destination($destination, $replace);
|
||||
if ($destination === FALSE) {
|
||||
drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error');
|
||||
watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => $destination));
|
||||
watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%directory' => $destination));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1113,10 +1149,10 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
|
||||
|
||||
// Allow potentially insecure uploads for very savvy users and admin
|
||||
if (!variable_get('allow_insecure_uploads', 0)) {
|
||||
// Remove any null bytes. See http://php.net/manual/en/security.filesystem.nullbytes.php
|
||||
// Remove any null bytes. See http://php.net/manual/security.filesystem.nullbytes.php
|
||||
$filename = str_replace(chr(0), '', $filename);
|
||||
|
||||
$whitelist = array_unique(explode(' ', trim($extensions)));
|
||||
$whitelist = array_unique(explode(' ', strtolower(trim($extensions))));
|
||||
|
||||
// Split the filename up by periods. The first part becomes the basename
|
||||
// the last part the final extension.
|
||||
@ -1129,7 +1165,7 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
|
||||
// of allowed extensions.
|
||||
foreach ($filename_parts as $filename_part) {
|
||||
$new_filename .= '.' . $filename_part;
|
||||
if (!in_array($filename_part, $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
|
||||
if (!in_array(strtolower($filename_part), $whitelist) && preg_match("/^[a-zA-Z]{2,5}\d?$/", $filename_part)) {
|
||||
$new_filename .= '_';
|
||||
}
|
||||
}
|
||||
@ -1261,6 +1297,7 @@ function file_delete(stdClass $file, $force = FALSE) {
|
||||
if (file_unmanaged_delete($file->uri)) {
|
||||
db_delete('file_managed')->condition('fid', $file->fid)->execute();
|
||||
db_delete('file_usage')->condition('fid', $file->fid)->execute();
|
||||
entity_get_controller('file')->resetCache();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -1370,8 +1407,9 @@ function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
|
||||
* Temporary files are periodically cleaned. To make the file a permanent file,
|
||||
* assign the status and use file_save() to save the changes.
|
||||
*
|
||||
* @param $source
|
||||
* A string specifying the filepath or URI of the uploaded file to save.
|
||||
* @param $form_field_name
|
||||
* A string that is the associative array key of the upload form element in
|
||||
* the form array.
|
||||
* @param $validators
|
||||
* An optional, associative array of callback functions used to validate the
|
||||
* file. See file_validate() for a full discussion of the array format.
|
||||
@ -1382,9 +1420,9 @@ function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
|
||||
* (Beware: this is not safe and should only be allowed for trusted users, if
|
||||
* at all).
|
||||
* @param $destination
|
||||
* A string containing the URI $source should be copied to.
|
||||
* This must be a stream wrapper URI. If this value is omitted, Drupal's
|
||||
* temporary files scheme will be used ("temporary://").
|
||||
* A string containing the URI that the file should be copied to. This must
|
||||
* be a stream wrapper URI. If this value is omitted, Drupal's temporary
|
||||
* files scheme will be used ("temporary://").
|
||||
* @param $replace
|
||||
* Replace behavior when the destination file already exists:
|
||||
* - FILE_EXISTS_REPLACE: Replace the existing file.
|
||||
@ -1402,45 +1440,45 @@ function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
|
||||
* - source: Path to the file before it is moved.
|
||||
* - destination: Path to the file after it is moved (same as 'uri').
|
||||
*/
|
||||
function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
|
||||
function file_save_upload($form_field_name, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
|
||||
global $user;
|
||||
static $upload_cache;
|
||||
|
||||
// Return cached objects without processing since the file will have
|
||||
// already been processed and the paths in _FILES will be invalid.
|
||||
if (isset($upload_cache[$source])) {
|
||||
return $upload_cache[$source];
|
||||
if (isset($upload_cache[$form_field_name])) {
|
||||
return $upload_cache[$form_field_name];
|
||||
}
|
||||
|
||||
// Make sure there's an upload to process.
|
||||
if (empty($_FILES['files']['name'][$source])) {
|
||||
if (empty($_FILES['files']['name'][$form_field_name])) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check for file upload errors and return FALSE if a lower level system
|
||||
// error occurred. For a complete list of errors:
|
||||
// See http://php.net/manual/en/features.file-upload.errors.php.
|
||||
switch ($_FILES['files']['error'][$source]) {
|
||||
// See http://php.net/manual/features.file-upload.errors.php.
|
||||
switch ($_FILES['files']['error'][$form_field_name]) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $_FILES['files']['name'][$source], '%maxsize' => format_size(file_upload_max_size()))), 'error');
|
||||
drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $_FILES['files']['name'][$form_field_name], '%maxsize' => format_size(file_upload_max_size()))), 'error');
|
||||
return FALSE;
|
||||
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $_FILES['files']['name'][$source])), 'error');
|
||||
drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $_FILES['files']['name'][$form_field_name])), 'error');
|
||||
return FALSE;
|
||||
|
||||
case UPLOAD_ERR_OK:
|
||||
// Final check that this is a valid upload, if it isn't, use the
|
||||
// default error handler.
|
||||
if (is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
|
||||
if (is_uploaded_file($_FILES['files']['tmp_name'][$form_field_name])) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown error
|
||||
default:
|
||||
drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $_FILES['files']['name'][$source])), 'error');
|
||||
drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $_FILES['files']['name'][$form_field_name])), 'error');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1448,10 +1486,10 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
$file = new stdClass();
|
||||
$file->uid = $user->uid;
|
||||
$file->status = 0;
|
||||
$file->filename = trim(drupal_basename($_FILES['files']['name'][$source]), '.');
|
||||
$file->uri = $_FILES['files']['tmp_name'][$source];
|
||||
$file->filename = trim(drupal_basename($_FILES['files']['name'][$form_field_name]), '.');
|
||||
$file->uri = $_FILES['files']['tmp_name'][$form_field_name];
|
||||
$file->filemime = file_get_mimetype($file->filename);
|
||||
$file->filesize = $_FILES['files']['size'][$source];
|
||||
$file->filesize = $_FILES['files']['size'][$form_field_name];
|
||||
|
||||
$extensions = '';
|
||||
if (isset($validators['file_validate_extensions'])) {
|
||||
@ -1508,7 +1546,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$file->source = $source;
|
||||
$file->source = $form_field_name;
|
||||
// A URI may already have a trailing slash or look like "public://".
|
||||
if (substr($destination, -1) != '/') {
|
||||
$destination .= '/';
|
||||
@ -1517,11 +1555,11 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
// If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
|
||||
// there's an existing file so we need to bail.
|
||||
if ($file->destination === FALSE) {
|
||||
drupal_set_message(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $source, '%directory' => $destination)), 'error');
|
||||
drupal_set_message(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', array('%source' => $form_field_name, '%directory' => $destination)), 'error');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Add in our check of the the file name length.
|
||||
// Add in our check of the file name length.
|
||||
$validators['file_validate_name_length'] = array();
|
||||
|
||||
// Call the validation functions specified by this function's caller.
|
||||
@ -1536,7 +1574,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
else {
|
||||
$message .= ' ' . array_pop($errors);
|
||||
}
|
||||
form_set_error($source, $message);
|
||||
form_set_error($form_field_name, $message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1544,8 +1582,8 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
// directory. This overcomes open_basedir restrictions for future file
|
||||
// operations.
|
||||
$file->uri = $file->destination;
|
||||
if (!drupal_move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
|
||||
form_set_error($source, t('File upload error. Could not move uploaded file.'));
|
||||
if (!drupal_move_uploaded_file($_FILES['files']['tmp_name'][$form_field_name], $file->uri)) {
|
||||
form_set_error($form_field_name, t('File upload error. Could not move uploaded file.'));
|
||||
watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));
|
||||
return FALSE;
|
||||
}
|
||||
@ -1565,7 +1603,7 @@ function file_save_upload($source, $validators = array(), $destination = FALSE,
|
||||
// If we made it this far it's safe to record this file in the database.
|
||||
if ($file = file_save($file)) {
|
||||
// Add file to the cache.
|
||||
$upload_cache[$source] = $file;
|
||||
$upload_cache[$form_field_name] = $file;
|
||||
return $file;
|
||||
}
|
||||
return FALSE;
|
||||
@ -1691,8 +1729,6 @@ function file_validate_extensions(stdClass $file, $extensions) {
|
||||
/**
|
||||
* Checks that the file's size is below certain limits.
|
||||
*
|
||||
* This check is not enforced for the user #1.
|
||||
*
|
||||
* @param $file
|
||||
* A Drupal file object.
|
||||
* @param $file_limit
|
||||
@ -1710,20 +1746,17 @@ function file_validate_extensions(stdClass $file, $extensions) {
|
||||
*/
|
||||
function file_validate_size(stdClass $file, $file_limit = 0, $user_limit = 0) {
|
||||
global $user;
|
||||
|
||||
$errors = array();
|
||||
|
||||
// Bypass validation for uid = 1.
|
||||
if ($user->uid != 1) {
|
||||
if ($file_limit && $file->filesize > $file_limit) {
|
||||
$errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
|
||||
}
|
||||
|
||||
// Save a query by only calling file_space_used() when a limit is provided.
|
||||
if ($user_limit && (file_space_used($user->uid) + $file->filesize) > $user_limit) {
|
||||
$errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit)));
|
||||
}
|
||||
if ($file_limit && $file->filesize > $file_limit) {
|
||||
$errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($file_limit)));
|
||||
}
|
||||
|
||||
// Save a query by only calling file_space_used() when a limit is provided.
|
||||
if ($user_limit && (file_space_used($user->uid) + $file->filesize) > $user_limit) {
|
||||
$errors[] = t('The file is %filesize which would exceed your disk quota of %quota.', array('%filesize' => format_size($file->filesize), '%quota' => format_size($user_limit)));
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
@ -1961,23 +1994,7 @@ function file_download() {
|
||||
$target = implode('/', $args);
|
||||
$uri = $scheme . '://' . $target;
|
||||
if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
|
||||
// Let other modules provide headers and controls access to the file.
|
||||
// module_invoke_all() uses array_merge_recursive() which merges header
|
||||
// values into a new array. To avoid that and allow modules to override
|
||||
// headers instead, use array_merge() to merge the returned arrays.
|
||||
$headers = array();
|
||||
foreach (module_implements('file_download') as $module) {
|
||||
$function = $module . '_file_download';
|
||||
$result = $function($uri);
|
||||
if ($result == -1) {
|
||||
// Throw away the headers received so far.
|
||||
$headers = array();
|
||||
break;
|
||||
}
|
||||
if (isset($result) && is_array($result)) {
|
||||
$headers = array_merge($headers, $result);
|
||||
}
|
||||
}
|
||||
$headers = file_download_headers($uri);
|
||||
if (count($headers)) {
|
||||
file_transfer($uri, $headers);
|
||||
}
|
||||
@ -1989,6 +2006,69 @@ function file_download() {
|
||||
drupal_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves headers for a private file download.
|
||||
*
|
||||
* Calls all module implementations of hook_file_download() to retrieve headers
|
||||
* for files by the module that originally provided the file. The presence of
|
||||
* returned headers indicates the current user has access to the file.
|
||||
*
|
||||
* @param $uri
|
||||
* The URI for the file whose headers should be retrieved.
|
||||
*
|
||||
* @return
|
||||
* If access is allowed, headers for the file, suitable for passing to
|
||||
* file_transfer(). If access is not allowed, an empty array will be returned.
|
||||
*
|
||||
* @see file_transfer()
|
||||
* @see file_download_access()
|
||||
* @see hook_file_downlaod()
|
||||
*/
|
||||
function file_download_headers($uri) {
|
||||
// Let other modules provide headers and control access to the file.
|
||||
// module_invoke_all() uses array_merge_recursive() which merges header
|
||||
// values into a new array. To avoid that and allow modules to override
|
||||
// headers instead, use array_merge() to merge the returned arrays.
|
||||
$headers = array();
|
||||
foreach (module_implements('file_download') as $module) {
|
||||
$function = $module . '_file_download';
|
||||
$result = $function($uri);
|
||||
if ($result == -1) {
|
||||
// Throw away the headers received so far.
|
||||
$headers = array();
|
||||
break;
|
||||
}
|
||||
if (isset($result) && is_array($result)) {
|
||||
$headers = array_merge($headers, $result);
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the current user has access to a particular file.
|
||||
*
|
||||
* The return value of this function hinges on the return value from
|
||||
* file_download_headers(), which is the function responsible for collecting
|
||||
* access information through hook_file_download().
|
||||
*
|
||||
* If immediately transferring the file to the browser and the headers will
|
||||
* need to be retrieved, the return value of file_download_headers() should be
|
||||
* used to determine access directly, so that access checks will not be run
|
||||
* twice.
|
||||
*
|
||||
* @param $uri
|
||||
* The URI for the file whose access should be retrieved.
|
||||
*
|
||||
* @return
|
||||
* Boolean TRUE if access is allowed. FALSE if access is not allowed.
|
||||
*
|
||||
* @see file_download_headers()
|
||||
* @see hook_file_download()
|
||||
*/
|
||||
function file_download_access($uri) {
|
||||
return count(file_download_headers($uri)) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all files that match a given mask in a given directory.
|
||||
@ -2182,7 +2262,7 @@ function drupal_chmod($uri, $mode = NULL) {
|
||||
* @param $uri
|
||||
* A URI or pathname.
|
||||
* @param $context
|
||||
* Refer to http://php.net/manual/en/ref.stream.php
|
||||
* Refer to http://php.net/manual/ref.stream.php
|
||||
*
|
||||
* @return
|
||||
* Boolean TRUE on success, or FALSE on failure.
|
||||
@ -2204,29 +2284,21 @@ function drupal_unlink($uri, $context = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute local filesystem path of a stream URI.
|
||||
* Resolves the absolute filepath of a local URI or filepath.
|
||||
*
|
||||
* This function was originally written to ease the conversion of 6.x code to
|
||||
* use 7.x stream wrappers. However, it assumes that every URI may be resolved
|
||||
* to an absolute local filesystem path, and this assumption fails when stream
|
||||
* wrappers are used to support remote file storage. Remote stream wrappers
|
||||
* may implement the realpath method by always returning FALSE. The use of
|
||||
* drupal_realpath() is discouraged, and is slowly being removed from core
|
||||
* functions where possible.
|
||||
* The use of drupal_realpath() is discouraged, because it does not work for
|
||||
* remote URIs. Except in rare cases, URIs should not be manually resolved.
|
||||
*
|
||||
* Only use this function if you know that the stream wrapper in the URI uses
|
||||
* the local file system, and you need to pass an absolute path to a function
|
||||
* that is incompatible with stream URIs.
|
||||
*
|
||||
* @param $uri
|
||||
* A stream wrapper URI or a filesystem path, possibly including one or more
|
||||
* symbolic links.
|
||||
* @param string $uri
|
||||
* A stream wrapper URI or a filepath, possibly including one or more symbolic
|
||||
* links.
|
||||
*
|
||||
* @return
|
||||
* The absolute local filesystem path (with no symbolic links), or FALSE on
|
||||
* failure.
|
||||
*
|
||||
* @todo This function is deprecated, and should be removed wherever possible.
|
||||
* @return string|false
|
||||
* The absolute local filepath (with no symbolic links), or FALSE on failure.
|
||||
*
|
||||
* @see DrupalStreamWrapperInterface::realpath()
|
||||
* @see http://php.net/manual/function.realpath.php
|
||||
@ -2323,7 +2395,7 @@ function drupal_basename($uri, $suffix = NULL) {
|
||||
* @param $recursive
|
||||
* Default to FALSE.
|
||||
* @param $context
|
||||
* Refer to http://php.net/manual/en/ref.stream.php
|
||||
* Refer to http://php.net/manual/ref.stream.php
|
||||
*
|
||||
* @return
|
||||
* Boolean TRUE on success, or FALSE on failure.
|
||||
@ -2354,7 +2426,7 @@ function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) {
|
||||
* @param $uri
|
||||
* A URI or pathname.
|
||||
* @param $context
|
||||
* Refer to http://php.net/manual/en/ref.stream.php
|
||||
* Refer to http://php.net/manual/ref.stream.php
|
||||
*
|
||||
* @return
|
||||
* Boolean TRUE on success, or FALSE on failure.
|
||||
@ -2481,20 +2553,10 @@ function file_directory_temp() {
|
||||
function file_get_content_headers($file) {
|
||||
$name = mime_header_encode($file->filename);
|
||||
$type = mime_header_encode($file->filemime);
|
||||
// Serve images, text, and flash content for display rather than download.
|
||||
$inline_types = variable_get('file_inline_types', array('^text/', '^image/', 'flash$'));
|
||||
$disposition = 'attachment';
|
||||
foreach ($inline_types as $inline_type) {
|
||||
// Exclamation marks are used as delimiters to avoid escaping slashes.
|
||||
if (preg_match('!' . $inline_type . '!', $file->filemime)) {
|
||||
$disposition = 'inline';
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'Content-Type' => $type,
|
||||
'Content-Length' => $file->filesize,
|
||||
'Content-Disposition' => $disposition . '; filename="' . $name . '"',
|
||||
'Cache-Control' => 'private',
|
||||
);
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ function file_default_mimetype_mapping() {
|
||||
4 => 'application/cap',
|
||||
5 => 'application/cu-seeme',
|
||||
6 => 'application/dsptype',
|
||||
350 => 'application/epub+zip',
|
||||
7 => 'application/hta',
|
||||
8 => 'application/java-archive',
|
||||
9 => 'application/java-serialized-object',
|
||||
@ -64,6 +65,7 @@ function file_default_mimetype_mapping() {
|
||||
25 => 'application/rss+xml',
|
||||
26 => 'application/rtf',
|
||||
27 => 'application/smil',
|
||||
349 => 'application/vnd.amazon.ebook',
|
||||
28 => 'application/vnd.cinderella',
|
||||
29 => 'application/vnd.google-earth.kml+xml',
|
||||
30 => 'application/vnd.google-earth.kmz',
|
||||
@ -183,6 +185,8 @@ function file_default_mimetype_mapping() {
|
||||
144 => 'application/x-lzx',
|
||||
145 => 'application/x-maker',
|
||||
146 => 'application/x-mif',
|
||||
351 => 'application/x-mobipocket-ebook',
|
||||
352 => 'application/x-mobipocket-ebook',
|
||||
147 => 'application/x-ms-wmd',
|
||||
148 => 'application/x-ms-wmz',
|
||||
149 => 'application/x-msdos-program',
|
||||
@ -228,8 +232,10 @@ function file_default_mimetype_mapping() {
|
||||
188 => 'audio/mpeg',
|
||||
189 => 'audio/ogg',
|
||||
190 => 'audio/prs.sid',
|
||||
356 => 'audio/webm',
|
||||
191 => 'audio/x-aiff',
|
||||
192 => 'audio/x-gsm',
|
||||
354 => 'audio/x-matroska',
|
||||
193 => 'audio/x-mpegurl',
|
||||
194 => 'audio/x-ms-wax',
|
||||
195 => 'audio/x-ms-wma',
|
||||
@ -301,6 +307,7 @@ function file_default_mimetype_mapping() {
|
||||
261 => 'image/vnd.djvu',
|
||||
262 => 'image/vnd.microsoft.icon',
|
||||
263 => 'image/vnd.wap.wbmp',
|
||||
355 => 'image/webp',
|
||||
264 => 'image/x-cmu-raster',
|
||||
265 => 'image/x-coreldraw',
|
||||
266 => 'image/x-coreldrawpattern',
|
||||
@ -337,6 +344,7 @@ function file_default_mimetype_mapping() {
|
||||
297 => 'text/vnd.sun.j2me.app-descriptor',
|
||||
298 => 'text/vnd.wap.wml',
|
||||
299 => 'text/vnd.wap.wmlscript',
|
||||
358 => 'text/vtt',
|
||||
300 => 'text/x-bibtex',
|
||||
301 => 'text/x-boo',
|
||||
302 => 'text/x-c++hdr',
|
||||
@ -371,9 +379,11 @@ function file_default_mimetype_mapping() {
|
||||
331 => 'video/ogg',
|
||||
332 => 'video/quicktime',
|
||||
333 => 'video/vnd.mpegurl',
|
||||
357 => 'video/webm',
|
||||
347 => 'video/x-flv',
|
||||
334 => 'video/x-la-asf',
|
||||
348 => 'video/x-m4v',
|
||||
353 => 'video/x-matroska',
|
||||
335 => 'video/x-mng',
|
||||
336 => 'video/x-ms-asf',
|
||||
337 => 'video/x-ms-wm',
|
||||
@ -854,6 +864,16 @@ function file_default_mimetype_mapping() {
|
||||
'f4b' => 346,
|
||||
'flv' => 347,
|
||||
'm4v' => 348,
|
||||
'azw' => 349,
|
||||
'epub' => 350,
|
||||
'mobi' => 351,
|
||||
'prc' => 352,
|
||||
'mkv' => 353,
|
||||
'mka' => 354,
|
||||
'webp' => 355,
|
||||
'weba' => 356,
|
||||
'webm' => 357,
|
||||
'vtt' => 358,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -406,10 +406,20 @@ class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator {
|
||||
*/
|
||||
function __construct($path) {
|
||||
parent::__construct($path);
|
||||
$this->skipdots();
|
||||
}
|
||||
|
||||
function rewind() {
|
||||
parent::rewind();
|
||||
$this->skipdots();
|
||||
}
|
||||
|
||||
function next() {
|
||||
parent::next();
|
||||
$this->skipdots();
|
||||
}
|
||||
|
||||
protected function skipdots() {
|
||||
while ($this->isDot()) {
|
||||
parent::next();
|
||||
}
|
||||
|
@ -82,11 +82,11 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh
|
||||
if (!$list) {
|
||||
$list = array();
|
||||
}
|
||||
foreach ($list as $item){
|
||||
foreach ($list as $item) {
|
||||
if ($item == '.' || $item == '..') {
|
||||
continue;
|
||||
}
|
||||
if (@ftp_chdir($this->connection, $item)){
|
||||
if (@ftp_chdir($this->connection, $item)) {
|
||||
ftp_cdup($this->connection);
|
||||
$this->removeDirectory(ftp_pwd($this->connection) . '/' . $item);
|
||||
}
|
||||
@ -122,7 +122,7 @@ class FileTransferFTPExtension extends FileTransferFTP implements FileTransferCh
|
||||
|
||||
function chmodJailed($path, $mode, $recursive) {
|
||||
if (!ftp_chmod($this->connection, $mode, $path)) {
|
||||
throw new FileTransferException("Unable to set permissions on %file", NULL, array ('%file' => $path));
|
||||
throw new FileTransferException("Unable to set permissions on %file", NULL, array('%file' => $path));
|
||||
}
|
||||
if ($this->isDirectory($path) && $recursive) {
|
||||
$filelist = @ftp_nlist($this->connection, $path);
|
||||
|
@ -72,7 +72,8 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new FileTransferException('Cannot check @path.', NULL, array('@path' => $path));
|
||||
}
|
||||
}
|
||||
@ -85,7 +86,8 @@ class FileTransferSSH extends FileTransfer implements FileTransferChmodInterface
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new FileTransferException('Cannot check @path.', NULL, array('@path' => $path));
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,9 @@
|
||||
* reference the form builder function using \@see. For examples, of this see
|
||||
* system_modules_uninstall() or user_pass(), the latter of which has the
|
||||
* following in its doxygen documentation:
|
||||
*
|
||||
* \@ingroup forms
|
||||
* \@see user_pass_validate().
|
||||
* \@see user_pass_submit().
|
||||
* - \@ingroup forms
|
||||
* - \@see user_pass_validate()
|
||||
* - \@see user_pass_submit()
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -168,6 +167,12 @@ function drupal_get_form($form_id) {
|
||||
* processed.
|
||||
* - base_form_id: Identification for a base form, as declared in a
|
||||
* hook_forms() implementation.
|
||||
* - immutable: If this flag is set to TRUE, a new form build id is
|
||||
* generated when the form is loaded from the cache. If it is subsequently
|
||||
* saved to the cache again, it will have another cache id and therefore
|
||||
* the original form and form-state will remain unaltered. This is
|
||||
* important when page caching is enabled in order to prevent form state
|
||||
* from leaking between anonymous users.
|
||||
* - rebuild_info: Internal. Similar to 'build_info', but pertaining to
|
||||
* drupal_rebuild_form().
|
||||
* - rebuild: Normally, after the entire form processing is completed and
|
||||
@ -235,6 +240,12 @@ function drupal_get_form($form_id) {
|
||||
* likely to occur during Ajax operations.
|
||||
* - programmed: If TRUE, the form was submitted programmatically, usually
|
||||
* invoked via drupal_form_submit(). Defaults to FALSE.
|
||||
* - programmed_bypass_access_check: If TRUE, programmatic form submissions
|
||||
* are processed without taking #access into account. Set this to FALSE
|
||||
* when submitting a form programmatically with values that may have been
|
||||
* input by the user executing the current request; this will cause #access
|
||||
* to be respected as it would on a normal form submission. Defaults to
|
||||
* TRUE.
|
||||
* - process_input: Boolean flag. TRUE signifies correct form submission.
|
||||
* This is always TRUE for programmed forms coming from drupal_form_submit()
|
||||
* (see 'programmed' key), or if the form_id coming from the $_POST data is
|
||||
@ -402,6 +413,7 @@ function form_state_defaults() {
|
||||
'submitted' => FALSE,
|
||||
'executed' => FALSE,
|
||||
'programmed' => FALSE,
|
||||
'programmed_bypass_access_check' => TRUE,
|
||||
'cache'=> FALSE,
|
||||
'method' => 'post',
|
||||
'groups' => array(),
|
||||
@ -452,17 +464,25 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
|
||||
$form = drupal_retrieve_form($form_id, $form_state);
|
||||
|
||||
// If only parts of the form will be returned to the browser (e.g., Ajax or
|
||||
// RIA clients), re-use the old #build_id to not require client-side code to
|
||||
// manually update the hidden 'build_id' input element.
|
||||
// RIA clients), or if the form already had a new build ID regenerated when it
|
||||
// was retrieved from the form cache, reuse the existing #build_id.
|
||||
// Otherwise, a new #build_id is generated, to not clobber the previous
|
||||
// build's data in the form cache; also allowing the user to go back to an
|
||||
// earlier build, make changes, and re-submit.
|
||||
// @see drupal_prepare_form()
|
||||
if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) {
|
||||
$enforce_old_build_id = isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id']);
|
||||
$old_form_is_mutable_copy = isset($old_form['#build_id_old']);
|
||||
if ($enforce_old_build_id || $old_form_is_mutable_copy) {
|
||||
$form['#build_id'] = $old_form['#build_id'];
|
||||
if ($old_form_is_mutable_copy) {
|
||||
$form['#build_id_old'] = $old_form['#build_id_old'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
|
||||
if (isset($old_form['#build_id'])) {
|
||||
$form['#build_id_old'] = $old_form['#build_id'];
|
||||
}
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
}
|
||||
|
||||
// #action defaults to request_uri(), but in case of Ajax and other partial
|
||||
@ -516,6 +536,15 @@ function form_get_cache($form_build_id, &$form_state) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generate a new #build_id if the cached form was rendered on a cacheable
|
||||
// page.
|
||||
if (!empty($form_state['build_info']['immutable'])) {
|
||||
$form['#build_id_old'] = $form['#build_id'];
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
$form['form_build_id']['#value'] = $form['#build_id'];
|
||||
$form['form_build_id']['#id'] = $form['#build_id'];
|
||||
unset($form_state['build_info']['immutable']);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
@ -528,15 +557,28 @@ function form_set_cache($form_build_id, $form, $form_state) {
|
||||
// 6 hours cache life time for forms should be plenty.
|
||||
$expire = 21600;
|
||||
|
||||
// Ensure that the form build_id embedded in the form structure is the same as
|
||||
// the one passed in as a parameter. This is an additional safety measure to
|
||||
// prevent legacy code operating directly with form_get_cache and
|
||||
// form_set_cache from accidentally overwriting immutable form state.
|
||||
if ($form['#build_id'] != $form_build_id) {
|
||||
watchdog('form', 'Form build-id mismatch detected while attempting to store a form in the cache.', array(), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache form structure.
|
||||
if (isset($form)) {
|
||||
if ($GLOBALS['user']->uid) {
|
||||
$form['#cache_token'] = drupal_get_token();
|
||||
}
|
||||
unset($form['#build_id_old']);
|
||||
cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire);
|
||||
}
|
||||
|
||||
// Cache form state.
|
||||
if (variable_get('cache', 0) && drupal_page_is_cacheable()) {
|
||||
$form_state['build_info']['immutable'] = TRUE;
|
||||
}
|
||||
if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) {
|
||||
cache_set('form_state_' . $form_build_id, $data, 'cache_form', REQUEST_TIME + $expire);
|
||||
}
|
||||
@ -727,8 +769,9 @@ function drupal_retrieve_form($form_id, &$form_state) {
|
||||
// Record the filepath of the include file containing the original form, so
|
||||
// the form builder callbacks can be loaded when the form is being rebuilt
|
||||
// from cache on a different path (such as 'system/ajax'). See
|
||||
// form_get_cache().
|
||||
// $menu_get_item() is not available during installation.
|
||||
// form_get_cache(). Don't do this in maintenance mode as Drupal may not be
|
||||
// fully bootstrapped (i.e. during installation) in which case
|
||||
// menu_get_item() is not available.
|
||||
if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
|
||||
$item = menu_get_item();
|
||||
if (!empty($item['include_file'])) {
|
||||
@ -895,7 +938,7 @@ function drupal_process_form($form_id, &$form, &$form_state) {
|
||||
// after the batch is processed.
|
||||
}
|
||||
|
||||
// Set a flag to indicate the the form has been processed and executed.
|
||||
// Set a flag to indicate that the form has been processed and executed.
|
||||
$form_state['executed'] = TRUE;
|
||||
|
||||
// Redirect the form based on values in $form_state.
|
||||
@ -976,7 +1019,7 @@ function drupal_prepare_form($form_id, &$form, &$form_state) {
|
||||
// @see drupal_build_form()
|
||||
// @see drupal_rebuild_form()
|
||||
if (!isset($form['#build_id'])) {
|
||||
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
|
||||
$form['#build_id'] = 'form-' . drupal_random_key();
|
||||
}
|
||||
$form['form_build_id'] = array(
|
||||
'#type' => 'hidden',
|
||||
@ -1128,6 +1171,12 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
|
||||
|
||||
// Setting this error will cause the form to fail validation.
|
||||
form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url)));
|
||||
|
||||
// Stop here and don't run any further validation handlers, because they
|
||||
// could invoke non-safe operations which opens the door for CSRF
|
||||
// vulnerabilities.
|
||||
$validated_forms[$form_id] = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1978,7 +2027,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
|
||||
// #access=FALSE on an element usually allow access for some users, so forms
|
||||
// submitted with drupal_form_submit() may bypass access restriction and be
|
||||
// treated as high-privilege users instead.
|
||||
$process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
|
||||
$process_input = empty($element['#disabled']) && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
|
||||
|
||||
// Set the element's #value property.
|
||||
if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
|
||||
@ -2402,6 +2451,17 @@ function form_type_password_confirm_value($element, $input = FALSE) {
|
||||
$element += array('#default_value' => array());
|
||||
return $element['#default_value'] + array('pass1' => '', 'pass2' => '');
|
||||
}
|
||||
$value = array('pass1' => '', 'pass2' => '');
|
||||
// Throw out all invalid array keys; we only allow pass1 and pass2.
|
||||
foreach ($value as $allowed_key => $default) {
|
||||
// These should be strings, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions. Any nested array values
|
||||
// are ignored.
|
||||
if (isset($input[$allowed_key]) && is_scalar($input[$allowed_key])) {
|
||||
$value[$allowed_key] = (string) $input[$allowed_key];
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2445,6 +2505,27 @@ function form_type_select_value($element, $input = FALSE) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value for a textarea form element.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element whose value is being populated.
|
||||
* @param mixed $input
|
||||
* The incoming input to populate the form element. If this is FALSE,
|
||||
* the element's default value should be returned.
|
||||
*
|
||||
* @return string
|
||||
* The data that will appear in the $element_state['values'] collection
|
||||
* for this element. Return nothing to use the default.
|
||||
*/
|
||||
function form_type_textarea_value($element, $input = FALSE) {
|
||||
if ($input !== FALSE) {
|
||||
// This should be a string, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions.
|
||||
return is_scalar($input) ? (string) $input : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value for a textfield form element.
|
||||
*
|
||||
@ -2460,9 +2541,12 @@ function form_type_select_value($element, $input = FALSE) {
|
||||
*/
|
||||
function form_type_textfield_value($element, $input = FALSE) {
|
||||
if ($input !== FALSE && $input !== NULL) {
|
||||
// Equate $input to the form value to ensure it's marked for
|
||||
// validation.
|
||||
return str_replace(array("\r", "\n"), '', $input);
|
||||
// This should be a string, but allow other scalars since they might be
|
||||
// valid input in programmatic form submissions.
|
||||
if (!is_scalar($input)) {
|
||||
$input = '';
|
||||
}
|
||||
return str_replace(array("\r", "\n"), '', (string) $input);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2650,17 +2734,43 @@ function theme_select($variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a select form element's options array into HTML.
|
||||
* Converts an array of options into HTML, for use in select list form elements.
|
||||
*
|
||||
* @param $element
|
||||
* An associative array containing the properties of the element.
|
||||
* @param $choices
|
||||
* Mixed: Either an associative array of items to list as choices, or an
|
||||
* object with an 'option' member that is an associative array. This
|
||||
* parameter is only used internally and should not be passed.
|
||||
* This function calls itself recursively to obtain the values for each optgroup
|
||||
* within the list of options and when the function encounters an object with
|
||||
* an 'options' property inside $element['#options'].
|
||||
*
|
||||
* @return
|
||||
* An HTML string of options for the select form element.
|
||||
* @param array $element
|
||||
* An associative array containing the following key-value pairs:
|
||||
* - #multiple: Optional Boolean indicating if the user may select more than
|
||||
* one item.
|
||||
* - #options: An associative array of options to render as HTML. Each array
|
||||
* value can be a string, an array, or an object with an 'option' property:
|
||||
* - A string or integer key whose value is a translated string is
|
||||
* interpreted as a single HTML option element. Do not use placeholders
|
||||
* that sanitize data: doing so will lead to double-escaping. Note that
|
||||
* the key will be visible in the HTML and could be modified by malicious
|
||||
* users, so don't put sensitive information in it.
|
||||
* - A translated string key whose value is an array indicates a group of
|
||||
* options. The translated string is used as the label attribute for the
|
||||
* optgroup. Do not use placeholders to sanitize data: doing so will lead
|
||||
* to double-escaping. The array should contain the options you wish to
|
||||
* group and should follow the syntax of $element['#options'].
|
||||
* - If the function encounters a string or integer key whose value is an
|
||||
* object with an 'option' property, the key is ignored, the contents of
|
||||
* the option property are interpreted as $element['#options'], and the
|
||||
* resulting HTML is added to the output.
|
||||
* - #value: Optional integer, string, or array representing which option(s)
|
||||
* to pre-select when the list is first displayed. The integer or string
|
||||
* must match the key of an option in the '#options' list. If '#multiple' is
|
||||
* TRUE, this can be an array of integers or strings.
|
||||
* @param array|null $choices
|
||||
* (optional) Either an associative array of options in the same format as
|
||||
* $element['#options'] above, or NULL. This parameter is only used internally
|
||||
* and is not intended to be passed in to the initial function call.
|
||||
*
|
||||
* @return string
|
||||
* An HTML string of options and optgroups for use in a select form element.
|
||||
*/
|
||||
function form_select_options($element, $choices = NULL) {
|
||||
if (!isset($choices)) {
|
||||
@ -2673,7 +2783,7 @@ function form_select_options($element, $choices = NULL) {
|
||||
$options = '';
|
||||
foreach ($choices as $key => $choice) {
|
||||
if (is_array($choice)) {
|
||||
$options .= '<optgroup label="' . $key . '">';
|
||||
$options .= '<optgroup label="' . check_plain($key) . '">';
|
||||
$options .= form_select_options($element, $choice);
|
||||
$options .= '</optgroup>';
|
||||
}
|
||||
@ -3051,14 +3161,12 @@ function form_process_radios($element) {
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - element: An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #return_value, #description, #required,
|
||||
* #attributes, #checked.
|
||||
* Properties used: #id, #name, #attributes, #checked, #return_value.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_checkbox($variables) {
|
||||
$element = $variables['element'];
|
||||
$t = get_t();
|
||||
$element['#attributes']['type'] = 'checkbox';
|
||||
element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
|
||||
|
||||
@ -3238,6 +3346,8 @@ function form_process_container($element, &$form_state) {
|
||||
*/
|
||||
function theme_container($variables) {
|
||||
$element = $variables['element'];
|
||||
// Ensure #attributes is set.
|
||||
$element += array('#attributes' => array());
|
||||
|
||||
// Special handling for form elements.
|
||||
if (isset($element['#array_parents'])) {
|
||||
@ -3662,35 +3772,6 @@ function form_pre_render_fieldset($element) {
|
||||
/**
|
||||
* Creates a group formatted as vertical tabs.
|
||||
*
|
||||
* Note that autocomplete callbacks should include special handling as the
|
||||
* user's input may contain forward slashes. If the user-submitted string has a
|
||||
* '/' in the text that is sent in the autocomplete request, the menu system
|
||||
* will split the text and pass it to the callback as multiple arguments.
|
||||
*
|
||||
* Suppose your autocomplete path in the menu system is 'mymodule_autocomplete.'
|
||||
* In your form you have:
|
||||
* @code
|
||||
* '#autocomplete_path' => 'mymodule_autocomplete/' . $some_key . '/' . $some_id,
|
||||
* @endcode
|
||||
* The user types in "keywords" so the full path called is:
|
||||
* 'mymodule_autocomplete/$some_key/$some_id/keywords'
|
||||
*
|
||||
* You should include code similar to the following to handle slashes in the
|
||||
* input:
|
||||
* @code
|
||||
* function mymodule_autocomplete_callback($arg1, $arg2, $keywords) {
|
||||
* $args = func_get_args();
|
||||
* // We need to remove $arg1 and $arg2 from the beginning of the array so we
|
||||
* // are left with the keywords.
|
||||
* array_shift($args);
|
||||
* array_shift($args);
|
||||
* // We store the user's original input in $keywords, including any slashes.
|
||||
* $keywords = implode('/', $args);
|
||||
*
|
||||
* // Your code here.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param $element
|
||||
* An associative array containing the properties and children of the
|
||||
* fieldset.
|
||||
@ -4039,8 +4120,6 @@ function theme_file($variables) {
|
||||
*/
|
||||
function theme_form_element($variables) {
|
||||
$element = &$variables['element'];
|
||||
// This is also used in the installer, pre-database setup.
|
||||
$t = get_t();
|
||||
|
||||
// This function is invoked as theme wrapper, but the rendered form element
|
||||
// may not necessarily have been processed by form_builder().
|
||||
@ -4199,7 +4278,7 @@ function _form_set_class(&$element, $class = array()) {
|
||||
if (!empty($element['#required'])) {
|
||||
$element['#attributes']['class'][] = 'required';
|
||||
}
|
||||
if (isset($element['#parents']) && form_get_error($element) !== NULL) {
|
||||
if (isset($element['#parents']) && form_get_error($element) !== NULL && !empty($element['#validated'])) {
|
||||
$element['#attributes']['class'][] = 'error';
|
||||
}
|
||||
}
|
||||
@ -4276,7 +4355,7 @@ function element_validate_number($element, &$form_state) {
|
||||
* returns any user input in the 'results' or 'message' keys of $context,
|
||||
* it must also sanitize them first.
|
||||
*
|
||||
* Sample batch operations:
|
||||
* Sample callback_batch_operation():
|
||||
* @code
|
||||
* // Simple and artificial: load a node of a given type for a given user
|
||||
* function my_function_1($uid, $type, &$context) {
|
||||
@ -4328,7 +4407,7 @@ function element_validate_number($element, &$form_state) {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Sample 'finished' callback:
|
||||
* Sample callback_batch_finished():
|
||||
* @code
|
||||
* function batch_test_finished($success, $results, $operations) {
|
||||
* // The 'success' parameter means no fatal PHP errors were detected. All
|
||||
@ -4367,12 +4446,14 @@ function element_validate_number($element, &$form_state) {
|
||||
* @param $batch_definition
|
||||
* An associative array defining the batch, with the following elements (all
|
||||
* are optional except as noted):
|
||||
* - operations: (required) Array of function calls to be performed.
|
||||
* - operations: (required) Array of operations to be performed, where each
|
||||
* item is an array consisting of the name of an implementation of
|
||||
* callback_batch_operation() and an array of parameter.
|
||||
* Example:
|
||||
* @code
|
||||
* array(
|
||||
* array('my_function_1', array($arg1)),
|
||||
* array('my_function_2', array($arg2_1, $arg2_2)),
|
||||
* array('callback_batch_operation_1', array($arg1)),
|
||||
* array('callback_batch_operation_2', array($arg2_1, $arg2_2)),
|
||||
* )
|
||||
* @endcode
|
||||
* - title: A safe, translated string to use as the title for the progress
|
||||
@ -4384,10 +4465,10 @@ function element_validate_number($element, &$form_state) {
|
||||
* @elapsed. Defaults to t('Completed @current of @total.').
|
||||
* - error_message: Message displayed if an error occurred while processing
|
||||
* the batch. Defaults to t('An error has occurred.').
|
||||
* - finished: Name of a function to be executed after the batch has
|
||||
* completed. This should be used to perform any result massaging that may
|
||||
* be needed, and possibly save data in $_SESSION for display after final
|
||||
* page redirection.
|
||||
* - finished: Name of an implementation of callback_batch_finished(). This is
|
||||
* executed after the batch has completed. This should be used to perform
|
||||
* any result massaging that may be needed, and possibly save data in
|
||||
* $_SESSION for display after final page redirection.
|
||||
* - file: Path to the file containing the definitions of the 'operations' and
|
||||
* 'finished' functions, for instance if they don't reside in the main
|
||||
* .module file. The path should be relative to base_path(), and thus should
|
||||
|
@ -233,11 +233,11 @@ function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NUL
|
||||
* @param $image
|
||||
* An image object returned by image_load().
|
||||
* @param $width
|
||||
* The target width, in pixels. This value is omitted then the scaling will
|
||||
* based only on the height value.
|
||||
* The target width, in pixels. If this value is NULL then the scaling will
|
||||
* be based only on the height value.
|
||||
* @param $height
|
||||
* The target height, in pixels. This value is omitted then the scaling will
|
||||
* based only on the width value.
|
||||
* The target height, in pixels. If this value is NULL then the scaling will
|
||||
* be based only on the width value.
|
||||
* @param $upscale
|
||||
* Boolean indicating that files smaller than the dimensions will be scaled
|
||||
* up. This generally results in a low quality image.
|
||||
|
@ -692,6 +692,21 @@ function install_full_redirect_url($install_state) {
|
||||
*/
|
||||
function install_display_output($output, $install_state) {
|
||||
drupal_page_header();
|
||||
|
||||
// Prevent install.php from being indexed when installed in a sub folder.
|
||||
// robots.txt rules are not read if the site is within domain.com/subfolder
|
||||
// resulting in /subfolder/install.php being found through search engines.
|
||||
// When settings.php is writeable this can be used via an external database
|
||||
// leading a malicious user to gain php access to the server.
|
||||
$noindex_meta_tag = array(
|
||||
'#tag' => 'meta',
|
||||
'#attributes' => array(
|
||||
'name' => 'robots',
|
||||
'content' => 'noindex, nofollow',
|
||||
),
|
||||
);
|
||||
drupal_add_html_head($noindex_meta_tag, 'install_meta_robots');
|
||||
|
||||
// Only show the task list if there is an active task; otherwise, the page
|
||||
// request has ended before tasks have even been started, so there is nothing
|
||||
// meaningful to show.
|
||||
@ -766,6 +781,15 @@ function install_system_module(&$install_state) {
|
||||
// Install system.module.
|
||||
drupal_install_system();
|
||||
|
||||
// Call file_ensure_htaccess() to ensure that all of Drupal's standard
|
||||
// directories (e.g., the public and private files directories) have
|
||||
// appropriate .htaccess files. These directories will have already been
|
||||
// created by this point in the installer, since Drupal creates them during
|
||||
// the install_verify_requirements() task. Note that we cannot call
|
||||
// file_ensure_htaccess() any earlier than this, since it relies on
|
||||
// system.module in order to work.
|
||||
file_ensure_htaccess();
|
||||
|
||||
// Enable the user module so that sessions can be recorded during the
|
||||
// upcoming bootstrap step.
|
||||
module_enable(array('user'), FALSE);
|
||||
@ -981,7 +1005,7 @@ function install_settings_form_submit($form, &$form_state) {
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['drupal_hash_salt'] = array(
|
||||
'value' => drupal_hash_base64(drupal_random_bytes(55)),
|
||||
'value' => drupal_random_key(),
|
||||
'required' => TRUE,
|
||||
);
|
||||
drupal_rewrite_settings($settings);
|
||||
@ -1041,7 +1065,21 @@ function install_select_profile(&$install_state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects an installation profile from a list or from a $_POST submission.
|
||||
* Selects an installation profile.
|
||||
*
|
||||
* A profile will be selected if:
|
||||
* - Only one profile is available,
|
||||
* - A profile was submitted through $_POST,
|
||||
* - Exactly one of the profiles is marked as "exclusive".
|
||||
* If multiple profiles are marked as "exclusive" then no profile will be
|
||||
* selected.
|
||||
*
|
||||
* @param array $profiles
|
||||
* An associative array of profiles with the machine-readable names as keys.
|
||||
*
|
||||
* @return
|
||||
* The machine-readable name of the selected profile or NULL if no profile was
|
||||
* selected.
|
||||
*/
|
||||
function _install_select_profile($profiles) {
|
||||
if (sizeof($profiles) == 0) {
|
||||
@ -1061,6 +1099,23 @@ function _install_select_profile($profiles) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for a profile marked as "exclusive" and ensure that only one
|
||||
// profile is marked as such.
|
||||
$exclusive_profile = NULL;
|
||||
foreach ($profiles as $profile) {
|
||||
$profile_info = install_profile_info($profile->name);
|
||||
if (!empty($profile_info['exclusive'])) {
|
||||
if (empty($exclusive_profile)) {
|
||||
$exclusive_profile = $profile->name;
|
||||
}
|
||||
else {
|
||||
// We found a second "exclusive" profile. There's no way to choose
|
||||
// between them, so we ignore the property.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $exclusive_profile;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,7 +420,7 @@ abstract class DatabaseTasks {
|
||||
}
|
||||
}
|
||||
if (!empty($message)) {
|
||||
$message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
|
||||
$message = 'Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider.' . $message;
|
||||
throw new DatabaseTaskException($message);
|
||||
}
|
||||
}
|
||||
@ -653,6 +653,13 @@ function drupal_rewrite_settings($settings = array(), $prefix = '') {
|
||||
if ($fp && fwrite($fp, $buffer) === FALSE) {
|
||||
throw new Exception(st('Failed to modify %settings. Verify the file permissions.', array('%settings' => $settings_file)));
|
||||
}
|
||||
else {
|
||||
// The existing settings.php file might have been included already. In
|
||||
// case an opcode cache is enabled, the rewritten contents of the file
|
||||
// will not be reflected in this process. Ensure to invalidate the file
|
||||
// in case an opcode cache is enabled.
|
||||
drupal_clear_opcode_cache(DRUPAL_ROOT . '/' . $settings_file);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Exception(st('Failed to open %settings. Verify the file permissions.', array('%settings' => $default_settings)));
|
||||
@ -741,20 +748,27 @@ function drupal_install_system() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a given list of modules.
|
||||
* Uninstalls a given list of disabled modules.
|
||||
*
|
||||
* @param $module_list
|
||||
* The modules to uninstall.
|
||||
* @param $uninstall_dependents
|
||||
* If TRUE, the function will check that all modules which depend on the
|
||||
* passed-in module list either are already uninstalled or contained in the
|
||||
* list, and it will ensure that the modules are uninstalled in the correct
|
||||
* order. This incurs a significant performance cost, so use FALSE if you
|
||||
* know $module_list is already complete and in the correct order.
|
||||
* @param array $module_list
|
||||
* The modules to uninstall. It is the caller's responsibility to ensure that
|
||||
* all modules in this list have already been disabled before this function
|
||||
* is called.
|
||||
* @param bool $uninstall_dependents
|
||||
* (optional) If TRUE, the function will check that all modules which depend
|
||||
* on the passed-in module list either are already uninstalled or contained in
|
||||
* the list, and it will ensure that the modules are uninstalled in the
|
||||
* correct order. This incurs a significant performance cost, so use FALSE if
|
||||
* you know $module_list is already complete and in the correct order.
|
||||
* Defaults to TRUE.
|
||||
*
|
||||
* @return
|
||||
* FALSE if one or more dependent modules are missing from the list, TRUE
|
||||
* otherwise.
|
||||
* @return bool
|
||||
* Returns TRUE if the operation succeeds or FALSE if it aborts due to an
|
||||
* unsafe condition, namely, $uninstall_dependents is TRUE and a module in
|
||||
* $module_list has dependents which are not already uninstalled and not also
|
||||
* included in $module_list).
|
||||
*
|
||||
* @see module_disable()
|
||||
*/
|
||||
function drupal_uninstall_modules($module_list = array(), $uninstall_dependents = TRUE) {
|
||||
if ($uninstall_dependents) {
|
||||
@ -766,7 +780,7 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
|
||||
$profile = drupal_get_profile();
|
||||
while (list($module) = each($module_list)) {
|
||||
if (!isset($module_data[$module]) || drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED) {
|
||||
// This module doesn't exist or is already uninstalled, skip it.
|
||||
// This module doesn't exist or is already uninstalled. Skip it.
|
||||
unset($module_list[$module]);
|
||||
continue;
|
||||
}
|
||||
@ -799,7 +813,7 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
|
||||
}
|
||||
|
||||
if (!empty($module_list)) {
|
||||
// Call hook_module_uninstall to let other modules act
|
||||
// Let other modules react.
|
||||
module_invoke_all('modules_uninstalled', $module_list);
|
||||
}
|
||||
|
||||
@ -1127,7 +1141,6 @@ function st($string, array $args = array(), array $options = array()) {
|
||||
}
|
||||
}
|
||||
|
||||
require_once DRUPAL_ROOT . '/includes/theme.inc';
|
||||
// Transform arguments before inserting them
|
||||
foreach ($args as $key => $value) {
|
||||
switch ($key[0]) {
|
||||
@ -1244,6 +1257,12 @@ function drupal_check_module($module) {
|
||||
* - distribution_name: The name of the Drupal distribution that is being
|
||||
* installed, to be shown throughout the installation process. Defaults to
|
||||
* 'Drupal'.
|
||||
* - exclusive: If the install profile is intended to be the only eligible
|
||||
* choice in a distribution, setting exclusive = TRUE will auto-select it
|
||||
* during installation, and the install profile selection screen will be
|
||||
* skipped. If more than one profile is found where exclusive = TRUE then
|
||||
* this property will have no effect and the profile selection screen will
|
||||
* be shown as normal with all available profiles shown.
|
||||
*
|
||||
* Note that this function does an expensive file system scan to get info file
|
||||
* information for dependencies. If you only need information from the info
|
||||
|
@ -53,6 +53,7 @@ function _country_get_predefined_list() {
|
||||
'BM' => $t('Bermuda'),
|
||||
'BN' => $t('Brunei'),
|
||||
'BO' => $t('Bolivia'),
|
||||
'BQ' => $t('Caribbean Netherlands'),
|
||||
'BR' => $t('Brazil'),
|
||||
'BS' => $t('Bahamas'),
|
||||
'BT' => $t('Bhutan'),
|
||||
@ -74,8 +75,8 @@ function _country_get_predefined_list() {
|
||||
'CO' => $t('Colombia'),
|
||||
'CR' => $t('Costa Rica'),
|
||||
'CU' => $t('Cuba'),
|
||||
'CW' => $t('Curaçao'),
|
||||
'CV' => $t('Cape Verde'),
|
||||
'CW' => $t('Curaçao'),
|
||||
'CX' => $t('Christmas Island'),
|
||||
'CY' => $t('Cyprus'),
|
||||
'CZ' => $t('Czech Republic'),
|
||||
@ -230,8 +231,10 @@ function _country_get_predefined_list() {
|
||||
'SN' => $t('Senegal'),
|
||||
'SO' => $t('Somalia'),
|
||||
'SR' => $t('Suriname'),
|
||||
'SS' => $t('South Sudan'),
|
||||
'ST' => $t('Sao Tome and Principe'),
|
||||
'SV' => $t('El Salvador'),
|
||||
'SX' => $t('Sint Maarten'),
|
||||
'SY' => $t('Syria'),
|
||||
'SZ' => $t('Swaziland'),
|
||||
'TC' => $t('Turks and Caicos Islands'),
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Multiple language handling functionality.
|
||||
* Language Negotiation API.
|
||||
*
|
||||
* @see http://drupal.org/node/1497272
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -11,7 +13,95 @@
|
||||
define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default');
|
||||
|
||||
/**
|
||||
* Return all the defined language types.
|
||||
* @defgroup language_negotiation Language Negotiation API functionality
|
||||
* @{
|
||||
* Functions to customize the language types and the negotiation process.
|
||||
*
|
||||
* The language negotiation API is based on two major concepts:
|
||||
* - Language types: types of translatable data (the types of data that a user
|
||||
* can view or request).
|
||||
* - Language negotiation providers: functions for determining which language to
|
||||
* use to present a particular piece of data to the user.
|
||||
* Both language types and language negotiation providers are customizable.
|
||||
*
|
||||
* Drupal defines three built-in language types:
|
||||
* - Interface language: The page's main language, used to present translated
|
||||
* user interface elements such as titles, labels, help text, and messages.
|
||||
* - Content language: The language used to present content that is available
|
||||
* in more than one language (see
|
||||
* @link field_language Field Language API @endlink for details).
|
||||
* - URL language: The language associated with URLs. When generating a URL,
|
||||
* this value will be used by url() as a default if no explicit preference is
|
||||
* provided.
|
||||
* Modules can define additional language types through
|
||||
* hook_language_types_info(), and alter existing language type definitions
|
||||
* through hook_language_types_info_alter().
|
||||
*
|
||||
* Language types may be configurable or fixed. The language negotiation
|
||||
* providers associated with a configurable language type can be explicitly
|
||||
* set through the user interface. A fixed language type has predetermined
|
||||
* (module-defined) language negotiation settings and, thus, does not appear in
|
||||
* the configuration page. Here is a code snippet that makes the content
|
||||
* language (which by default inherits the interface language's values)
|
||||
* configurable:
|
||||
* @code
|
||||
* function mymodule_language_types_info_alter(&$language_types) {
|
||||
* unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Every language type can have a different set of language negotiation
|
||||
* providers assigned to it. Different language types often share the same
|
||||
* language negotiation settings, but they can have independent settings if
|
||||
* needed. If two language types are configured the same way, their language
|
||||
* switcher configuration will be functionally identical and the same settings
|
||||
* will act on both language types.
|
||||
*
|
||||
* Drupal defines the following built-in language negotiation providers:
|
||||
* - URL: Determine the language from the URL (path prefix or domain).
|
||||
* - Session: Determine the language from a request/session parameter.
|
||||
* - User: Follow the user's language preference.
|
||||
* - Browser: Determine the language from the browser's language settings.
|
||||
* - Default language: Use the default site language.
|
||||
* Language negotiation providers are simple callback functions that implement a
|
||||
* particular logic to return a language code. For instance, the URL provider
|
||||
* searches for a valid path prefix or domain name in the current request URL.
|
||||
* If a language negotiation provider does not return a valid language code, the
|
||||
* next provider associated to the language type (based on provider weight) is
|
||||
* invoked.
|
||||
*
|
||||
* Modules can define additional language negotiation providers through
|
||||
* hook_language_negotiation_info(), and alter existing providers through
|
||||
* hook_language_negotiation_info_alter(). Here is an example snippet that lets
|
||||
* path prefixes be ignored for administrative paths:
|
||||
* @code
|
||||
* function mymodule_language_negotiation_info_alter(&$negotiation_info) {
|
||||
* // Replace the core function with our own function.
|
||||
* module_load_include('language', 'inc', 'language.negotiation');
|
||||
* $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['language'] = 'mymodule_from_url';
|
||||
* $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module';
|
||||
* }
|
||||
*
|
||||
* function mymodule_from_url($languages) {
|
||||
* // Use the core URL language negotiation provider to get a valid language
|
||||
* // code.
|
||||
* module_load_include('language', 'inc', 'language.negotiation');
|
||||
* $langcode = language_from_url($languages);
|
||||
*
|
||||
* // If we are on an administrative path, override with the default language.
|
||||
* if (isset($_GET['q']) && strtok($_GET['q'], '/') == 'admin') {
|
||||
* return language_default()->langcode;
|
||||
* }
|
||||
* return $langcode;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* For more information, see
|
||||
* @link http://drupal.org/node/1497272 Language Negotiation API @endlink
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns all the defined language types.
|
||||
*
|
||||
* @return
|
||||
* An array of language type names. The name will be used as the global
|
||||
@ -30,11 +120,11 @@ function language_types_info() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only the configurable language types.
|
||||
* Returns only the configurable language types.
|
||||
*
|
||||
* A language type maybe configurable or fixed. A fixed language type is a type
|
||||
* whose negotiation values are unchangeable and defined while defining the
|
||||
* language type itself.
|
||||
* whose language negotiation providers are module-defined and not altered
|
||||
* through the user interface.
|
||||
*
|
||||
* @param $stored
|
||||
* Optional. By default retrieves values from the 'language_types' variable to
|
||||
@ -68,7 +158,7 @@ function language_types_configurable($stored = TRUE) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the given language types.
|
||||
* Disables the given language types.
|
||||
*
|
||||
* @param $types
|
||||
* An array of language types.
|
||||
@ -122,16 +212,17 @@ function language_types_set() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a language provider is enabled.
|
||||
* Checks whether a language negotiation provider is enabled for a language type.
|
||||
*
|
||||
* This has two possible behaviors:
|
||||
* - If $provider_id is given return its ID if enabled, FALSE otherwise.
|
||||
* - If no ID is passed the first enabled language provider is returned.
|
||||
* - If no ID is passed the first enabled language negotiation provider is
|
||||
* returned.
|
||||
*
|
||||
* @param $type
|
||||
* The language negotiation type.
|
||||
* The language negotiation provider type.
|
||||
* @param $provider_id
|
||||
* The language provider ID.
|
||||
* The language negotiation provider ID.
|
||||
*
|
||||
* @return
|
||||
* The provider ID if it is enabled, FALSE otherwise.
|
||||
@ -155,14 +246,13 @@ function language_negotiation_get($type, $provider_id = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given language provider is enabled for any configurable language
|
||||
* type.
|
||||
* Checks if the language negotiation provider is enabled for any language type.
|
||||
*
|
||||
* @param $provider_id
|
||||
* The language provider ID.
|
||||
* The language negotiation provider ID.
|
||||
*
|
||||
* @return
|
||||
* TRUE if there is at least one language type for which the give language
|
||||
* TRUE if there is at least one language type for which the given language
|
||||
* provider is enabled, FALSE otherwise.
|
||||
*/
|
||||
function language_negotiation_get_any($provider_id) {
|
||||
@ -176,7 +266,7 @@ function language_negotiation_get_any($provider_id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the language switch links for the given language.
|
||||
* Returns the language switch links for the given language.
|
||||
*
|
||||
* @param $type
|
||||
* The language negotiation type.
|
||||
@ -207,7 +297,7 @@ function language_negotiation_get_switch_links($type, $path) {
|
||||
// Add support for WCAG 2.0's Language of Parts to add language identifiers.
|
||||
// http://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html
|
||||
foreach ($result as $langcode => $link) {
|
||||
$result[$langcode]['attributes']['lang'] = $langcode;
|
||||
$result[$langcode]['attributes']['xml:lang'] = $langcode;
|
||||
}
|
||||
|
||||
if (!empty($result)) {
|
||||
@ -223,7 +313,7 @@ function language_negotiation_get_switch_links($type, $path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates language configuration to remove any language provider that is no longer defined.
|
||||
* Removes any unused language negotiation providers from the configuration.
|
||||
*/
|
||||
function language_negotiation_purge() {
|
||||
// Ensure that we are getting the defined language negotiation information. An
|
||||
@ -246,12 +336,12 @@ function language_negotiation_purge() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a list of language providers.
|
||||
* Saves a list of language negotiation providers.
|
||||
*
|
||||
* @param $type
|
||||
* The language negotiation type.
|
||||
* @param $language_providers
|
||||
* An array of language provider weights keyed by id.
|
||||
* An array of language negotiation provider weights keyed by provider ID.
|
||||
* @see language_provider_weight()
|
||||
*/
|
||||
function language_negotiation_set($type, $language_providers) {
|
||||
@ -277,7 +367,7 @@ function language_negotiation_set($type, $language_providers) {
|
||||
// If the provider does not express any preference about types, make it
|
||||
// available for any configurable type.
|
||||
$types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
|
||||
// Check if the provider is defined and has the right type.
|
||||
// Check whether the provider is defined and has the right type.
|
||||
if (isset($types[$type])) {
|
||||
$provider_data = array();
|
||||
foreach ($provider_fields as $field) {
|
||||
@ -294,10 +384,10 @@ function language_negotiation_set($type, $language_providers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the defined language providers.
|
||||
* Returns all the defined language negotiation providers.
|
||||
*
|
||||
* @return
|
||||
* An array of language providers.
|
||||
* An array of language negotiation providers.
|
||||
*/
|
||||
function language_negotiation_info() {
|
||||
$language_providers = &drupal_static(__FUNCTION__);
|
||||
@ -306,7 +396,7 @@ function language_negotiation_info() {
|
||||
// Collect all the module-defined language negotiation providers.
|
||||
$language_providers = module_invoke_all('language_negotiation_info');
|
||||
|
||||
// Add the default language provider.
|
||||
// Add the default language negotiation provider.
|
||||
$language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
|
||||
'callbacks' => array('language' => 'language_from_default'),
|
||||
'weight' => 10,
|
||||
@ -314,7 +404,7 @@ function language_negotiation_info() {
|
||||
'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
|
||||
);
|
||||
|
||||
// Let other modules alter the list of language providers.
|
||||
// Let other modules alter the list of language negotiation providers.
|
||||
drupal_alter('language_negotiation_info', $language_providers);
|
||||
}
|
||||
|
||||
@ -322,16 +412,17 @@ function language_negotiation_info() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function used to cache the language providers results.
|
||||
* Helper function used to cache the language negotiation providers results.
|
||||
*
|
||||
* @param $provider_id
|
||||
* The language provider ID.
|
||||
* The language negotiation provider's identifier.
|
||||
* @param $provider
|
||||
* The language provider to be invoked. If not passed it will be explicitly
|
||||
* loaded through language_negotiation_info().
|
||||
* (optional) An associative array of information about the provider to be
|
||||
* invoked (see hook_language_negotiation_info() for details). If not passed
|
||||
* in, it will be loaded through language_negotiation_info().
|
||||
*
|
||||
* @return
|
||||
* The language provider's return value.
|
||||
* A language object representing the language chosen by the provider.
|
||||
*/
|
||||
function language_provider_invoke($provider_id, $provider = NULL) {
|
||||
$results = &drupal_static(__FUNCTION__);
|
||||
@ -352,25 +443,26 @@ function language_provider_invoke($provider_id, $provider = NULL) {
|
||||
require_once DRUPAL_ROOT . '/' . $provider['file'];
|
||||
}
|
||||
|
||||
// If the language provider has no cache preference or this is satisfied
|
||||
// we can execute the callback.
|
||||
// If the language negotiation provider has no cache preference or this is
|
||||
// satisfied we can execute the callback.
|
||||
$cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
|
||||
$callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
|
||||
$langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
|
||||
$results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
|
||||
}
|
||||
|
||||
// Since objects are resources we need to return a clone to prevent the
|
||||
// provider cache to be unintentionally altered. The same providers might be
|
||||
// used with different language types based on configuration.
|
||||
// Since objects are resources, we need to return a clone to prevent the
|
||||
// language negotiation provider cache from being unintentionally altered. The
|
||||
// same providers might be used with different language types based on
|
||||
// configuration.
|
||||
return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the passed language provider weight or a default value.
|
||||
* Returns the passed language negotiation provider weight or a default value.
|
||||
*
|
||||
* @param $provider
|
||||
* A language provider data structure.
|
||||
* A language negotiation provider data structure.
|
||||
*
|
||||
* @return
|
||||
* A numeric weight.
|
||||
@ -381,16 +473,16 @@ function language_provider_weight($provider) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a language for the given type based on language negotiation settings.
|
||||
* Chooses a language based on language negotiation provider settings.
|
||||
*
|
||||
* @param $type
|
||||
* The language type.
|
||||
* The language type key to find the language for.
|
||||
*
|
||||
* @return
|
||||
* The negotiated language object.
|
||||
*/
|
||||
function language_initialize($type) {
|
||||
// Execute the language providers in the order they were set up and return the
|
||||
// Execute the language negotiation providers in the order they were set up and return the
|
||||
// first valid language found.
|
||||
$negotiation = variable_get("language_negotiation_$type", array());
|
||||
|
||||
@ -409,7 +501,7 @@ function language_initialize($type) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default language provider.
|
||||
* Returns the default language negotiation provider.
|
||||
*
|
||||
* @return
|
||||
* The default language code.
|
||||
@ -421,8 +513,8 @@ function language_from_default() {
|
||||
/**
|
||||
* Splits the given path into prefix and actual path.
|
||||
*
|
||||
* Parse the given path and return the language object identified by the
|
||||
* prefix and the actual path.
|
||||
* Parse the given path and return the language object identified by the prefix
|
||||
* and the actual path.
|
||||
*
|
||||
* @param $path
|
||||
* The path to split.
|
||||
@ -482,3 +574,7 @@ function language_fallback_get_candidates($type = LANGUAGE_TYPE_CONTENT) {
|
||||
|
||||
return $fallback_candidates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "language_negotiation"
|
||||
*/
|
||||
|
@ -398,7 +398,7 @@ function locale_language_switcher_session($type, $path) {
|
||||
$links[$langcode]['query'][$param] = $langcode;
|
||||
}
|
||||
else {
|
||||
$links[$langcode]['attributes']['class'][] = ' session-active';
|
||||
$links[$langcode]['attributes']['class'][] = 'session-active';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1931,7 +1931,7 @@ function _locale_translate_seek() {
|
||||
$groups[$string['group']],
|
||||
array('data' => check_plain(truncate_utf8($string['source'], 150, FALSE, TRUE)) . '<br /><small>' . $string['location'] . '</small>'),
|
||||
$string['context'],
|
||||
array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
|
||||
array('data' => _locale_translate_language_list($string, $limit_language), 'align' => 'center'),
|
||||
array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
|
||||
array('data' => l(t('delete'), "admin/config/regional/translate/delete/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
|
||||
);
|
||||
@ -2126,16 +2126,21 @@ function _locale_rebuild_js($langcode = NULL) {
|
||||
/**
|
||||
* List languages in search result table
|
||||
*/
|
||||
function _locale_translate_language_list($translation, $limit_language) {
|
||||
function _locale_translate_language_list($string, $limit_language) {
|
||||
// Add CSS.
|
||||
drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
|
||||
|
||||
// Include both translated and not yet translated target languages in the
|
||||
// list. The source language is English for built-in strings and the default
|
||||
// language for other strings.
|
||||
$languages = language_list();
|
||||
unset($languages['en']);
|
||||
$default = language_default();
|
||||
$omit = $string['group'] == 'default' ? 'en' : $default->language;
|
||||
unset($languages[$omit]);
|
||||
$output = '';
|
||||
foreach ($languages as $langcode => $language) {
|
||||
if (!$limit_language || $limit_language == $langcode) {
|
||||
$output .= (!empty($translation[$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
|
||||
$output .= (!empty($string['languages'][$langcode])) ? $langcode . ' ' : "<em class=\"locale-untranslated\">$langcode</em> ";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ function _lock_id() {
|
||||
* Acquire (or renew) a lock, but do not block if it fails.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the lock.
|
||||
* The name of the lock. Limit of name's length is 255 characters.
|
||||
* @param $timeout
|
||||
* A number of seconds (float) before the lock expires (minimum of 0.001).
|
||||
*
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* $conf['mail_line_endings'] will override this setting.
|
||||
*/
|
||||
define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE ? "\r\n" : "\n");
|
||||
define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE) ? "\r\n" : "\n");
|
||||
|
||||
/**
|
||||
* Composes and optionally sends an e-mail message.
|
||||
@ -93,7 +93,9 @@ define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER
|
||||
* will be {$module}_{$key}.
|
||||
* @param $to
|
||||
* The e-mail address or addresses where the message will be sent to. The
|
||||
* formatting of this string must comply with RFC 2822. Some examples are:
|
||||
* formatting of this string will be validated with the
|
||||
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
|
||||
* Some examples are:
|
||||
* - user@example.com
|
||||
* - user@example.com, anotheruser@example.com
|
||||
* - User <user@example.com>
|
||||
@ -212,9 +214,9 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N
|
||||
* 'mail_system', which is a keyed array. The default implementation
|
||||
* is the class whose name is the value of 'default-system' key. A more specific
|
||||
* match first to key and then to module will be used in preference to the
|
||||
* default. To specificy a different class for all mail sent by one module, set
|
||||
* default. To specify a different class for all mail sent by one module, set
|
||||
* the class name as the value for the key corresponding to the module name. To
|
||||
* specificy a class for a particular message sent by one module, set the class
|
||||
* specify a class for a particular message sent by one module, set the class
|
||||
* name as the value for the array key that is the message id, which is
|
||||
* "${module}_${key}".
|
||||
*
|
||||
@ -307,19 +309,21 @@ interface MailSystemInterface {
|
||||
* - id: A unique identifier of the e-mail type. Examples: 'contact_user_copy',
|
||||
* 'user_password_reset'.
|
||||
* - to: The mail address or addresses where the message will be sent to.
|
||||
* The formatting of this string must comply with RFC 2822. Some examples:
|
||||
* The formatting of this string will be validated with the
|
||||
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
|
||||
* Some examples are:
|
||||
* - user@example.com
|
||||
* - user@example.com, anotheruser@example.com
|
||||
* - User <user@example.com>
|
||||
* - User <user@example.com>, Another User <anotheruser@example.com>
|
||||
* - subject: Subject of the e-mail to be sent. This must not contain any
|
||||
* newline characters, or the mail may not be sent properly.
|
||||
* - body: Message to be sent. Accepts both CRLF and LF line-endings.
|
||||
* E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
|
||||
* smart plain text wrapping.
|
||||
* - headers: Associative array containing all additional mail headers not
|
||||
* defined by one of the other parameters. PHP's mail() looks for Cc
|
||||
* and Bcc headers and sends the mail to addresses in these headers too.
|
||||
* - subject: Subject of the e-mail to be sent. This must not contain any
|
||||
* newline characters, or the mail may not be sent properly.
|
||||
* - body: Message to be sent. Accepts both CRLF and LF line-endings.
|
||||
* E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
|
||||
* smart plain text wrapping.
|
||||
* - headers: Associative array containing all additional mail headers not
|
||||
* defined by one of the other parameters. PHP's mail() looks for Cc and
|
||||
* Bcc headers and sends the mail to addresses in these headers too.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the mail was successfully accepted for delivery, otherwise FALSE.
|
||||
@ -335,13 +339,13 @@ interface MailSystemInterface {
|
||||
*
|
||||
* We deliberately use LF rather than CRLF, see drupal_mail().
|
||||
*
|
||||
* @param $text
|
||||
* @param string $text
|
||||
* The plain text to process.
|
||||
* @param $indent (optional)
|
||||
* @param string $indent (optional)
|
||||
* A string to indent the text with. Only '>' characters are repeated on
|
||||
* subsequent wrapped lines. Others are replaced by spaces.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The content of the email as a string with formatting applied.
|
||||
*/
|
||||
function drupal_wrap_mail($text, $indent = '') {
|
||||
@ -352,8 +356,9 @@ function drupal_wrap_mail($text, $indent = '') {
|
||||
$soft = strpos($clean_indent, ' ') === FALSE;
|
||||
// Check if the string has line breaks.
|
||||
if (strpos($text, "\n") !== FALSE) {
|
||||
// Remove trailing spaces to make existing breaks hard.
|
||||
$text = preg_replace('/ +\n/m', "\n", $text);
|
||||
// Remove trailing spaces to make existing breaks hard, but leave signature
|
||||
// marker untouched (RFC 3676, Section 4.3).
|
||||
$text = preg_replace('/(?(?<!^--) +\n| +\n)/m', "\n", $text);
|
||||
// Wrap each line at the needed width.
|
||||
$lines = explode("\n", $text);
|
||||
array_walk($lines, '_drupal_wrap_mail_line', array('soft' => $soft, 'length' => strlen($indent)));
|
||||
@ -559,7 +564,7 @@ function drupal_html_to_text($string, $allowed_tags = NULL) {
|
||||
*/
|
||||
function _drupal_wrap_mail_line(&$line, $key, $values) {
|
||||
// Use soft-breaks only for purely quoted or unindented text.
|
||||
$line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
|
||||
$line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
|
||||
// Break really long words at the maximum width allowed.
|
||||
$line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ define('MENU_PREFERRED_LINK', '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91');
|
||||
* actually exists. This list of 'masks' is built in menu_rebuild().
|
||||
*
|
||||
* @param $parts
|
||||
* An array of path parts, for the above example
|
||||
* An array of path parts; for the above example,
|
||||
* array('node', '12345', 'edit').
|
||||
*
|
||||
* @return
|
||||
@ -430,7 +430,7 @@ function menu_set_item($path, $router_item) {
|
||||
* Gets a router item.
|
||||
*
|
||||
* @param $path
|
||||
* The path, for example node/5. The function will find the corresponding
|
||||
* The path; for example, 'node/5'. The function will find the corresponding
|
||||
* node/% item and return that.
|
||||
* @param $router_item
|
||||
* Internal use only.
|
||||
@ -456,7 +456,9 @@ function menu_get_item($path = NULL, $router_item = NULL) {
|
||||
// Rebuild if we know it's needed, or if the menu masks are missing which
|
||||
// occurs rarely, likely due to a race condition of multiple rebuilds.
|
||||
if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) {
|
||||
menu_rebuild();
|
||||
if (_menu_check_rebuild()) {
|
||||
menu_rebuild();
|
||||
}
|
||||
}
|
||||
$original_map = arg(NULL, $path);
|
||||
|
||||
@ -542,7 +544,7 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
|
||||
* @param $item
|
||||
* A menu router or menu link item
|
||||
* @param $map
|
||||
* An array of path arguments (ex: array('node', '5'))
|
||||
* An array of path arguments; for example, array('node', '5').
|
||||
*
|
||||
* @return
|
||||
* Returns TRUE for success, FALSE if an object cannot be loaded.
|
||||
@ -612,12 +614,13 @@ function _menu_load_objects(&$item, &$map) {
|
||||
* @param $item
|
||||
* A menu router or menu link item
|
||||
* @param $map
|
||||
* An array of path arguments (ex: array('node', '5'))
|
||||
* An array of path arguments; for example, array('node', '5').
|
||||
*
|
||||
* @return
|
||||
* $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
|
||||
*/
|
||||
function _menu_check_access(&$item, $map) {
|
||||
$item['access'] = FALSE;
|
||||
// Determine access callback, which will decide whether or not the current
|
||||
// user has access to this path.
|
||||
$callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
|
||||
@ -737,7 +740,7 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
|
||||
* @param $router_item
|
||||
* A menu router item
|
||||
* @param $map
|
||||
* An array of path arguments (ex: array('node', '5'))
|
||||
* An array of path arguments; for example, array('node', '5').
|
||||
* @param $to_arg
|
||||
* Execute $item['to_arg_functions'] or not. Use only if you want to render a
|
||||
* path from the menu table, for example tabs.
|
||||
@ -800,9 +803,9 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
|
||||
* Translates the path elements in the map using any to_arg helper function.
|
||||
*
|
||||
* @param $map
|
||||
* An array of path arguments (ex: array('node', '5'))
|
||||
* An array of path arguments; for example, array('node', '5').
|
||||
* @param $to_arg_functions
|
||||
* An array of helper function (ex: array(2 => 'menu_tail_to_arg'))
|
||||
* An array of helper functions; for example, array(2 => 'menu_tail_to_arg').
|
||||
*
|
||||
* @see hook_menu()
|
||||
*/
|
||||
@ -999,7 +1002,7 @@ function menu_tree($menu_name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered menu tree.
|
||||
* Returns an output structure for rendering a menu tree.
|
||||
*
|
||||
* The menu item's LI element is given one of the following classes:
|
||||
* - expanded: The menu item is showing its submenu.
|
||||
@ -1925,13 +1928,21 @@ function menu_local_tasks($level = 0) {
|
||||
}
|
||||
|
||||
// Get all tabs (also known as local tasks) and the root page.
|
||||
$result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
|
||||
->fields('menu_router')
|
||||
->condition('tab_root', $router_item['tab_root'])
|
||||
->condition('context', MENU_CONTEXT_INLINE, '<>')
|
||||
->orderBy('weight')
|
||||
->orderBy('title')
|
||||
->execute();
|
||||
$cid = 'local_tasks:' . $router_item['tab_root'];
|
||||
if ($cache = cache_get($cid, 'cache_menu')) {
|
||||
$result = $cache->data;
|
||||
}
|
||||
else {
|
||||
$result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
|
||||
->fields('menu_router')
|
||||
->condition('tab_root', $router_item['tab_root'])
|
||||
->condition('context', MENU_CONTEXT_INLINE, '<>')
|
||||
->orderBy('weight')
|
||||
->orderBy('title')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
cache_set($cid, $result, 'cache_menu');
|
||||
}
|
||||
$map = $router_item['original_map'];
|
||||
$children = array();
|
||||
$tasks = array();
|
||||
@ -2138,7 +2149,7 @@ function menu_local_tasks($level = 0) {
|
||||
* example 'node' or 'admin/structure/block/manage'.
|
||||
* @param $args
|
||||
* A list of dynamic path arguments to append to $parent_path to form the
|
||||
* fully-qualified menu router path, for example array(123) for a certain
|
||||
* fully-qualified menu router path; for example, array(123) for a certain
|
||||
* node or array('system', 'navigation') for a certain block.
|
||||
*
|
||||
* @return
|
||||
@ -2429,7 +2440,7 @@ function menu_set_active_trail($new_trail = NULL) {
|
||||
* Looks up the preferred menu link for a given system path.
|
||||
*
|
||||
* @param $path
|
||||
* The path, for example 'node/5'. The function will find the corresponding
|
||||
* The path; for example, 'node/5'. The function will find the corresponding
|
||||
* menu link ('node/5' if it exists, or fallback to 'node/%').
|
||||
* @param $selected_menu
|
||||
* The name of a menu used to restrict the search for a preferred menu link.
|
||||
@ -2486,6 +2497,7 @@ function menu_link_get_preferred($path = NULL, $selected_menu = NULL) {
|
||||
$query->addField('ml', 'weight', 'link_weight');
|
||||
$query->fields('m');
|
||||
$query->condition('ml.link_path', $path_candidates, 'IN');
|
||||
$query->addTag('preferred_menu_links');
|
||||
|
||||
// Sort candidates by link path and menu name.
|
||||
$candidates = array();
|
||||
@ -2683,6 +2695,21 @@ function menu_reset_static_cache() {
|
||||
drupal_static_reset('menu_link_get_preferred');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a menu_rebuild() is necessary.
|
||||
*/
|
||||
function _menu_check_rebuild() {
|
||||
// To absolutely ensure that the menu rebuild is required, re-load the
|
||||
// variables in case they were set by another process.
|
||||
$variables = variable_initialize();
|
||||
if (empty($variables['menu_rebuild_needed']) && !empty($variables['menu_masks'])) {
|
||||
unset($GLOBALS['conf']['menu_rebuild_needed']);
|
||||
$GLOBALS['conf']['menu_masks'] = $variables['menu_masks'];
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the database tables used by various menu functions.
|
||||
*
|
||||
@ -2703,6 +2730,14 @@ function menu_rebuild() {
|
||||
// We choose to block here since otherwise the router item may not
|
||||
// be available in menu_execute_active_handler() resulting in a 404.
|
||||
lock_wait('menu_rebuild');
|
||||
|
||||
if (_menu_check_rebuild()) {
|
||||
// If we get here and menu_masks was not set, then it is possible a menu
|
||||
// is being reloaded, or that the process rebuilding the menu was unable
|
||||
// to complete successfully. A missing menu_masks variable could result
|
||||
// in a 404, so re-run the function.
|
||||
return menu_rebuild();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -2727,6 +2762,12 @@ function menu_rebuild() {
|
||||
$transaction->rollback();
|
||||
watchdog_exception('menu', $e);
|
||||
}
|
||||
// Explicitly commit the transaction now; this ensures that the database
|
||||
// operations during the menu rebuild are committed before the lock is made
|
||||
// available again, since locks may not always reside in the same database
|
||||
// connection. The lock is acquired outside of the transaction so should also
|
||||
// be released outside of it.
|
||||
unset($transaction);
|
||||
|
||||
lock_release('menu_rebuild');
|
||||
return TRUE;
|
||||
|
@ -265,11 +265,11 @@ function _module_build_dependencies($files) {
|
||||
/**
|
||||
* Determines whether a given module exists.
|
||||
*
|
||||
* @param $module
|
||||
* @param string $module
|
||||
* The name of the module (without the .module extension).
|
||||
*
|
||||
* @return
|
||||
* TRUE if the module is both installed and enabled.
|
||||
* @return bool
|
||||
* TRUE if the module is both installed and enabled, FALSE otherwise.
|
||||
*/
|
||||
function module_exists($module) {
|
||||
$list = module_list();
|
||||
@ -610,9 +610,40 @@ function module_disable($module_list, $disable_dependents = TRUE) {
|
||||
* just models that you can modify. Only the hooks implemented within modules
|
||||
* are executed when running Drupal.
|
||||
*
|
||||
* See also @link themeable the themeable group page. @endlink
|
||||
* @see themeable
|
||||
* @see callbacks
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup callbacks Callbacks
|
||||
* @{
|
||||
* Callback function signatures.
|
||||
*
|
||||
* Drupal's API sometimes uses callback functions to allow you to define how
|
||||
* some type of processing happens. A callback is a function with a defined
|
||||
* signature, which you define in a module. Then you pass the function name as
|
||||
* a parameter to a Drupal API function or return it as part of a hook
|
||||
* implementation return value, and your function is called at an appropriate
|
||||
* time. For instance, when setting up batch processing you might need to
|
||||
* provide a callback function for each processing step and/or a callback for
|
||||
* when processing is finished; you would do that by defining these functions
|
||||
* and passing their names into the batch setup function.
|
||||
*
|
||||
* Callback function signatures, like hook definitions, are described by
|
||||
* creating and documenting dummy functions in a *.api.php file; normally, the
|
||||
* dummy callback function's name should start with "callback_", and you should
|
||||
* document the parameters and return value and provide a sample function body.
|
||||
* Then your API documentation can refer to this callback function in its
|
||||
* documentation. A user of your API can usually name their callback function
|
||||
* anything they want, although a standard name would be to replace "callback_"
|
||||
* with the module name.
|
||||
*
|
||||
* @see hooks
|
||||
* @see themeable
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines whether a module implements a hook.
|
||||
*
|
||||
@ -803,10 +834,7 @@ function module_hook_info() {
|
||||
*/
|
||||
function module_implements_write_cache() {
|
||||
$implementations = &drupal_static('module_implements');
|
||||
// Check whether we need to write the cache. We do not want to cache hooks
|
||||
// which are only invoked on HTTP POST requests since these do not need to be
|
||||
// optimized as tightly, and not doing so keeps the cache entry smaller.
|
||||
if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
|
||||
if (isset($implementations['#write_cache'])) {
|
||||
unset($implementations['#write_cache']);
|
||||
cache_set('module_implements', $implementations, 'cache_bootstrap');
|
||||
}
|
||||
@ -815,6 +843,9 @@ function module_implements_write_cache() {
|
||||
/**
|
||||
* Invokes a hook in a particular module.
|
||||
*
|
||||
* All arguments are passed by value. Use drupal_alter() if you need to pass
|
||||
* arguments by reference.
|
||||
*
|
||||
* @param $module
|
||||
* The name of the module (without the .module extension).
|
||||
* @param $hook
|
||||
@ -824,6 +855,8 @@ function module_implements_write_cache() {
|
||||
*
|
||||
* @return
|
||||
* The return value of the hook implementation.
|
||||
*
|
||||
* @see drupal_alter()
|
||||
*/
|
||||
function module_invoke($module, $hook) {
|
||||
$args = func_get_args();
|
||||
@ -837,6 +870,9 @@ function module_invoke($module, $hook) {
|
||||
/**
|
||||
* Invokes a hook in all enabled modules that implement it.
|
||||
*
|
||||
* All arguments are passed by value. Use drupal_alter() if you need to pass
|
||||
* arguments by reference.
|
||||
*
|
||||
* @param $hook
|
||||
* The name of the hook to invoke.
|
||||
* @param ...
|
||||
@ -845,6 +881,8 @@ function module_invoke($module, $hook) {
|
||||
* @return
|
||||
* An array of return values of the hook implementations. If modules return
|
||||
* arrays from their implementations, those are merged into one array.
|
||||
*
|
||||
* @see drupal_alter()
|
||||
*/
|
||||
function module_invoke_all($hook) {
|
||||
$args = func_get_args();
|
||||
@ -898,9 +936,10 @@ function drupal_required_modules() {
|
||||
* hook_TYPE_alter() implementations in modules. It ensures a consistent
|
||||
* interface for all altering operations.
|
||||
*
|
||||
* A maximum of 2 alterable arguments is supported. In case more arguments need
|
||||
* to be passed and alterable, modules provide additional variables assigned by
|
||||
* reference in the last $context argument:
|
||||
* A maximum of 2 alterable arguments is supported (a third is supported for
|
||||
* legacy reasons, but should not be used in new code). In case more arguments
|
||||
* need to be passed and alterable, modules provide additional variables
|
||||
* assigned by reference in the last $context argument:
|
||||
* @code
|
||||
* $context = array(
|
||||
* 'alterable' => &$alterable,
|
||||
@ -939,8 +978,14 @@ function drupal_required_modules() {
|
||||
* (optional) An additional variable that is passed by reference. If more
|
||||
* context needs to be provided to implementations, then this should be an
|
||||
* associative array as described above.
|
||||
* @param $context3
|
||||
* (optional) An additional variable that is passed by reference. This
|
||||
* parameter is deprecated and will not exist in Drupal 8; consequently, it
|
||||
* should not be used for new Drupal 7 code either. It is here only for
|
||||
* backwards compatibility with older code that passed additional arguments
|
||||
* to drupal_alter().
|
||||
*/
|
||||
function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
|
||||
function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
|
||||
// Use the advanced drupal_static() pattern, since this is called very often.
|
||||
static $drupal_static_fast;
|
||||
if (!isset($drupal_static_fast)) {
|
||||
@ -1053,6 +1098,6 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
|
||||
}
|
||||
|
||||
foreach ($functions[$cid] as $function) {
|
||||
$function($data, $context1, $context2);
|
||||
$function($data, $context1, $context2, $context3);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ function _password_itoa64() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode bytes into printable base 64 using the *nix standard from crypt().
|
||||
* Encodes bytes into printable base 64 using the *nix standard from crypt().
|
||||
*
|
||||
* @param $input
|
||||
* The string containing bytes to encode.
|
||||
@ -140,7 +140,7 @@ function _password_enforce_log2_boundaries($count_log2) {
|
||||
* @param $algo
|
||||
* The string name of a hashing algorithm usable by hash(), like 'sha256'.
|
||||
* @param $password
|
||||
* The plain-text password to hash.
|
||||
* Plain-text password up to 512 bytes (128 to 512 UTF-8 characters) to hash.
|
||||
* @param $setting
|
||||
* An existing hash or the output of _password_generate_salt(). Must be
|
||||
* at least 12 characters (the settings and salt).
|
||||
@ -150,6 +150,10 @@ function _password_enforce_log2_boundaries($count_log2) {
|
||||
* The return string will be truncated at DRUPAL_HASH_LENGTH characters max.
|
||||
*/
|
||||
function _password_crypt($algo, $password, $setting) {
|
||||
// Prevent DoS attacks by refusing to hash large passwords.
|
||||
if (strlen($password) > 512) {
|
||||
return FALSE;
|
||||
}
|
||||
// The first 12 characters of an existing hash are its setting string.
|
||||
$setting = substr($setting, 0, 12);
|
||||
|
||||
|
@ -386,7 +386,7 @@ function drupal_path_alias_whitelist_rebuild($source = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific URL alias from the database.
|
||||
* Fetches a specific URL alias from the database.
|
||||
*
|
||||
* @param $conditions
|
||||
* A string representing the source, a number representing the pid, or an
|
||||
@ -475,11 +475,11 @@ function path_delete($criteria) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a path is in the administrative section of the site.
|
||||
* Determines whether a path is in the administrative section of the site.
|
||||
*
|
||||
* By default, paths are considered to be non-administrative. If a path does not
|
||||
* match any of the patterns in path_get_admin_paths(), or if it matches both
|
||||
* administrative and non-administrative patterns, it is considered
|
||||
* By default, paths are considered to be non-administrative. If a path does
|
||||
* not match any of the patterns in path_get_admin_paths(), or if it matches
|
||||
* both administrative and non-administrative patterns, it is considered
|
||||
* non-administrative.
|
||||
*
|
||||
* @param $path
|
||||
@ -503,7 +503,7 @@ function path_is_admin($path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of administrative and non-administrative paths.
|
||||
* Gets a list of administrative and non-administrative paths.
|
||||
*
|
||||
* @return array
|
||||
* An associative array containing the following keys:
|
||||
@ -560,8 +560,8 @@ function drupal_valid_path($path, $dynamic_allowed = FALSE) {
|
||||
elseif ($dynamic_allowed && preg_match('/\/\%/', $path)) {
|
||||
// Path is dynamic (ie 'user/%'), so check directly against menu_router table.
|
||||
if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) {
|
||||
$item['link_path'] = $form_item['link_path'];
|
||||
$item['link_title'] = $form_item['link_title'];
|
||||
$item['link_path'] = $item['path'];
|
||||
$item['link_title'] = $item['title'];
|
||||
$item['external'] = FALSE;
|
||||
$item['options'] = '';
|
||||
_menu_link_translate($item);
|
||||
|
@ -10,7 +10,7 @@
|
||||
* @{
|
||||
* The code registry engine.
|
||||
*
|
||||
* Drupal maintains an internal registry of all functions or classes in the
|
||||
* Drupal maintains an internal registry of all interfaces or classes in the
|
||||
* system, allowing it to lazy-load code files as needed (reducing the amount
|
||||
* of code that must be parsed on each request).
|
||||
*/
|
||||
@ -120,7 +120,10 @@ function registry_get_parsed_files() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all files that have changed since the registry was last built, and save their function and class listings.
|
||||
* Parse all changed files and save their interface and class listings.
|
||||
*
|
||||
* Parse all files that have changed since the registry was last built, and save
|
||||
* their interface and class listings.
|
||||
*
|
||||
* @param $files
|
||||
* The list of files to check and parse.
|
||||
@ -149,7 +152,7 @@ function _registry_parse_files($files) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a file and save its function and class listings.
|
||||
* Parse a file and save its interface and class listings.
|
||||
*
|
||||
* @param $filename
|
||||
* Name of the file we are going to parse.
|
||||
|
@ -79,7 +79,7 @@ function _drupal_session_read($sid) {
|
||||
// Handle the case of first time visitors and clients that don't store
|
||||
// cookies (eg. web crawlers).
|
||||
$insecure_session_name = substr(session_name(), 1);
|
||||
if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) {
|
||||
if (empty($sid) || (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name]))) {
|
||||
$user = drupal_anonymous_user();
|
||||
return '';
|
||||
}
|
||||
@ -263,10 +263,10 @@ function drupal_session_initialize() {
|
||||
// Less random sessions (which are much faster to generate) are used for
|
||||
// anonymous users than are generated in drupal_session_regenerate() when
|
||||
// a user becomes authenticated.
|
||||
session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE)));
|
||||
session_id(drupal_random_key());
|
||||
if ($is_https && variable_get('https', FALSE)) {
|
||||
$insecure_session_name = substr(session_name(), 1);
|
||||
$session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE));
|
||||
$session_id = drupal_random_key();
|
||||
$_COOKIE[$insecure_session_name] = $session_id;
|
||||
}
|
||||
}
|
||||
@ -274,7 +274,7 @@ function drupal_session_initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully starts a session, preserving already set session data.
|
||||
* Starts a session forcefully, preserving already set session data.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
@ -360,7 +360,7 @@ function drupal_session_regenerate() {
|
||||
$old_insecure_session_id = $_COOKIE[$insecure_session_name];
|
||||
}
|
||||
$params = session_get_cookie_params();
|
||||
$session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
|
||||
$session_id = drupal_random_key();
|
||||
// If a session cookie lifetime is set, the session will expire
|
||||
// $params['lifetime'] seconds from the current request. If it is not set,
|
||||
// it will expire when the browser is closed.
|
||||
@ -372,7 +372,7 @@ function drupal_session_regenerate() {
|
||||
if (drupal_session_started()) {
|
||||
$old_session_id = session_id();
|
||||
}
|
||||
session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)));
|
||||
session_id(drupal_random_key());
|
||||
|
||||
if (isset($old_session_id)) {
|
||||
$params = session_get_cookie_params();
|
||||
|
@ -93,7 +93,7 @@ define('STREAM_WRAPPERS_LOCAL_NORMAL', STREAM_WRAPPERS_LOCAL | STREAM_WRAPPERS_N
|
||||
/**
|
||||
* Generic PHP stream wrapper interface.
|
||||
*
|
||||
* @see http://www.php.net/manual/en/class.streamwrapper.php
|
||||
* @see http://www.php.net/manual/class.streamwrapper.php
|
||||
*/
|
||||
interface StreamWrapperInterface {
|
||||
public function stream_open($uri, $mode, $options, &$opened_url);
|
||||
@ -401,7 +401,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* Returns TRUE if file was opened successfully.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-open.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-open.php
|
||||
*/
|
||||
public function stream_open($uri, $mode, $options, &$opened_path) {
|
||||
$this->uri = $uri;
|
||||
@ -429,7 +429,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* Always returns TRUE at the present time.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-lock.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-lock.php
|
||||
*/
|
||||
public function stream_lock($operation) {
|
||||
if (in_array($operation, array(LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB))) {
|
||||
@ -448,7 +448,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* The string that was read, or FALSE in case of an error.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-read.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-read.php
|
||||
*/
|
||||
public function stream_read($count) {
|
||||
return fread($this->handle, $count);
|
||||
@ -463,7 +463,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* The number of bytes written (integer).
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-write.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-write.php
|
||||
*/
|
||||
public function stream_write($data) {
|
||||
return fwrite($this->handle, $data);
|
||||
@ -475,7 +475,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if end-of-file has been reached.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-eof.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-eof.php
|
||||
*/
|
||||
public function stream_eof() {
|
||||
return feof($this->handle);
|
||||
@ -492,7 +492,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-seek.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-seek.php
|
||||
*/
|
||||
public function stream_seek($offset, $whence) {
|
||||
// fseek returns 0 on success and -1 on a failure.
|
||||
@ -506,7 +506,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if data was successfully stored (or there was no data to store).
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-flush.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-flush.php
|
||||
*/
|
||||
public function stream_flush() {
|
||||
return fflush($this->handle);
|
||||
@ -518,7 +518,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* The current offset in bytes from the beginning of file.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-tell.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-tell.php
|
||||
*/
|
||||
public function stream_tell() {
|
||||
return ftell($this->handle);
|
||||
@ -531,7 +531,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* An array with file status, or FALSE in case of an error - see fstat()
|
||||
* for a description of this array.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-stat.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-stat.php
|
||||
*/
|
||||
public function stream_stat() {
|
||||
return fstat($this->handle);
|
||||
@ -543,7 +543,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if stream was successfully closed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-close.php
|
||||
* @see http://php.net/manual/streamwrapper.stream-close.php
|
||||
*/
|
||||
public function stream_close() {
|
||||
return fclose($this->handle);
|
||||
@ -558,7 +558,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if resource was successfully deleted.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.unlink.php
|
||||
* @see http://php.net/manual/streamwrapper.unlink.php
|
||||
*/
|
||||
public function unlink($uri) {
|
||||
$this->uri = $uri;
|
||||
@ -576,7 +576,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if file was successfully renamed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.rename.php
|
||||
* @see http://php.net/manual/streamwrapper.rename.php
|
||||
*/
|
||||
public function rename($from_uri, $to_uri) {
|
||||
return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
|
||||
@ -622,7 +622,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if directory was successfully created.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.mkdir.php
|
||||
* @see http://php.net/manual/streamwrapper.mkdir.php
|
||||
*/
|
||||
public function mkdir($uri, $mode, $options) {
|
||||
$this->uri = $uri;
|
||||
@ -654,7 +654,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE if directory was successfully removed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.rmdir.php
|
||||
* @see http://php.net/manual/streamwrapper.rmdir.php
|
||||
*/
|
||||
public function rmdir($uri, $options) {
|
||||
$this->uri = $uri;
|
||||
@ -678,7 +678,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* An array with file status, or FALSE in case of an error - see fstat()
|
||||
* for a description of this array.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.url-stat.php
|
||||
* @see http://php.net/manual/streamwrapper.url-stat.php
|
||||
*/
|
||||
public function url_stat($uri, $flags) {
|
||||
$this->uri = $uri;
|
||||
@ -704,7 +704,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-opendir.php
|
||||
* @see http://php.net/manual/streamwrapper.dir-opendir.php
|
||||
*/
|
||||
public function dir_opendir($uri, $options) {
|
||||
$this->uri = $uri;
|
||||
@ -719,7 +719,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* The next filename, or FALSE if there are no more files in the directory.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-readdir.php
|
||||
* @see http://php.net/manual/streamwrapper.dir-readdir.php
|
||||
*/
|
||||
public function dir_readdir() {
|
||||
return readdir($this->handle);
|
||||
@ -731,7 +731,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
|
||||
* @see http://php.net/manual/streamwrapper.dir-rewinddir.php
|
||||
*/
|
||||
public function dir_rewinddir() {
|
||||
rewinddir($this->handle);
|
||||
@ -747,7 +747,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
|
||||
* @return
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-closedir.php
|
||||
* @see http://php.net/manual/streamwrapper.dir-closedir.php
|
||||
*/
|
||||
public function dir_closedir() {
|
||||
closedir($this->handle);
|
||||
@ -788,8 +788,6 @@ class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper {
|
||||
*
|
||||
* Provides support for storing privately accessible files with the Drupal file
|
||||
* interface.
|
||||
*
|
||||
* Extends DrupalPublicStreamWrapper.
|
||||
*/
|
||||
class DrupalPrivateStreamWrapper extends DrupalLocalStreamWrapper {
|
||||
/**
|
||||
|
@ -46,16 +46,15 @@ class TableSort extends SelectQueryExtender {
|
||||
// Based on code from db_escape_table(), but this can also contain a dot.
|
||||
$field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']);
|
||||
|
||||
// Sort order can only be ASC or DESC.
|
||||
$sort = drupal_strtoupper($ts['sort']);
|
||||
$sort = in_array($sort, array('ASC', 'DESC')) ? $sort : '';
|
||||
$this->orderBy($field, $sort);
|
||||
// orderBy() will ensure that only ASC/DESC values are accepted, so we
|
||||
// don't need to sanitize that here.
|
||||
$this->orderBy($field, $ts['sort']);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the table sort context.
|
||||
* Initializes the table sort context.
|
||||
*/
|
||||
protected function init() {
|
||||
$ts = $this->order();
|
||||
@ -115,7 +114,7 @@ function tablesort_init($header) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a column header.
|
||||
* Formats a column header.
|
||||
*
|
||||
* If the cell in question is the column header for the current sort criterion,
|
||||
* it gets special formatting. All possible sort criteria become links.
|
||||
@ -126,6 +125,7 @@ function tablesort_init($header) {
|
||||
* An array of column headers in the format described in theme_table().
|
||||
* @param $ts
|
||||
* The current table sort context as returned from tablesort_init().
|
||||
*
|
||||
* @return
|
||||
* A properly formatted cell, ready for _theme_table_cell().
|
||||
*/
|
||||
@ -151,7 +151,7 @@ function tablesort_header($cell, $header, $ts) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a table cell.
|
||||
* Formats a table cell.
|
||||
*
|
||||
* Adds a class attribute to all cells in the currently active column.
|
||||
*
|
||||
@ -163,6 +163,7 @@ function tablesort_header($cell, $header, $ts) {
|
||||
* The current table sort context as returned from tablesort_init().
|
||||
* @param $i
|
||||
* The index of the cell's table column.
|
||||
*
|
||||
* @return
|
||||
* A properly formatted cell, ready for _theme_table_cell().
|
||||
*/
|
||||
@ -179,7 +180,7 @@ function tablesort_cell($cell, $header, $ts, $i) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a URL query parameter array for table sorting links.
|
||||
* Composes a URL query parameter array for table sorting links.
|
||||
*
|
||||
* @return
|
||||
* A URL query parameter array that consists of all components of the current
|
||||
@ -190,10 +191,11 @@ function tablesort_get_query_parameters() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current sort criterion.
|
||||
* Determines the current sort criterion.
|
||||
*
|
||||
* @param $headers
|
||||
* An array of column headers in the format described in theme_table().
|
||||
*
|
||||
* @return
|
||||
* An associative array describing the criterion, containing the keys:
|
||||
* - "name": The localized title of the table column.
|
||||
@ -226,10 +228,11 @@ function tablesort_get_order($headers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current sort direction.
|
||||
* Determines the current sort direction.
|
||||
*
|
||||
* @param $headers
|
||||
* An array of column headers in the format described in theme_table().
|
||||
*
|
||||
* @return
|
||||
* The current sort direction ("asc" or "desc").
|
||||
*/
|
||||
|
@ -65,7 +65,7 @@ function _drupal_theme_access($theme) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the theme system by loading the theme.
|
||||
* Initializes the theme system by loading the theme.
|
||||
*/
|
||||
function drupal_theme_initialize() {
|
||||
global $theme, $user, $theme_key;
|
||||
@ -113,8 +113,9 @@ function drupal_theme_initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the theme system given already loaded information. This
|
||||
* function is useful to initialize a theme when no database is present.
|
||||
* Initializes the theme system given already loaded information.
|
||||
*
|
||||
* This function is useful to initialize a theme when no database is present.
|
||||
*
|
||||
* @param $theme
|
||||
* An object with the following information:
|
||||
@ -235,7 +236,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the theme registry.
|
||||
* Gets the theme registry.
|
||||
*
|
||||
* @param $complete
|
||||
* Optional boolean to indicate whether to return the complete theme registry
|
||||
@ -280,7 +281,7 @@ function theme_get_registry($complete = TRUE) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback that will be used by theme_get_registry() to fetch the registry.
|
||||
* Sets the callback that will be used by theme_get_registry().
|
||||
*
|
||||
* @param $callback
|
||||
* The name of the callback function.
|
||||
@ -296,7 +297,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the theme_registry cache; if it doesn't exist, build it.
|
||||
* Gets the theme_registry cache; if it doesn't exist, builds it.
|
||||
*
|
||||
* @param $theme
|
||||
* The loaded $theme object as returned by list_themes().
|
||||
@ -336,16 +337,17 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL,
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the theme_registry cache into the database.
|
||||
* Writes the theme_registry cache into the database.
|
||||
*/
|
||||
function _theme_save_registry($theme, $registry) {
|
||||
cache_set("theme_registry:$theme->name", $registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the system to rebuild the theme registry; this should be called
|
||||
* when modules are added to the system, or when a dynamic system needs
|
||||
* to add more theme hooks.
|
||||
* Forces the system to rebuild the theme registry.
|
||||
*
|
||||
* This function should be called when modules are added to the system, or when
|
||||
* a dynamic system needs to add more theme hooks.
|
||||
*/
|
||||
function drupal_theme_rebuild() {
|
||||
drupal_static_reset('theme_get_registry');
|
||||
@ -506,7 +508,7 @@ class ThemeRegistry Extends DrupalCacheArray {
|
||||
* themes/bartik.
|
||||
*
|
||||
* @see theme()
|
||||
* @see _theme_process_registry()
|
||||
* @see _theme_build_registry()
|
||||
* @see hook_theme()
|
||||
* @see list_themes()
|
||||
*/
|
||||
@ -635,7 +637,8 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
|
||||
$cache = $result + $cache;
|
||||
}
|
||||
|
||||
// Let themes have variable processors even if they didn't register a template.
|
||||
// Let themes have variable processors even if they didn't register a
|
||||
// template.
|
||||
if ($type == 'theme' || $type == 'base_theme') {
|
||||
foreach ($cache as $hook => $info) {
|
||||
// Check only if not registered by the theme or engine.
|
||||
@ -662,7 +665,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the theme registry cache.
|
||||
* Builds the theme registry cache.
|
||||
*
|
||||
* @param $theme
|
||||
* The loaded $theme object as returned by list_themes().
|
||||
@ -724,7 +727,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all currently available themes.
|
||||
* Returns a list of all currently available themes.
|
||||
*
|
||||
* Retrieved from the database, if available and the site is not in maintenance
|
||||
* mode; otherwise compiled freshly from the filesystem.
|
||||
@ -766,7 +769,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
|
||||
* their base theme), direct sub-themes of sub-themes, etc. The keys are
|
||||
* the themes' machine names, and the values are the themes' human-readable
|
||||
* names. This element is not set if there are no themes on the system that
|
||||
* declare this theme as their base theme.
|
||||
* declare this theme as their base theme.
|
||||
*/
|
||||
function list_themes($refresh = FALSE) {
|
||||
$list = &drupal_static(__FUNCTION__, array());
|
||||
@ -866,11 +869,18 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
/**
|
||||
* Generates themed output.
|
||||
*
|
||||
* All requests for themed output must go through this function. It examines
|
||||
* the request and routes it to the appropriate
|
||||
* All requests for themed output must go through this function (however,
|
||||
* calling the theme() function directly is strongly discouraged - see next
|
||||
* paragraph). It examines the request and routes it to the appropriate
|
||||
* @link themeable theme function or template @endlink, by checking the theme
|
||||
* registry.
|
||||
*
|
||||
* Avoid calling this function directly. It is preferable to replace direct
|
||||
* calls to the theme() function with calls to drupal_render() by passing a
|
||||
* render array with a #theme key to drupal_render(), which in turn calls
|
||||
* theme().
|
||||
*
|
||||
* @section sec_theme_hooks Theme Hooks
|
||||
* Most commonly, the first argument to this function is the name of the theme
|
||||
* hook. For instance, to theme a taxonomy term, the theme hook name is
|
||||
* 'taxonomy_term'. Modules register theme hooks within a hook_theme()
|
||||
@ -882,6 +892,7 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
* underscores changed to hyphens, so for the 'taxonomy_term' theme hook, the
|
||||
* default template is 'taxonomy-term.tpl.php'.
|
||||
*
|
||||
* @subsection sub_overriding_theme_hooks Overriding Theme Hooks
|
||||
* Themes may also register new theme hooks within a hook_theme()
|
||||
* implementation, but it is more common for themes to override default
|
||||
* implementations provided by modules than to register entirely new theme
|
||||
@ -894,21 +905,22 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
* rendering engine, it overrides the default implementation of the 'page' theme
|
||||
* hook by containing a 'page.tpl.php' file within its folder structure).
|
||||
*
|
||||
* @subsection sub_preprocess_templates Preprocessing for Template Files
|
||||
* If the implementation is a template file, several functions are called
|
||||
* before the template file is invoked, to modify the $variables array. These
|
||||
* fall into the "preprocessing" phase and the "processing" phase, and are
|
||||
* executed (if they exist), in the following order (note that in the following
|
||||
* list, HOOK indicates the theme hook name, MODULE indicates a module name,
|
||||
* THEME indicates a theme name, and ENGINE indicates a theme engine name):
|
||||
* - template_preprocess(&$variables, $hook): Creates a default set of variables
|
||||
* for all theme hooks with template implementations.
|
||||
* - template_preprocess(&$variables, $hook): Creates a default set of
|
||||
* variables for all theme hooks with template implementations.
|
||||
* - template_preprocess_HOOK(&$variables): Should be implemented by the module
|
||||
* that registers the theme hook, to set up default variables.
|
||||
* - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
|
||||
* implementing modules.
|
||||
* - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
|
||||
* all implementing modules, so that modules that didn't define the theme hook
|
||||
* can alter the variables.
|
||||
* all implementing modules, so that modules that didn't define the theme
|
||||
* hook can alter the variables.
|
||||
* - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
|
||||
* set necessary variables for all theme hooks with template implementations.
|
||||
* - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
|
||||
@ -942,12 +954,14 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
* - THEME_process_HOOK(&$variables): Allows the theme to process the
|
||||
* variables specific to the theme hook.
|
||||
*
|
||||
* @subsection sub_preprocess_theme_funcs Preprocessing for Theme Functions
|
||||
* If the implementation is a function, only the theme-hook-specific preprocess
|
||||
* and process functions (the ones ending in _HOOK) are called from the
|
||||
* list above. This is because theme hooks with function implementations
|
||||
* need to be fast, and calling the non-theme-hook-specific preprocess and
|
||||
* process functions for them would incur a noticeable performance penalty.
|
||||
*
|
||||
* @subsection sub_alternate_suggestions Suggesting Alternate Hooks
|
||||
* There are two special variables that these preprocess and process functions
|
||||
* can set: 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be
|
||||
* merged together to form a list of 'suggested' alternate theme hooks to use,
|
||||
@ -963,10 +977,10 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
* @param $hook
|
||||
* The name of the theme hook to call. If the name contains a
|
||||
* double-underscore ('__') and there isn't an implementation for the full
|
||||
* name, the part before the '__' is checked. This allows a fallback to a more
|
||||
* generic implementation. For example, if theme('links__node', ...) is
|
||||
* called, but there is no implementation of that theme hook, then the 'links'
|
||||
* implementation is used. This process is iterative, so if
|
||||
* name, the part before the '__' is checked. This allows a fallback to a
|
||||
* more generic implementation. For example, if theme('links__node', ...) is
|
||||
* called, but there is no implementation of that theme hook, then the
|
||||
* 'links' implementation is used. This process is iterative, so if
|
||||
* theme('links__contextual__node', ...) is called, theme() checks for the
|
||||
* following implementations, and uses the first one that exists:
|
||||
* - links__contextual__node
|
||||
@ -989,6 +1003,7 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
|
||||
* @return
|
||||
* An HTML string representing the themed output.
|
||||
*
|
||||
* @see drupal_render()
|
||||
* @see themeable
|
||||
* @see hook_theme()
|
||||
* @see template_preprocess()
|
||||
@ -1014,6 +1029,7 @@ function theme($hook, $variables = array()) {
|
||||
}
|
||||
$hook = $candidate;
|
||||
}
|
||||
$theme_hook_original = $hook;
|
||||
|
||||
// If there's no implementation, check for more generic fallbacks. If there's
|
||||
// still no implementation, log an error and return an empty string.
|
||||
@ -1030,7 +1046,7 @@ function theme($hook, $variables = array()) {
|
||||
// Only log a message when not trying theme suggestions ($hook being an
|
||||
// array).
|
||||
if (!isset($candidate)) {
|
||||
watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
|
||||
watchdog('theme', 'Theme hook %hook not found.', array('%hook' => $hook), WATCHDOG_WARNING);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -1042,7 +1058,8 @@ function theme($hook, $variables = array()) {
|
||||
// point path_to_theme() to the currently used theme path:
|
||||
$theme_path = $info['theme path'];
|
||||
|
||||
// Include a file if the theme function or variable processor is held elsewhere.
|
||||
// Include a file if the theme function or variable processor is held
|
||||
// elsewhere.
|
||||
if (!empty($info['includes'])) {
|
||||
foreach ($info['includes'] as $include_file) {
|
||||
include_once DRUPAL_ROOT . '/' . $include_file;
|
||||
@ -1074,6 +1091,8 @@ function theme($hook, $variables = array()) {
|
||||
$variables += array($info['render element'] => array());
|
||||
}
|
||||
|
||||
$variables['theme_hook_original'] = $theme_hook_original;
|
||||
|
||||
// Invoke the variable processors, if any. The processors may specify
|
||||
// alternate suggestions for which hook's template/function to use. If the
|
||||
// hook is a suggestion of a base hook, invoke the variable processors of
|
||||
@ -1182,7 +1201,12 @@ function theme($hook, $variables = array()) {
|
||||
if (isset($info['path'])) {
|
||||
$template_file = $info['path'] . '/' . $template_file;
|
||||
}
|
||||
$output = $render_function($template_file, $variables);
|
||||
if (variable_get('theme_debug', FALSE)) {
|
||||
$output = _theme_render_template_debug($render_function, $template_file, $variables, $extension);
|
||||
}
|
||||
else {
|
||||
$output = $render_function($template_file, $variables);
|
||||
}
|
||||
}
|
||||
|
||||
// restore path_to_theme()
|
||||
@ -1191,14 +1215,14 @@ function theme($hook, $variables = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the current themed element.
|
||||
* Returns the path to the current themed element.
|
||||
*
|
||||
* It can point to the active theme or the module handling a themed implementation.
|
||||
* For example, when invoked within the scope of a theming call it will depend
|
||||
* on where the theming function is handled. If implemented from a module, it
|
||||
* will point to the module. If implemented from the active theme, it will point
|
||||
* to the active theme. When called outside the scope of a theming call, it will
|
||||
* always point to the active theme.
|
||||
* It can point to the active theme or the module handling a themed
|
||||
* implementation. For example, when invoked within the scope of a theming call
|
||||
* it will depend on where the theming function is handled. If implemented from
|
||||
* a module, it will point to the module. If implemented from the active theme,
|
||||
* it will point to the active theme. When called outside the scope of a
|
||||
* theming call, it will always point to the active theme.
|
||||
*/
|
||||
function path_to_theme() {
|
||||
global $theme_path;
|
||||
@ -1211,7 +1235,7 @@ function path_to_theme() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow themes and/or theme engines to easily discover overridden theme functions.
|
||||
* Allows themes and/or theme engines to discover overridden theme functions.
|
||||
*
|
||||
* @param $cache
|
||||
* The existing cache of theme hooks to test against.
|
||||
@ -1268,7 +1292,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow themes and/or theme engines to easily discover overridden templates.
|
||||
* Allows themes and/or theme engines to easily discover overridden templates.
|
||||
*
|
||||
* @param $cache
|
||||
* The existing cache of theme hooks to test against.
|
||||
@ -1345,7 +1369,8 @@ function drupal_find_theme_templates($cache, $extension, $path) {
|
||||
if ($matches) {
|
||||
foreach ($matches as $match) {
|
||||
$file = substr($match, 0, strpos($match, '.'));
|
||||
// Put the underscores back in for the hook name and register this pattern.
|
||||
// Put the underscores back in for the hook name and register this
|
||||
// pattern.
|
||||
$arg_name = isset($info['variables']) ? 'variables' : 'render element';
|
||||
$implementations[strtr($file, '-', '_')] = array(
|
||||
'template' => $file,
|
||||
@ -1361,7 +1386,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a setting for the current theme or for a given theme.
|
||||
* Retrieves a setting for the current theme or for a given theme.
|
||||
*
|
||||
* The final setting is obtained from the last value found in the following
|
||||
* sources:
|
||||
@ -1479,7 +1504,7 @@ function theme_get_setting($setting_name, $theme = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a system default template, which is essentially a PHP template.
|
||||
* Renders a system default template, which is essentially a PHP template.
|
||||
*
|
||||
* @param $template_file
|
||||
* The filename of the template to render.
|
||||
@ -1490,14 +1515,87 @@ function theme_get_setting($setting_name, $theme = NULL) {
|
||||
* The output generated by the template.
|
||||
*/
|
||||
function theme_render_template($template_file, $variables) {
|
||||
extract($variables, EXTR_SKIP); // Extract the variables to a local namespace
|
||||
ob_start(); // Start output buffering
|
||||
include DRUPAL_ROOT . '/' . $template_file; // Include the template file
|
||||
return ob_get_clean(); // End buffering and return its contents
|
||||
// Extract the variables to a local namespace
|
||||
extract($variables, EXTR_SKIP);
|
||||
|
||||
// Start output buffering
|
||||
ob_start();
|
||||
|
||||
// Include the template file
|
||||
include DRUPAL_ROOT . '/' . $template_file;
|
||||
|
||||
// End buffering and return its contents
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a given list of themes.
|
||||
* Renders a template for any engine.
|
||||
*
|
||||
* Includes the possibility to get debug output by setting the
|
||||
* theme_debug variable to TRUE.
|
||||
*
|
||||
* @param string $template_function
|
||||
* The function to call for rendering the template.
|
||||
* @param string $template_file
|
||||
* The filename of the template to render.
|
||||
* @param array $variables
|
||||
* A keyed array of variables that will appear in the output.
|
||||
* @param string $extension
|
||||
* The extension used by the theme engine for template files.
|
||||
*
|
||||
* @return string
|
||||
* The output generated by the template including debug information.
|
||||
*/
|
||||
function _theme_render_template_debug($template_function, $template_file, $variables, $extension) {
|
||||
$output = array(
|
||||
'debug_prefix' => '',
|
||||
'debug_info' => '',
|
||||
'rendered_markup' => call_user_func($template_function, $template_file, $variables),
|
||||
'debug_suffix' => '',
|
||||
);
|
||||
$output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
|
||||
$output['debug_prefix'] .= "\n<!-- CALL: theme('" . check_plain($variables['theme_hook_original']) . "') -->";
|
||||
// If there are theme suggestions, reverse the array so more specific
|
||||
// suggestions are shown first.
|
||||
if (!empty($variables['theme_hook_suggestions'])) {
|
||||
$variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
|
||||
}
|
||||
// Add debug output for directly called suggestions like
|
||||
// '#theme' => 'comment__node__article'.
|
||||
if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
|
||||
$derived_suggestions[] = $hook = $variables['theme_hook_original'];
|
||||
while ($pos = strrpos($hook, '__')) {
|
||||
$hook = substr($hook, 0, $pos);
|
||||
$derived_suggestions[] = $hook;
|
||||
}
|
||||
// Get the value of the base hook (last derived suggestion) and append it
|
||||
// to the end of all theme suggestions.
|
||||
$base_hook = array_pop($derived_suggestions);
|
||||
$variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
|
||||
$variables['theme_hook_suggestions'][] = $base_hook;
|
||||
}
|
||||
if (!empty($variables['theme_hook_suggestions'])) {
|
||||
$current_template = basename($template_file);
|
||||
$suggestions = $variables['theme_hook_suggestions'];
|
||||
// Only add the original theme hook if it wasn't a directly called
|
||||
// suggestion.
|
||||
if (strpos($variables['theme_hook_original'], '__') === FALSE) {
|
||||
$suggestions[] = $variables['theme_hook_original'];
|
||||
}
|
||||
foreach ($suggestions as &$suggestion) {
|
||||
$template = strtr($suggestion, '_', '-') . $extension;
|
||||
$prefix = ($template == $current_template) ? 'x' : '*';
|
||||
$suggestion = $prefix . ' ' . $template;
|
||||
}
|
||||
$output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n " . check_plain(implode("\n ", $suggestions)) . "\n-->";
|
||||
}
|
||||
$output['debug_info'] .= "\n<!-- BEGIN OUTPUT from '" . check_plain($template_file) . "' -->\n";
|
||||
$output['debug_suffix'] .= "\n<!-- END OUTPUT from '" . check_plain($template_file) . "' -->\n\n";
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a given list of themes.
|
||||
*
|
||||
* @param $theme_list
|
||||
* An array of theme names.
|
||||
@ -1522,7 +1620,7 @@ function theme_enable($theme_list) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a given list of themes.
|
||||
* Disables a given list of themes.
|
||||
*
|
||||
* @param $theme_list
|
||||
* An array of theme names.
|
||||
@ -1593,7 +1691,7 @@ function theme_status_messages($variables) {
|
||||
$output .= " </ul>\n";
|
||||
}
|
||||
else {
|
||||
$output .= $messages[0];
|
||||
$output .= reset($messages);
|
||||
}
|
||||
$output .= "</div>\n";
|
||||
}
|
||||
@ -1608,13 +1706,13 @@ function theme_status_messages($variables) {
|
||||
* theme('link') for rendering the anchor tag.
|
||||
*
|
||||
* To optimize performance for sites that don't need custom theming of links,
|
||||
* the l() function includes an inline copy of this function, and uses that copy
|
||||
* if none of the enabled modules or the active theme implement any preprocess
|
||||
* or process functions or override this theme implementation.
|
||||
* the l() function includes an inline copy of this function, and uses that
|
||||
* copy if none of the enabled modules or the active theme implement any
|
||||
* preprocess or process functions or override this theme implementation.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing the keys 'text', 'path', and 'options'. See
|
||||
* the l() function for information about these variables.
|
||||
* An associative array containing the keys 'text', 'path', and 'options'.
|
||||
* See the l() function for information about these variables.
|
||||
*
|
||||
* @see l()
|
||||
*/
|
||||
@ -1635,15 +1733,16 @@ function theme_link($variables) {
|
||||
* item in the links list.
|
||||
* - html: (optional) Whether or not 'title' is HTML. If set, the title
|
||||
* will not be passed through check_plain().
|
||||
* - attributes: (optional) Attributes for the anchor, or for the <span> tag
|
||||
* used in its place if no 'href' is supplied. If element 'class' is
|
||||
* - attributes: (optional) Attributes for the anchor, or for the <span>
|
||||
* tag used in its place if no 'href' is supplied. If element 'class' is
|
||||
* included, it must be an array of one or more class names.
|
||||
* If the 'href' element is supplied, the entire link array is passed to l()
|
||||
* as its $options parameter.
|
||||
* If the 'href' element is supplied, the entire link array is passed to
|
||||
* l() as its $options parameter.
|
||||
* - attributes: A keyed array of attributes for the UL containing the
|
||||
* list of links.
|
||||
* - heading: (optional) A heading to precede the links. May be an associative
|
||||
* array or a string. If it's an array, it can have the following elements:
|
||||
* - heading: (optional) A heading to precede the links. May be an
|
||||
* associative array or a string. If it's an array, it can have the
|
||||
* following elements:
|
||||
* - text: The heading text.
|
||||
* - level: The heading level (e.g. 'h2', 'h3').
|
||||
* - class: (optional) An array of the CSS classes for the heading.
|
||||
@ -1665,8 +1764,6 @@ function theme_links($variables) {
|
||||
$output = '';
|
||||
|
||||
if (count($links) > 0) {
|
||||
$output = '';
|
||||
|
||||
// Treat the heading first if it is present to prepend it to the
|
||||
// list of links.
|
||||
if (!empty($heading)) {
|
||||
@ -1747,8 +1844,8 @@ function theme_links($variables) {
|
||||
* attribute to be omitted in some cases. Therefore, this variable defaults
|
||||
* to an empty string, but can be set to NULL for the attribute to be
|
||||
* omitted. Usually, neither omission nor an empty string satisfies
|
||||
* accessibility requirements, so it is strongly encouraged for code calling
|
||||
* theme('image') to pass a meaningful value for this variable.
|
||||
* accessibility requirements, so it is strongly encouraged for code
|
||||
* calling theme('image') to pass a meaningful value for this variable.
|
||||
* - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
|
||||
* - http://www.w3.org/TR/xhtml1/dtds.html
|
||||
* - http://dev.w3.org/html5/spec/Overview.html#alt
|
||||
@ -1801,7 +1898,9 @@ function theme_breadcrumb($variables) {
|
||||
* - "data": The localized title of the table column.
|
||||
* - "field": The database field represented in the table column (required
|
||||
* if user is to be able to sort on this column).
|
||||
* - "sort": A default sort order for this column ("asc" or "desc").
|
||||
* - "sort": A default sort order for this column ("asc" or "desc"). Only
|
||||
* one column should be given a default sort order because table sorting
|
||||
* only applies to one column at a time.
|
||||
* - Any HTML attributes, such as "colspan", to apply to the column header
|
||||
* cell.
|
||||
* - rows: An array of table rows. Every row is an array of cells, or an
|
||||
@ -1960,25 +2059,24 @@ function theme_table($variables) {
|
||||
$flip = array('even' => 'odd', 'odd' => 'even');
|
||||
$class = 'even';
|
||||
foreach ($rows as $number => $row) {
|
||||
$attributes = array();
|
||||
|
||||
// Check if we're dealing with a simple or complex row
|
||||
if (isset($row['data'])) {
|
||||
foreach ($row as $key => $value) {
|
||||
if ($key == 'data') {
|
||||
$cells = $value;
|
||||
}
|
||||
else {
|
||||
$attributes[$key] = $value;
|
||||
}
|
||||
}
|
||||
$cells = $row['data'];
|
||||
$no_striping = isset($row['no_striping']) ? $row['no_striping'] : FALSE;
|
||||
|
||||
// Set the attributes array and exclude 'data' and 'no_striping'.
|
||||
$attributes = $row;
|
||||
unset($attributes['data']);
|
||||
unset($attributes['no_striping']);
|
||||
}
|
||||
else {
|
||||
$cells = $row;
|
||||
$attributes = array();
|
||||
$no_striping = FALSE;
|
||||
}
|
||||
if (count($cells)) {
|
||||
// Add odd/even class
|
||||
if (empty($row['no_striping'])) {
|
||||
if (!$no_striping) {
|
||||
$class = $flip[$class];
|
||||
$attributes['class'][] = $class;
|
||||
}
|
||||
@ -2005,7 +2103,8 @@ function theme_table($variables) {
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - style: Set to either 'asc' or 'desc', this determines which icon to show.
|
||||
* - style: Set to either 'asc' or 'desc', this determines which icon to
|
||||
* show.
|
||||
*/
|
||||
function theme_tablesort_indicator($variables) {
|
||||
if ($variables['style'] == "asc") {
|
||||
@ -2148,7 +2247,8 @@ function theme_feed_icon($variables) {
|
||||
* - script: To load JavaScript.
|
||||
* - #attributes: (optional) An array of HTML attributes to apply to the
|
||||
* tag.
|
||||
* - #value: (optional) A string containing tag content, such as inline CSS.
|
||||
* - #value: (optional) A string containing tag content, such as inline
|
||||
* CSS.
|
||||
* - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
|
||||
* wrapper prefix.
|
||||
* - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
|
||||
@ -2316,8 +2416,9 @@ function template_preprocess(&$variables, $hook) {
|
||||
global $user;
|
||||
static $count = array();
|
||||
|
||||
// Track run count for each hook to provide zebra striping.
|
||||
// See "template_preprocess_block()" which provides the same feature specific to blocks.
|
||||
// Track run count for each hook to provide zebra striping. See
|
||||
// "template_preprocess_block()" which provides the same feature specific to
|
||||
// blocks.
|
||||
$count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1;
|
||||
$variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
|
||||
$variables['id'] = $count[$hook]++;
|
||||
@ -2521,6 +2622,9 @@ function template_preprocess_page(&$variables) {
|
||||
if (!isset($variables['page'][$region_key])) {
|
||||
$variables['page'][$region_key] = array();
|
||||
}
|
||||
if ($region_content = drupal_get_region_content($region_key)) {
|
||||
$variables['page'][$region_key][]['#markup'] = $region_content;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up layout variable.
|
||||
@ -2677,13 +2781,13 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
|
||||
}
|
||||
|
||||
/**
|
||||
* The variables array generated here is a mirror of template_preprocess_page().
|
||||
* This preprocessor will run its course when theme_maintenance_page() is
|
||||
* invoked.
|
||||
* Process variables for maintenance-page.tpl.php.
|
||||
*
|
||||
* An alternate template file of "maintenance-page--offline.tpl.php" can be
|
||||
* used when the database is offline to hide errors and completely replace the
|
||||
* content.
|
||||
* The variables array generated here is a mirror of
|
||||
* template_preprocess_page(). This preprocessor will run its course when
|
||||
* theme_maintenance_page() is invoked. An alternate template file of
|
||||
* maintenance-page--offline.tpl.php can be used when the database is offline to
|
||||
* hide errors and completely replace the content.
|
||||
*
|
||||
* The $variables array contains the following arguments:
|
||||
* - $content
|
||||
@ -2777,10 +2881,13 @@ function template_preprocess_maintenance_page(&$variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme process function for theme_maintenance_field().
|
||||
*
|
||||
* The variables array generated here is a mirror of template_process_html().
|
||||
* This processor will run its course when theme_maintenance_page() is invoked.
|
||||
*
|
||||
* @see maintenance-page.tpl.php
|
||||
* @see template_process_html()
|
||||
*/
|
||||
function template_process_maintenance_page(&$variables) {
|
||||
$variables['head'] = drupal_get_html_head();
|
||||
@ -2792,7 +2899,7 @@ function template_process_maintenance_page(&$variables) {
|
||||
/**
|
||||
* Preprocess variables for region.tpl.php
|
||||
*
|
||||
* Prepare the values passed to the theme_region function to be passed into a
|
||||
* Prepares the values passed to the theme_region function to be passed into a
|
||||
* pluggable template engine. Uses the region name to generate a template file
|
||||
* suggestions. If none are found, the default region.tpl.php is used.
|
||||
*
|
||||
|
@ -10,9 +10,9 @@
|
||||
*
|
||||
* Used for site installs, updates and when the site is in maintenance mode.
|
||||
* It also applies when the database is unavailable or bootstrap was not
|
||||
* complete. Seven is always used for the initial install and update operations.
|
||||
* In other cases, Bartik is used, but this can be overridden by setting a
|
||||
* "maintenance_theme" key in the $conf variable in settings.php.
|
||||
* complete. Seven is always used for the initial install and update
|
||||
* operations. In other cases, Bartik is used, but this can be overridden by
|
||||
* setting a "maintenance_theme" key in the $conf variable in settings.php.
|
||||
*/
|
||||
function _drupal_maintenance_theme() {
|
||||
global $theme, $theme_key, $conf;
|
||||
@ -85,7 +85,7 @@ function _drupal_maintenance_theme() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This builds the registry when the site needs to bypass any database calls.
|
||||
* Builds the registry when the site needs to bypass any database calls.
|
||||
*/
|
||||
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
|
||||
return _theme_build_registry($theme, $base_theme, $theme_engine);
|
||||
@ -160,7 +160,7 @@ function theme_update_page($variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a report of the results from an operation run via authorize.php.
|
||||
* Returns HTML for a results report of an operation run by authorize.php.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
|
@ -113,13 +113,13 @@ function token_replace($text, array $data = array(), array $options = array()) {
|
||||
*/
|
||||
function token_scan($text) {
|
||||
// Matches tokens with the following pattern: [$type:$name]
|
||||
// $type and $name may not contain [ ] or whitespace characters.
|
||||
// $type may not contain : characters, but $name may.
|
||||
// $type and $name may not contain [ ] characters.
|
||||
// $type may not contain : or whitespace characters, but $name may.
|
||||
preg_match_all('/
|
||||
\[ # [ - pattern start
|
||||
([^\s\[\]:]*) # match $type not containing whitespace : [ or ]
|
||||
: # : - separator
|
||||
([^\s\[\]]*) # match $name not containing whitespace [ or ]
|
||||
([^\[\]]*) # match $name not containing [ or ]
|
||||
\] # ] - pattern end
|
||||
/x', $text, $matches);
|
||||
|
||||
@ -190,10 +190,10 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of tokens, returns those that begin with a specific prefix.
|
||||
* Returns a list of tokens that begin with a specific prefix.
|
||||
*
|
||||
* Used to extract a group of 'chained' tokens (such as [node:author:name]) from
|
||||
* the full list of tokens found in text. For example:
|
||||
* Used to extract a group of 'chained' tokens (such as [node:author:name])
|
||||
* from the full list of tokens found in text. For example:
|
||||
* @code
|
||||
* $data = array(
|
||||
* 'author:name' => '[node:author:name]',
|
||||
@ -230,8 +230,10 @@ function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
|
||||
/**
|
||||
* Returns metadata describing supported tokens.
|
||||
*
|
||||
* The metadata array contains token type, name, and description data as well as
|
||||
* an optional pointer indicating that the token chains to another set of tokens.
|
||||
* The metadata array contains token type, name, and description data as well
|
||||
* as an optional pointer indicating that the token chains to another set of
|
||||
* tokens.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* $data['types']['node'] = array(
|
||||
|
@ -1,5 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides Unicode-related conversions and operations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates an error during check for PHP unicode support.
|
||||
*/
|
||||
@ -19,8 +24,6 @@ define('UNICODE_MULTIBYTE', 1);
|
||||
/**
|
||||
* Matches Unicode characters that are word boundaries.
|
||||
*
|
||||
* @see http://unicode.org/glossary
|
||||
*
|
||||
* Characters with the following General_category (gc) property values are used
|
||||
* as word boundaries. While this does not fully conform to the Word Boundaries
|
||||
* algorithm described in http://unicode.org/reports/tr29, as PCRE does not
|
||||
@ -39,6 +42,8 @@ define('UNICODE_MULTIBYTE', 1);
|
||||
* Note that the PCRE property matcher is not used because we wanted to be
|
||||
* compatible with Unicode 5.2.0 regardless of the PCRE version used (and any
|
||||
* bugs in PCRE property tables).
|
||||
*
|
||||
* @see http://unicode.org/glossary
|
||||
*/
|
||||
define('PREG_CLASS_UNICODE_WORD_BOUNDARY',
|
||||
'\x{0}-\x{2F}\x{3A}-\x{40}\x{5B}-\x{60}\x{7B}-\x{A9}\x{AB}-\x{B1}\x{B4}' .
|
||||
@ -111,11 +116,15 @@ function _unicode_check() {
|
||||
if (ini_get('mbstring.encoding_translation') != 0) {
|
||||
return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.encoding_translation</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
|
||||
}
|
||||
if (ini_get('mbstring.http_input') != 'pass') {
|
||||
return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_input</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
|
||||
}
|
||||
if (ini_get('mbstring.http_output') != 'pass') {
|
||||
return array(UNICODE_ERROR, $t('Multibyte string output conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_output</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
|
||||
// mbstring.http_input and mbstring.http_output are deprecated and empty by
|
||||
// default in PHP 5.6.
|
||||
if (version_compare(PHP_VERSION, '5.6.0') == -1) {
|
||||
if (ini_get('mbstring.http_input') != 'pass') {
|
||||
return array(UNICODE_ERROR, $t('Multibyte string input conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_input</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
|
||||
}
|
||||
if (ini_get('mbstring.http_output') != 'pass') {
|
||||
return array(UNICODE_ERROR, $t('Multibyte string output conversion in PHP is active and must be disabled. Check the php.ini <em>mbstring.http_output</em> setting. Please refer to the <a href="@url">PHP mbstring documentation</a> for more information.', array('@url' => 'http://www.php.net/mbstring')));
|
||||
}
|
||||
}
|
||||
|
||||
// Set appropriate configuration
|
||||
@ -125,7 +134,7 @@ function _unicode_check() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Unicode library status and errors.
|
||||
* Returns Unicode library status and errors.
|
||||
*/
|
||||
function unicode_requirements() {
|
||||
// Ensure translations don't break during installation.
|
||||
@ -157,14 +166,14 @@ function unicode_requirements() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a new XML parser.
|
||||
* Prepares a new XML parser.
|
||||
*
|
||||
* This is a wrapper around xml_parser_create() which extracts the encoding from
|
||||
* the XML data first and sets the output encoding to UTF-8. This function should
|
||||
* be used instead of xml_parser_create(), because PHP 4's XML parser doesn't
|
||||
* check the input encoding itself. "Starting from PHP 5, the input encoding is
|
||||
* automatically detected, so that the encoding parameter specifies only the
|
||||
* output encoding."
|
||||
* This is a wrapper around xml_parser_create() which extracts the encoding
|
||||
* from the XML data first and sets the output encoding to UTF-8. This function
|
||||
* should be used instead of xml_parser_create(), because PHP 4's XML parser
|
||||
* doesn't check the input encoding itself. "Starting from PHP 5, the input
|
||||
* encoding is automatically detected, so that the encoding parameter specifies
|
||||
* only the output encoding."
|
||||
*
|
||||
* This is also where unsupported encodings will be converted. Callers should
|
||||
* take this into account: $data might have been changed after the call.
|
||||
@ -213,7 +222,7 @@ function drupal_xml_parser_create(&$data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data to UTF-8
|
||||
* Converts data to UTF-8.
|
||||
*
|
||||
* Requires the iconv, GNU recode or mbstring PHP extension.
|
||||
*
|
||||
@ -244,15 +253,15 @@ function drupal_convert_to_utf8($data, $encoding) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a UTF-8-encoded string safely to a number of bytes.
|
||||
* Truncates a UTF-8-encoded string safely to a number of bytes.
|
||||
*
|
||||
* If the end position is in the middle of a UTF-8 sequence, it scans backwards
|
||||
* until the beginning of the byte sequence.
|
||||
*
|
||||
* Use this function whenever you want to chop off a string at an unsure
|
||||
* location. On the other hand, if you're sure that you're splitting on a
|
||||
* character boundary (e.g. after using strpos() or similar), you can safely use
|
||||
* substr() instead.
|
||||
* character boundary (e.g. after using strpos() or similar), you can safely
|
||||
* use substr() instead.
|
||||
*
|
||||
* @param $string
|
||||
* The string to truncate.
|
||||
@ -306,7 +315,7 @@ function drupal_truncate_bytes($string, $len) {
|
||||
* boundaries, giving you "See myverylongurl..." (assuming you had set
|
||||
* $add_ellipses to TRUE).
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The truncated string.
|
||||
*/
|
||||
function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1) {
|
||||
@ -356,8 +365,7 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes MIME/HTTP header values that contain non-ASCII, UTF-8 encoded
|
||||
* characters.
|
||||
* Encodes MIME/HTTP header values that contain incorrectly encoded characters.
|
||||
*
|
||||
* For example, mime_header_encode('tést.txt') returns "=?UTF-8?B?dMOpc3QudHh0?=".
|
||||
*
|
||||
@ -369,6 +377,14 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
|
||||
* each chunk starts and ends on a character boundary.
|
||||
* - Using \n as the chunk separator may cause problems on some systems and may
|
||||
* have to be changed to \r\n or \r.
|
||||
*
|
||||
* @param $string
|
||||
* The header to encode.
|
||||
*
|
||||
* @return string
|
||||
* The mime-encoded header.
|
||||
*
|
||||
* @see mime_header_decode()
|
||||
*/
|
||||
function mime_header_encode($string) {
|
||||
if (preg_match('/[^\x20-\x7E]/', $string)) {
|
||||
@ -388,7 +404,15 @@ function mime_header_encode($string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Complement to mime_header_encode
|
||||
* Decodes MIME/HTTP encoded header values.
|
||||
*
|
||||
* @param $header
|
||||
* The header to decode.
|
||||
*
|
||||
* @return string
|
||||
* The mime-decoded header.
|
||||
*
|
||||
* @see mime_header_encode()
|
||||
*/
|
||||
function mime_header_decode($header) {
|
||||
// First step: encoded chunks followed by other encoded chunks (need to collapse whitespace)
|
||||
@ -398,7 +422,17 @@ function mime_header_decode($header) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to mime_header_decode
|
||||
* Decodes encoded header data passed from mime_header_decode().
|
||||
*
|
||||
* Callback for preg_replace_callback() within mime_header_decode().
|
||||
*
|
||||
* @param $matches
|
||||
* The array of matches from preg_replace_callback().
|
||||
*
|
||||
* @return string
|
||||
* The mime-decoded string.
|
||||
*
|
||||
* @see mime_header_decode()
|
||||
*/
|
||||
function _mime_header_decode($matches) {
|
||||
// Regexp groups:
|
||||
@ -415,9 +449,9 @@ function _mime_header_decode($matches) {
|
||||
/**
|
||||
* Decodes all HTML entities (including numerical ones) to regular UTF-8 bytes.
|
||||
*
|
||||
* Double-escaped entities will only be decoded once ("&lt;" becomes "<",
|
||||
* not "<"). Be careful when using this function, as decode_entities can revert
|
||||
* previous sanitization efforts (<script> will become <script>).
|
||||
* Double-escaped entities will only be decoded once ("&lt;" becomes "<"
|
||||
* , not "<"). Be careful when using this function, as decode_entities can
|
||||
* revert previous sanitization efforts (<script> will become <script>).
|
||||
*
|
||||
* @param $text
|
||||
* The text to decode entities in.
|
||||
@ -430,8 +464,15 @@ function decode_entities($text) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the amount of characters in a UTF-8 string. This is less than or
|
||||
* equal to the byte count.
|
||||
* Counts the number of characters in a UTF-8 string.
|
||||
*
|
||||
* This is less than or equal to the byte count.
|
||||
*
|
||||
* @param $text
|
||||
* The string to run the operation on.
|
||||
*
|
||||
* @return integer
|
||||
* The length of the string.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
@ -449,6 +490,12 @@ function drupal_strlen($text) {
|
||||
/**
|
||||
* Uppercase a UTF-8 string.
|
||||
*
|
||||
* @param $text
|
||||
* The string to run the operation on.
|
||||
*
|
||||
* @return string
|
||||
* The string in uppercase.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
function drupal_strtoupper($text) {
|
||||
@ -468,6 +515,12 @@ function drupal_strtoupper($text) {
|
||||
/**
|
||||
* Lowercase a UTF-8 string.
|
||||
*
|
||||
* @param $text
|
||||
* The string to run the operation on.
|
||||
*
|
||||
* @return string
|
||||
* The string in lowercase.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
function drupal_strtolower($text) {
|
||||
@ -485,15 +538,28 @@ function drupal_strtolower($text) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for case conversion of Latin-1.
|
||||
* Used for flipping U+C0-U+DE to U+E0-U+FD and back.
|
||||
* Flips U+C0-U+DE to U+E0-U+FD and back.
|
||||
*
|
||||
* @param $matches
|
||||
* An array of matches.
|
||||
*
|
||||
* @return array
|
||||
* The Latin-1 version of the array of matches.
|
||||
*
|
||||
* @see drupal_strtolower()
|
||||
*/
|
||||
function _unicode_caseflip($matches) {
|
||||
return $matches[0][0] . chr(ord($matches[0][1]) ^ 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalize the first letter of a UTF-8 string.
|
||||
* Capitalizes the first letter of a UTF-8 string.
|
||||
*
|
||||
* @param $text
|
||||
* The string to convert.
|
||||
*
|
||||
* @return
|
||||
* The string with the first letter as uppercase.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
@ -503,12 +569,21 @@ function drupal_ucfirst($text) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut off a piece of a string based on character indices and counts. Follows
|
||||
* the same behavior as PHP's own substr() function.
|
||||
* Cuts off a piece of a string based on character indices and counts.
|
||||
*
|
||||
* Note that for cutting off a string at a known character/substring
|
||||
* location, the usage of PHP's normal strpos/substr is safe and
|
||||
* much faster.
|
||||
* Follows the same behavior as PHP's own substr() function. Note that for
|
||||
* cutting off a string at a known character/substring location, the usage of
|
||||
* PHP's normal strpos/substr is safe and much faster.
|
||||
*
|
||||
* @param $text
|
||||
* The input string.
|
||||
* @param $start
|
||||
* The position at which to start reading.
|
||||
* @param $length
|
||||
* The number of characters to read.
|
||||
*
|
||||
* @return
|
||||
* The shortened string.
|
||||
*
|
||||
* @ingroup php_wrappers
|
||||
*/
|
||||
|
@ -38,7 +38,7 @@ function update_fix_compatibility() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test compatibility of a module or theme.
|
||||
* Tests the compatibility of a module or theme.
|
||||
*/
|
||||
function update_check_incompatibility($name, $type = 'module') {
|
||||
static $themes, $modules;
|
||||
@ -908,7 +908,7 @@ function update_get_d6_session_name() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform one update and store the results for display on finished page.
|
||||
* Performs one update and stores the results for display on the results page.
|
||||
*
|
||||
* If an update function completes successfully, it should return a message
|
||||
* as a string indicating success, for example:
|
||||
@ -1008,7 +1008,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
|
||||
class DrupalUpdateException extends Exception { }
|
||||
|
||||
/**
|
||||
* Start the database update batch process.
|
||||
* Starts the database update batch process.
|
||||
*
|
||||
* @param $start
|
||||
* An array whose keys contain the names of modules to be updated during the
|
||||
@ -1078,7 +1078,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the update process and store results for eventual display.
|
||||
* Finishes the update process and stores the results for eventual display.
|
||||
*
|
||||
* After the updates run, all caches are flushed. The update results are
|
||||
* stored into the session (for example, to be displayed on the update results
|
||||
@ -1115,7 +1115,7 @@ function update_finished($success, $results, $operations) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all the pending database updates.
|
||||
* Returns a list of all the pending database updates.
|
||||
*
|
||||
* @return
|
||||
* An associative array keyed by module name which contains all information
|
||||
@ -1409,7 +1409,7 @@ function update_already_performed($module, $number) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke hook_update_dependencies() in all installed modules.
|
||||
* Invokes hook_update_dependencies() in all installed modules.
|
||||
*
|
||||
* This function is similar to module_invoke_all(), with the main difference
|
||||
* that it does not require that a module be enabled to invoke its hook, only
|
||||
|
@ -12,6 +12,7 @@
|
||||
* The variable to export.
|
||||
* @param $prefix
|
||||
* A prefix that will be added at the beginning of every lines of the output.
|
||||
*
|
||||
* @return
|
||||
* The variable exported in a way compatible to Drupal's coding standards.
|
||||
*/
|
||||
|
@ -178,7 +178,41 @@ function xmlrpc_message_parse($xmlrpc_message) {
|
||||
xml_set_element_handler($xmlrpc_message->_parser, 'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
|
||||
xml_set_character_data_handler($xmlrpc_message->_parser, 'xmlrpc_message_cdata');
|
||||
xmlrpc_message_set($xmlrpc_message);
|
||||
if (!xml_parse($xmlrpc_message->_parser, $xmlrpc_message->message)) {
|
||||
|
||||
// Strip XML declaration.
|
||||
$header = preg_replace('/<\?xml.*?\?'.'>/s', '', substr($xmlrpc_message->message, 0, 100), 1);
|
||||
$xml = trim(substr_replace($xmlrpc_message->message, $header, 0, 100));
|
||||
if ($xml == '') {
|
||||
return FALSE;
|
||||
}
|
||||
// Strip DTD.
|
||||
$header = preg_replace('/^<!DOCTYPE[^>]*+>/i', '', substr($xml, 0, 200), 1);
|
||||
$xml = trim(substr_replace($xml, $header, 0, 200));
|
||||
if ($xml == '') {
|
||||
return FALSE;
|
||||
}
|
||||
// Confirm the XML now starts with a valid root tag. A root tag can end in [> \t\r\n]
|
||||
$root_tag = substr($xml, 0, strcspn(substr($xml, 0, 20), "> \t\r\n"));
|
||||
// Reject a second DTD.
|
||||
if (strtoupper($root_tag) == '<!DOCTYPE') {
|
||||
return FALSE;
|
||||
}
|
||||
if (!in_array($root_tag, array('<methodCall', '<methodResponse', '<fault'))) {
|
||||
return FALSE;
|
||||
}
|
||||
// Skip parsing if there is an unreasonably large number of tags.
|
||||
try {
|
||||
$dom = new DOMDocument();
|
||||
@$dom->loadXML($xml);
|
||||
if ($dom->getElementsByTagName('*')->length > variable_get('xmlrpc_message_maximum_tag_count', 30000)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!xml_parse($xmlrpc_message->_parser, $xml)) {
|
||||
return FALSE;
|
||||
}
|
||||
xml_parser_free($xmlrpc_message->_parser);
|
||||
|
@ -9,7 +9,9 @@
|
||||
* Invokes XML-RPC methods on this server.
|
||||
*
|
||||
* @param array $callbacks
|
||||
* Array of external XML-RPC method names with the callbacks they map to.
|
||||
* Either an associative array of external XML-RPC method names as keys with
|
||||
* the callbacks they map to as values, or a more complex structure
|
||||
* describing XML-RPC callbacks as returned from hook_xmlrpc().
|
||||
*/
|
||||
function xmlrpc_server($callbacks) {
|
||||
$xmlrpc_server = new stdClass();
|
||||
|
@ -6,12 +6,12 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Root directory of Drupal installation.
|
||||
* Defines the root directory of the Drupal installation.
|
||||
*/
|
||||
define('DRUPAL_ROOT', getcwd());
|
||||
|
||||
/**
|
||||
* Global flag to indicate that site is in installation mode.
|
||||
* Global flag to indicate the site is in installation mode.
|
||||
*/
|
||||
define('MAINTENANCE_MODE', 'install');
|
||||
|
||||
|
31
misc/ajax.js
31
misc/ajax.js
@ -348,7 +348,7 @@ Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) {
|
||||
// this is only needed for IFRAME submissions.
|
||||
var v = $.fieldValue(this.element);
|
||||
if (v !== null) {
|
||||
options.extraData[this.element.name] = v;
|
||||
options.extraData[this.element.name] = Drupal.checkPlain(v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ Drupal.ajax.prototype.success = function (response, status) {
|
||||
Drupal.freezeHeight();
|
||||
|
||||
for (var i in response) {
|
||||
if (response[i]['command'] && this.commands[response[i]['command']]) {
|
||||
if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) {
|
||||
this.commands[response[i]['command']](this, response[i], status);
|
||||
}
|
||||
}
|
||||
@ -616,6 +616,33 @@ Drupal.ajax.prototype.commands = {
|
||||
.removeClass('odd even')
|
||||
.filter(':even').addClass('odd').end()
|
||||
.filter(':odd').addClass('even');
|
||||
},
|
||||
|
||||
/**
|
||||
* Command to add css.
|
||||
*
|
||||
* Uses the proprietary addImport method if available as browsers which
|
||||
* support that method ignore @import statements in dynamically added
|
||||
* stylesheets.
|
||||
*/
|
||||
add_css: function (ajax, response, status) {
|
||||
// Add the styles in the normal way.
|
||||
$('head').prepend(response.data);
|
||||
// Add imports in the styles using the addImport method if available.
|
||||
var match, importMatch = /^@import url\("(.*)"\);$/igm;
|
||||
if (document.styleSheets[0].addImport && importMatch.test(response.data)) {
|
||||
importMatch.lastIndex = 0;
|
||||
while (match = importMatch.exec(response.data)) {
|
||||
document.styleSheets[0].addImport(match[1]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Command to update a form's build ID.
|
||||
*/
|
||||
updateBuildId: function(ajax, response, status) {
|
||||
$('input[name="form_build_id"][value="' + response['old'] + '"]').val(response['new']);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -114,6 +114,7 @@ Drupal.jsAC.prototype.onkeyup = function (input, e) {
|
||||
*/
|
||||
Drupal.jsAC.prototype.select = function (node) {
|
||||
this.input.value = $(node).data('autocompleteValue');
|
||||
$(this.input).trigger('autocompleteSelect', [node]);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -167,7 +168,7 @@ Drupal.jsAC.prototype.unhighlight = function (node) {
|
||||
Drupal.jsAC.prototype.hidePopup = function (keycode) {
|
||||
// Select item if the right key or mousebutton was pressed.
|
||||
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
|
||||
this.input.value = $(this.selected).data('autocompleteValue');
|
||||
this.select(this.selected);
|
||||
}
|
||||
// Hide popup.
|
||||
var popup = this.popup;
|
||||
@ -220,7 +221,7 @@ Drupal.jsAC.prototype.found = function (matches) {
|
||||
for (key in matches) {
|
||||
$('<li></li>')
|
||||
.html($('<div></div>').html(matches[key]))
|
||||
.mousedown(function () { ac.select(this); })
|
||||
.mousedown(function () { ac.hidePopup(this); })
|
||||
.mouseover(function () { ac.highlight(this); })
|
||||
.mouseout(function () { ac.unhighlight(this); })
|
||||
.data('autocompleteValue', key)
|
||||
|
BIN
misc/favicon.ico
BIN
misc/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 5.3 KiB |
@ -80,7 +80,7 @@ Drupal.behaviors.machineName = {
|
||||
// changes, but only if there is no machine name yet; i.e., only upon
|
||||
// initial creation, not when editing.
|
||||
if ($target.val() == '') {
|
||||
$source.bind('keyup.machineName change.machineName', function () {
|
||||
$source.bind('keyup.machineName change.machineName input.machineName', function () {
|
||||
machine = self.transliterate($(this).val(), options);
|
||||
// Set the machine name to the transliterated value.
|
||||
if (machine != '') {
|
||||
|
@ -373,7 +373,7 @@ states.Trigger.states = {
|
||||
|
||||
checked: {
|
||||
'change': function () {
|
||||
return this.attr('checked');
|
||||
return this.is(':checked');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -500,7 +500,7 @@ Drupal.tableDrag.prototype.dragRow = function (event, self) {
|
||||
if (self.indentEnabled) {
|
||||
var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x;
|
||||
// Set the number of indentations the mouse has been moved left or right.
|
||||
var indentDiff = Math.round(xDiff / self.indentAmount * self.rtl);
|
||||
var indentDiff = Math.round(xDiff / self.indentAmount);
|
||||
// Indent the row with our estimated diff, which may be further
|
||||
// restricted according to the rows around this row.
|
||||
var indentChange = self.rowObject.indent(indentDiff);
|
||||
|
@ -126,7 +126,7 @@ Drupal.tableHeader.prototype.eventhandlerRecalculateStickyHeader = function (eve
|
||||
$stickyCell.css('display', 'none');
|
||||
}
|
||||
}
|
||||
this.stickyTable.css('width', this.originalTable.css('width'));
|
||||
this.stickyTable.css('width', this.originalTable.outerWidth());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -57,10 +57,14 @@ Drupal.tableSelect = function () {
|
||||
// Keep track of the last checked checkbox.
|
||||
lastChecked = e.target;
|
||||
});
|
||||
|
||||
// If all checkboxes are checked on page load, make sure the select-all one
|
||||
// is checked too, otherwise keep unchecked.
|
||||
updateSelectAll((checkboxes.length == $(checkboxes).filter(':checked').length));
|
||||
};
|
||||
|
||||
Drupal.tableSelectRange = function (from, to, state) {
|
||||
// We determine the looping mode based on the the order of from and to.
|
||||
// We determine the looping mode based on the order of from and to.
|
||||
var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
|
||||
|
||||
// Traverse through the sibling nodes.
|
||||
|
BIN
misc/throbber-active.gif
Normal file
BIN
misc/throbber-active.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
misc/throbber-inactive.png
Normal file
BIN
misc/throbber-inactive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 320 B |
@ -134,6 +134,8 @@ Drupal.verticalTab.prototype = {
|
||||
tabShow: function () {
|
||||
// Display the tab.
|
||||
this.item.show();
|
||||
// Show the vertical tabs.
|
||||
this.item.closest('.vertical-tabs').show();
|
||||
// Update .first marker for items. We need recurse from parent to retain the
|
||||
// actual DOM element order as jQuery implements sortOrder, but not as public
|
||||
// method.
|
||||
@ -164,6 +166,10 @@ Drupal.verticalTab.prototype = {
|
||||
if ($firstTab.length) {
|
||||
$firstTab.data('verticalTab').focus();
|
||||
}
|
||||
// Hide the vertical tabs (if no tabs remain).
|
||||
else {
|
||||
this.item.closest('.vertical-tabs').hide();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Right-to-Left styles for theme in the Aggregator module.
|
||||
*/
|
||||
|
||||
#aggregator .feed-source .feed-icon {
|
||||
float: left;
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Admin page callbacks for the aggregator module.
|
||||
* Administration page callbacks for the Aggregator module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback; displays the aggregator administration page.
|
||||
* Page callback: Displays the Aggregator module administration page.
|
||||
*/
|
||||
function aggregator_admin_overview() {
|
||||
return aggregator_view();
|
||||
@ -16,7 +16,7 @@ function aggregator_admin_overview() {
|
||||
* Displays the aggregator administration page.
|
||||
*
|
||||
* @return
|
||||
* The page HTML.
|
||||
* A HTML-formatted string with administration page content.
|
||||
*/
|
||||
function aggregator_view() {
|
||||
$result = db_query('SELECT f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block ORDER BY f.title');
|
||||
@ -56,8 +56,8 @@ function aggregator_view() {
|
||||
* Form constructor for adding and editing feed sources.
|
||||
*
|
||||
* @param $feed
|
||||
* If editing a feed, the feed to edit as a PHP stdClass value; if adding a
|
||||
* new feed, NULL.
|
||||
* (optional) If editing a feed, the feed to edit as a PHP stdClass value; if
|
||||
* adding a new feed, NULL. Defaults to NULL.
|
||||
*
|
||||
* @ingroup forms
|
||||
* @see aggregator_form_feed_validate()
|
||||
@ -165,6 +165,7 @@ function aggregator_form_feed_validate($form, &$form_state) {
|
||||
* Form submission handler for aggregator_form_feed().
|
||||
*
|
||||
* @see aggregator_form_feed_validate()
|
||||
*
|
||||
* @todo Add delete confirmation dialog.
|
||||
*/
|
||||
function aggregator_form_feed_submit($form, &$form_state) {
|
||||
@ -398,7 +399,7 @@ function _aggregator_parse_opml($opml) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; refreshes a feed, then redirects to the overview page.
|
||||
* Page callback: Refreshes a feed, then redirects to the overview page.
|
||||
*
|
||||
* @param $feed
|
||||
* An object describing the feed to be refreshed.
|
||||
@ -590,6 +591,7 @@ function aggregator_form_category_validate($form, &$form_state) {
|
||||
* Form submission handler for aggregator_form_category().
|
||||
*
|
||||
* @see aggregator_form_category_validate()
|
||||
*
|
||||
* @todo Add delete confirmation dialog.
|
||||
*/
|
||||
function aggregator_form_category_submit($form, &$form_state) {
|
||||
|
@ -189,7 +189,7 @@ function hook_aggregator_process($feed) {
|
||||
*
|
||||
* @ingroup aggregator
|
||||
*/
|
||||
function hook_aggregator_process_info($feed) {
|
||||
function hook_aggregator_process_info() {
|
||||
return array(
|
||||
'title' => t('Default processor'),
|
||||
'description' => t('Creates lightweight records of feed items.'),
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Styles for theme in the Aggregator module.
|
||||
*/
|
||||
|
||||
#aggregator .feed-source .feed-title {
|
||||
margin-top: 0;
|
||||
|
@ -27,7 +27,7 @@ function aggregator_aggregator_fetch($feed) {
|
||||
$headers['If-None-Match'] = $feed->etag;
|
||||
}
|
||||
if ($feed->modified) {
|
||||
$headers['If-Modified-Since'] = gmdate(DATE_RFC1123, $feed->modified);
|
||||
$headers['If-Modified-Since'] = gmdate(DATE_RFC7231, $feed->modified);
|
||||
}
|
||||
|
||||
// Request feed.
|
||||
|
@ -6,3 +6,9 @@ core = 7.x
|
||||
files[] = aggregator.test
|
||||
configure = admin/config/services/aggregator/settings
|
||||
stylesheets[all][] = aggregator.css
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -260,6 +260,7 @@ function aggregator_schema() {
|
||||
'primary key' => array('iid'),
|
||||
'indexes' => array(
|
||||
'fid' => array('fid'),
|
||||
'timestamp' => array('timestamp'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'aggregator_feed' => array(
|
||||
@ -325,6 +326,15 @@ function aggregator_update_7003() {
|
||||
db_add_index('aggregator_feed', 'url', array(array('url', 255)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add index on timestamp.
|
||||
*/
|
||||
function aggregator_update_7004() {
|
||||
if (!db_index_exists('aggregator_item', 'timestamp')) {
|
||||
db_add_index('aggregator_item', 'timestamp', array('timestamp'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-7.x-extra"
|
||||
*/
|
||||
|
@ -266,13 +266,13 @@ function aggregator_menu() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Title callback: Returns a title for aggregatory category pages.
|
||||
* Title callback: Returns a title for aggregator category pages.
|
||||
*
|
||||
* @param $category
|
||||
* An aggregator category.
|
||||
*
|
||||
* @return
|
||||
* An aggregator category title.
|
||||
* A string with the aggregator category title.
|
||||
*/
|
||||
function _aggregator_category_title($category) {
|
||||
return $category['title'];
|
||||
@ -723,7 +723,7 @@ function theme_aggregator_block_item($variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely renders HTML content, as allowed.
|
||||
* Renders the HTML content safely, as allowed.
|
||||
*
|
||||
* @param $value
|
||||
* The content to be filtered.
|
||||
@ -739,7 +739,7 @@ function aggregator_filter_xss($value) {
|
||||
* Checks and sanitizes the aggregator configuration.
|
||||
*
|
||||
* Goes through all fetchers, parsers and processors and checks whether they
|
||||
* are available. If one is missing resets to standard configuration.
|
||||
* are available. If one is missing, resets to standard configuration.
|
||||
*
|
||||
* @return
|
||||
* TRUE if this function resets the configuration; FALSE if not.
|
||||
@ -775,7 +775,7 @@ function aggregator_sanitize_configuration() {
|
||||
* Items count.
|
||||
*
|
||||
* @return
|
||||
* Plural-formatted "@count items"
|
||||
* A string that is plural-formatted as "@count items".
|
||||
*/
|
||||
function _aggregator_items($count) {
|
||||
return format_plural($count, '1 item', '@count items');
|
||||
|
@ -2,14 +2,14 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* User page callbacks for the aggregator module.
|
||||
* User page callbacks for the Aggregator module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback; displays the most recent items gathered from any feed.
|
||||
* Page callback: Displays the most recent items gathered from any feed.
|
||||
*
|
||||
* @return
|
||||
* The items HTML.
|
||||
* The rendered list of items for the feed.
|
||||
*/
|
||||
function aggregator_page_last() {
|
||||
drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
|
||||
@ -20,13 +20,15 @@ function aggregator_page_last() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays all the items captured from a particular feed.
|
||||
* Page callback: Displays all the items captured from the particular feed.
|
||||
*
|
||||
* @param $feed
|
||||
* The feed for which to display all items.
|
||||
*
|
||||
* @return
|
||||
* The rendered list of items for a feed.
|
||||
*
|
||||
* @see aggregator_menu()
|
||||
*/
|
||||
function aggregator_page_source($feed) {
|
||||
drupal_set_title($feed->title);
|
||||
@ -40,13 +42,13 @@ function aggregator_page_source($feed) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays a form with all items captured from a feed.
|
||||
* Page callback: Displays a form with all items captured from a feed.
|
||||
*
|
||||
* @param $feed
|
||||
* The feed for which to list all the aggregated items.
|
||||
* The feed for which to list all of the aggregated items.
|
||||
*
|
||||
* @return
|
||||
* The rendered list of items for a feed.
|
||||
* The rendered list of items for the feed.
|
||||
*
|
||||
* @see aggregator_page_source()
|
||||
*/
|
||||
@ -55,13 +57,13 @@ function aggregator_page_source_form($form, $form_state, $feed) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays all the items aggregated in a particular category.
|
||||
* Page callback: Displays all the items aggregated in a particular category.
|
||||
*
|
||||
* @param $category
|
||||
* The category for which to list all the aggregated items.
|
||||
* The category for which to list all of the aggregated items.
|
||||
*
|
||||
* @return
|
||||
* The rendered list of items for a category.
|
||||
* The rendered list of items for the feed.
|
||||
*/
|
||||
function aggregator_page_category($category) {
|
||||
drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
|
||||
@ -74,13 +76,13 @@ function aggregator_page_category($category) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays a form containing items aggregated in a category.
|
||||
* Page callback: Displays a form containing items aggregated in a category.
|
||||
*
|
||||
* @param $category
|
||||
* The category for which to list all the aggregated items.
|
||||
* The category for which to list all of the aggregated items.
|
||||
*
|
||||
* @return
|
||||
* The rendered list of items for a category.
|
||||
* The rendered list of items for the feed.
|
||||
*
|
||||
* @see aggregator_page_category()
|
||||
*/
|
||||
@ -166,7 +168,7 @@ function aggregator_feed_items_load($type, $data = NULL) {
|
||||
* The feed source URL.
|
||||
*
|
||||
* @return
|
||||
* The rendered list of items for a feed.
|
||||
* The rendered list of items for the feed.
|
||||
*/
|
||||
function _aggregator_page_list($items, $op, $feed_source = '') {
|
||||
if (user_access('administer news feeds') && ($op == 'categorize')) {
|
||||
@ -191,10 +193,14 @@ function _aggregator_page_list($items, $op, $feed_source = '') {
|
||||
* @param $items
|
||||
* An array of the feed items.
|
||||
* @param $feed_source
|
||||
* The feed source URL.
|
||||
* (optional) The feed source URL. Defaults to an empty string.
|
||||
*
|
||||
* @return array
|
||||
* An array of FAPI elements.
|
||||
*
|
||||
* @ingroup forms
|
||||
* @see aggregator_categorize_items_submit()
|
||||
* @see theme_aggregator_categorize_items()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function aggregator_categorize_items($items, $feed_source = '') {
|
||||
$form['#submit'][] = 'aggregator_categorize_items_submit';
|
||||
@ -334,7 +340,12 @@ function template_preprocess_aggregator_item(&$variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays all the feeds used by the aggregator.
|
||||
* Page callback: Displays all the feeds used by the aggregator.
|
||||
*
|
||||
* @return
|
||||
* An HTML-formatted string.
|
||||
*
|
||||
* @see aggregator_menu()
|
||||
*/
|
||||
function aggregator_page_sources() {
|
||||
$result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');
|
||||
@ -358,7 +369,12 @@ function aggregator_page_sources() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; displays all the categories used by the aggregator.
|
||||
* Page callback: Displays all the categories used by the Aggregator module.
|
||||
*
|
||||
* @return string
|
||||
* An HTML formatted string.
|
||||
*
|
||||
* @see aggregator_menu()
|
||||
*/
|
||||
function aggregator_page_categories() {
|
||||
$result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');
|
||||
@ -380,7 +396,10 @@ function aggregator_page_categories() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
|
||||
* Page callback: Generates an RSS 0.92 feed of aggregator items or categories.
|
||||
*
|
||||
* @return string
|
||||
* An HTML formatted string.
|
||||
*/
|
||||
function aggregator_page_rss() {
|
||||
$result = NULL;
|
||||
@ -448,12 +467,14 @@ function theme_aggregator_page_rss($variables) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; generates an OPML representation of all feeds.
|
||||
* Page callback: Generates an OPML representation of all feeds.
|
||||
*
|
||||
* @param $cid
|
||||
* If set, feeds are exported only from a category with this ID. Otherwise, all feeds are exported.
|
||||
* (optional) If set, feeds are exported only from a category with this ID.
|
||||
* Otherwise, all feeds are exported. Defaults to NULL.
|
||||
*
|
||||
* @return
|
||||
* The output XML.
|
||||
* An OPML formatted string.
|
||||
*/
|
||||
function aggregator_page_opml($cid = NULL) {
|
||||
if ($cid) {
|
||||
@ -468,14 +489,12 @@ function aggregator_page_opml($cid = NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the OPML page for a feed.
|
||||
* Prints the OPML page for the feed.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - feeds: An array of the feeds to theme.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_aggregator_page_opml($variables) {
|
||||
|
@ -131,6 +131,12 @@ function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
|
||||
*
|
||||
* Callback for drupal_map_assoc() within
|
||||
* aggregator_form_aggregator_admin_form_alter().
|
||||
*
|
||||
* @param $length
|
||||
* The desired length of teaser text, in bytes.
|
||||
*
|
||||
* @return
|
||||
* A translated string explaining the teaser string length.
|
||||
*/
|
||||
function _aggregator_characters($length) {
|
||||
return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
|
||||
|
@ -5,6 +5,9 @@
|
||||
* Tests for aggregator.module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines a base class for testing the Aggregator module.
|
||||
*/
|
||||
class AggregatorTestCase extends DrupalWebTestCase {
|
||||
function setUp() {
|
||||
parent::setUp('aggregator', 'aggregator_test');
|
||||
@ -13,10 +16,15 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an aggregator feed (simulate form submission on admin/config/services/aggregator/add/feed).
|
||||
* Creates an aggregator feed.
|
||||
*
|
||||
* This method simulates the form submission on path
|
||||
* admin/config/services/aggregator/add/feed.
|
||||
*
|
||||
* @param $feed_url
|
||||
* If given, feed will be created with this URL, otherwise /rss.xml will be used.
|
||||
* (optional) If given, feed will be created with this URL, otherwise
|
||||
* /rss.xml will be used. Defaults to NULL.
|
||||
*
|
||||
* @return $feed
|
||||
* Full feed object if possible.
|
||||
*
|
||||
@ -33,7 +41,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an aggregator feed.
|
||||
* Deletes an aggregator feed.
|
||||
*
|
||||
* @param $feed
|
||||
* Feed object representing the feed.
|
||||
@ -44,10 +52,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a randomly generated feed edit array.
|
||||
* Returns a randomly generated feed edit array.
|
||||
*
|
||||
* @param $feed_url
|
||||
* If given, feed will be created with this URL, otherwise /rss.xml will be used.
|
||||
* (optional) If given, feed will be created with this URL, otherwise
|
||||
* /rss.xml will be used. Defaults to NULL.
|
||||
* @return
|
||||
* A feed array.
|
||||
*/
|
||||
@ -68,7 +77,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of the randomly created feed array.
|
||||
* Returns the count of the randomly created feed array.
|
||||
*
|
||||
* @return
|
||||
* Number of feed items on default feed created by createFeed().
|
||||
@ -80,10 +89,13 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update feed items (simulate click to admin/config/services/aggregator/update/$fid).
|
||||
* Updates the feed items.
|
||||
*
|
||||
* This method simulates a click to
|
||||
* admin/config/services/aggregator/update/$fid.
|
||||
*
|
||||
* @param $feed
|
||||
* Feed object representing the feed.
|
||||
* Feed object representing the feed, passed by reference.
|
||||
* @param $expected_count
|
||||
* Expected number of feed items.
|
||||
*/
|
||||
@ -112,7 +124,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm item removal from a feed.
|
||||
* Confirms an item removal from a feed.
|
||||
*
|
||||
* @param $feed
|
||||
* Feed object representing the feed.
|
||||
@ -123,7 +135,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add and remove feed items and ensure that the count is zero.
|
||||
* Adds and removes feed items and ensure that the count is zero.
|
||||
*
|
||||
* @param $feed
|
||||
* Feed object representing the feed.
|
||||
@ -140,7 +152,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull feed categories from aggregator_category_feed table.
|
||||
* Pulls feed categories from {aggregator_category_feed} table.
|
||||
*
|
||||
* @param $feed
|
||||
* Feed object representing the feed.
|
||||
@ -154,7 +166,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull categories from aggregator_category table.
|
||||
* Pulls categories from {aggregator_category} table.
|
||||
*
|
||||
* @return
|
||||
* An associative array keyed by category ID and values are set to the
|
||||
* category names.
|
||||
*/
|
||||
function getCategories() {
|
||||
$categories = array();
|
||||
@ -165,14 +181,14 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
return $categories;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the feed name and URL is unique.
|
||||
* Checks whether the feed name and URL are unique.
|
||||
*
|
||||
* @param $feed_name
|
||||
* String containing the feed name to check.
|
||||
* @param $feed_url
|
||||
* String containing the feed URL to check.
|
||||
*
|
||||
* @return
|
||||
* TRUE if feed is unique.
|
||||
*/
|
||||
@ -182,10 +198,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a valid OPML file from an array of feeds.
|
||||
* Creates a valid OPML file from an array of feeds.
|
||||
*
|
||||
* @param $feeds
|
||||
* An array of feeds.
|
||||
*
|
||||
* @return
|
||||
* Path to valid OPML file.
|
||||
*/
|
||||
@ -223,7 +240,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an invalid OPML file.
|
||||
* Creates an invalid OPML file.
|
||||
*
|
||||
* @return
|
||||
* Path to invalid OPML file.
|
||||
@ -240,7 +257,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a valid but empty OPML file.
|
||||
* Creates a valid but empty OPML file.
|
||||
*
|
||||
* @return
|
||||
* Path to empty OPML file.
|
||||
@ -271,11 +288,15 @@ EOF;
|
||||
return $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'aggregator') . '/tests/aggregator_test_atom.xml';
|
||||
}
|
||||
|
||||
function getHtmlEntitiesSample() {
|
||||
return $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'aggregator') . '/tests/aggregator_test_title_entities.xml';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates sample article nodes.
|
||||
*
|
||||
* @param $count
|
||||
* (optional) The number of nodes to generate.
|
||||
* (optional) The number of nodes to generate. Defaults to five.
|
||||
*/
|
||||
function createSampleNodes($count = 5) {
|
||||
$langcode = LANGUAGE_NONE;
|
||||
@ -290,7 +311,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests aggregator configuration settings.
|
||||
* Tests functionality of the configuration settings in the Aggregator module.
|
||||
*/
|
||||
class AggregatorConfigurationTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
@ -321,6 +342,9 @@ class AggregatorConfigurationTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests adding aggregator feeds.
|
||||
*/
|
||||
class AddFeedTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -331,7 +355,7 @@ class AddFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a feed, ensure that it is unique, check the source, and delete the feed.
|
||||
* Creates and ensures that a feed is unique, checks source, and deletes feed.
|
||||
*/
|
||||
function testAddFeed() {
|
||||
$feed = $this->createFeed();
|
||||
@ -381,6 +405,9 @@ class AddFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the categorize feed functionality in the Aggregator module.
|
||||
*/
|
||||
class CategorizeFeedTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -391,7 +418,7 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a feed and make sure you can add more than one category to it.
|
||||
* Creates a feed and makes sure you can add more than one category to it.
|
||||
*/
|
||||
function testCategorizeFeed() {
|
||||
|
||||
@ -424,6 +451,9 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests functionality of updating the feed in the Aggregator module.
|
||||
*/
|
||||
class UpdateFeedTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -434,7 +464,7 @@ class UpdateFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a feed and attempt to update it.
|
||||
* Creates a feed and attempts to update it.
|
||||
*/
|
||||
function testUpdateFeed() {
|
||||
$remamining_fields = array('title', 'url', '');
|
||||
@ -466,6 +496,9 @@ class UpdateFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests functionality for removing feeds in the Aggregator module.
|
||||
*/
|
||||
class RemoveFeedTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -476,7 +509,7 @@ class RemoveFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a feed and ensure that all it services are removed.
|
||||
* Removes a feed and ensures that all of its services are removed.
|
||||
*/
|
||||
function testRemoveFeed() {
|
||||
$feed = $this->createFeed();
|
||||
@ -494,6 +527,9 @@ class RemoveFeedTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests functionality of updating a feed item in the Aggregator module.
|
||||
*/
|
||||
class UpdateFeedItemTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -504,7 +540,7 @@ class UpdateFeedItemTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test running "update items" from the 'admin/config/services/aggregator' page.
|
||||
* Tests running "update items" from 'admin/config/services/aggregator' page.
|
||||
*/
|
||||
function testUpdateFeedItem() {
|
||||
$this->createSampleNodes();
|
||||
@ -564,7 +600,7 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test running "remove items" from the 'admin/config/services/aggregator' page.
|
||||
* Tests running "remove items" from 'admin/config/services/aggregator' page.
|
||||
*/
|
||||
function testRemoveFeedItem() {
|
||||
// Create a bunch of test feeds.
|
||||
@ -592,6 +628,9 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests categorization functionality in the Aggregator module.
|
||||
*/
|
||||
class CategorizeFeedItemTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -602,6 +641,8 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that children of a feed inherit a defined category.
|
||||
*
|
||||
* If a feed has a category, make sure that the children inherit that
|
||||
* categorization.
|
||||
*/
|
||||
@ -649,6 +690,9 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests importing feeds from OPML functionality for the Aggregator module.
|
||||
*/
|
||||
class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -659,7 +703,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open OPML import form.
|
||||
* Opens OPML import form.
|
||||
*/
|
||||
function openImportForm() {
|
||||
db_delete('aggregator_category')->execute();
|
||||
@ -681,7 +725,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit form filled with invalid fields.
|
||||
* Submits form filled with invalid fields.
|
||||
*/
|
||||
function validateImportFormFields() {
|
||||
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
|
||||
@ -707,7 +751,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit form with invalid, empty and valid OPML files.
|
||||
* Submits form with invalid, empty, and valid OPML files.
|
||||
*/
|
||||
function submitImportForm() {
|
||||
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
|
||||
@ -766,6 +810,9 @@ class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
$this->assertTrue($category, 'Categories are correct.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the import of an OPML file.
|
||||
*/
|
||||
function testOPMLImport() {
|
||||
$this->openImportForm();
|
||||
$this->validateImportFormFields();
|
||||
@ -773,6 +820,9 @@ class ImportOPMLTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests functionality of the cron process in the Aggregator module.
|
||||
*/
|
||||
class AggregatorCronTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -783,7 +833,7 @@ class AggregatorCronTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add feeds update them on cron.
|
||||
* Adds feeds and updates them via cron process.
|
||||
*/
|
||||
public function testCron() {
|
||||
// Create feed and test basic updating on cron.
|
||||
@ -819,6 +869,9 @@ class AggregatorCronTestCase extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering functionality in the Aggregator module.
|
||||
*/
|
||||
class AggregatorRenderingTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
@ -829,9 +882,9 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a feed block to the page and checks its links.
|
||||
* Adds a feed block to the page and checks its links.
|
||||
*
|
||||
* TODO: Test the category block as well.
|
||||
* @todo Test the category block as well.
|
||||
*/
|
||||
public function testBlockLinks() {
|
||||
// Create feed.
|
||||
@ -882,7 +935,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
|
||||
// up.
|
||||
$feed->block = 0;
|
||||
aggregator_save_feed((array) $feed);
|
||||
// It is nescessary to flush the cache after saving the number of items.
|
||||
// It is necessary to flush the cache after saving the number of items.
|
||||
drupal_flush_all_caches();
|
||||
// Check that the block is no longer displayed.
|
||||
$this->drupalGet('node');
|
||||
@ -890,7 +943,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a feed and check that feed's page.
|
||||
* Creates a feed and checks that feed's page.
|
||||
*/
|
||||
public function testFeedPage() {
|
||||
// Increase the number of items published in the rss.xml feed so we have
|
||||
@ -913,7 +966,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for feed parsing.
|
||||
* Tests feed parsing in the Aggregator module.
|
||||
*/
|
||||
class FeedParserTestCase extends AggregatorTestCase {
|
||||
public static function getInfo() {
|
||||
@ -933,7 +986,7 @@ class FeedParserTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a feed that uses the RSS 0.91 format.
|
||||
* Tests a feed that uses the RSS 0.91 format.
|
||||
*/
|
||||
function testRSS091Sample() {
|
||||
$feed = $this->createFeed($this->getRSS091Sample());
|
||||
@ -955,7 +1008,7 @@ class FeedParserTestCase extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a feed that uses the Atom format.
|
||||
* Tests a feed that uses the Atom format.
|
||||
*/
|
||||
function testAtomSample() {
|
||||
$feed = $this->createFeed($this->getAtomSample());
|
||||
@ -967,4 +1020,15 @@ class FeedParserTestCase extends AggregatorTestCase {
|
||||
$this->assertText('Some text.');
|
||||
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(':link' => 'http://example.org/2003/12/13/atom03'))->fetchField(), 'Atom entry id element is parsed correctly.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a feed that uses HTML entities in item titles.
|
||||
*/
|
||||
function testHtmlEntitiesSample() {
|
||||
$feed = $this->createFeed($this->getHtmlEntitiesSample());
|
||||
aggregator_refresh($feed);
|
||||
$this->drupalGet('aggregator/sources/' . $feed->fid);
|
||||
$this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
|
||||
$this->assertRaw("Quote" Amp&");
|
||||
}
|
||||
}
|
||||
|
@ -4,3 +4,9 @@ package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -32,7 +32,7 @@ function aggregator_test_feed($use_last_modified = FALSE, $use_etag = FALSE) {
|
||||
// Send appropriate response. We respond with a 304 not modified on either
|
||||
// etag or on last modified.
|
||||
if ($use_last_modified) {
|
||||
drupal_add_http_header('Last-Modified', gmdate(DATE_RFC1123, $last_modified));
|
||||
drupal_add_http_header('Last-Modified', gmdate(DATE_RFC7231, $last_modified));
|
||||
}
|
||||
if ($use_etag) {
|
||||
drupal_add_http_header('ETag', $etag);
|
||||
|
14
modules/aggregator/tests/aggregator_test_title_entities.xml
Normal file
14
modules/aggregator/tests/aggregator_test_title_entities.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="0.91">
|
||||
<channel>
|
||||
<title>Example with Entities</title>
|
||||
<link>http://example.com</link>
|
||||
<description>Example RSS Feed With HTML Entities in Title</description>
|
||||
<language>en-us</language>
|
||||
<item>
|
||||
<title>Quote" Amp&</title>
|
||||
<link>http://example.com/example-turns-one</link>
|
||||
<description>Some text.</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
@ -272,7 +272,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
|
||||
$form['settings']['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Block title'),
|
||||
'#maxlength' => 64,
|
||||
'#maxlength' => 255,
|
||||
'#description' => $block->module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <em>!placeholder</em> to display no title, or leave blank to use the default block title.', array('!placeholder' => '<none>')),
|
||||
'#default_value' => isset($block->title) ? $block->title : '',
|
||||
'#weight' => -19,
|
||||
|
@ -87,13 +87,13 @@
|
||||
* and any value provided can be modified by a user on the block
|
||||
* configuration screen.
|
||||
* - pages: (optional) See 'visibility' above. A string that contains one or
|
||||
* more page paths separated by '\n', '\r', or '\r\n' when 'visibility' is
|
||||
* set to BLOCK_VISIBILITY_NOTLISTED or BLOCK_VISIBILITY_LISTED, or custom
|
||||
* PHP code when 'visibility' is set to BLOCK_VISIBILITY_PHP. Paths may use
|
||||
* '*' as a wildcard (matching any number of characters); '<front>'
|
||||
* designates the site's front page. For BLOCK_VISIBILITY_PHP, the PHP
|
||||
* code's return value should be TRUE if the block is to be made visible or
|
||||
* FALSE if the block should not be visible.
|
||||
* more page paths separated by "\n", "\r", or "\r\n" when 'visibility' is
|
||||
* set to BLOCK_VISIBILITY_NOTLISTED or BLOCK_VISIBILITY_LISTED (example:
|
||||
* "<front>\nnode/1"), or custom PHP code when 'visibility' is set to
|
||||
* BLOCK_VISIBILITY_PHP. Paths may use '*' as a wildcard (matching any
|
||||
* number of characters); '<front>' designates the site's front page. For
|
||||
* BLOCK_VISIBILITY_PHP, the PHP code's return value should be TRUE if the
|
||||
* block is to be made visible or FALSE if the block should not be visible.
|
||||
*
|
||||
* For a detailed usage example, see block_example.module.
|
||||
*
|
||||
@ -200,11 +200,13 @@ function hook_block_save($delta = '', $edit = array()) {
|
||||
* within the module, defined in hook_block_info().
|
||||
*
|
||||
* @return
|
||||
* An array containing the following elements:
|
||||
* Either an empty array so the block will not be shown or an array containing
|
||||
* the following elements:
|
||||
* - subject: The default localized title of the block. If the block does not
|
||||
* have a default title, this should be set to NULL.
|
||||
* - content: The content of the block's body. This may be a renderable array
|
||||
* (preferable) or a string containing rendered HTML content.
|
||||
* (preferable) or a string containing rendered HTML content. If the content
|
||||
* is empty the block will not be shown.
|
||||
*
|
||||
* For a detailed usage example, see block_example.module.
|
||||
*
|
||||
@ -253,8 +255,9 @@ function hook_block_view($delta = '') {
|
||||
* specific block.
|
||||
*
|
||||
* @param $data
|
||||
* An array of data, as returned from the hook_block_view() implementation of
|
||||
* the module that defined the block:
|
||||
* The data as returned from the hook_block_view() implementation of the
|
||||
* module that defined the block. This could be an empty array or NULL value
|
||||
* (if the block is empty) or an array containing:
|
||||
* - subject: The default localized title of the block.
|
||||
* - content: Either a string or a renderable array representing the content
|
||||
* of the block. You should check that the content is an array before trying
|
||||
@ -287,8 +290,9 @@ function hook_block_view_alter(&$data, $block) {
|
||||
* specific block, rather than implementing hook_block_view_alter().
|
||||
*
|
||||
* @param $data
|
||||
* An array of data, as returned from the hook_block_view() implementation of
|
||||
* the module that defined the block:
|
||||
* The data as returned from the hook_block_view() implementation of the
|
||||
* module that defined the block. This could be an empty array or NULL value
|
||||
* (if the block is empty) or an array containing:
|
||||
* - subject: The localized title of the block.
|
||||
* - content: Either a string or a renderable array representing the content
|
||||
* of the block. You should check that the content is an array before trying
|
||||
|
@ -5,3 +5,9 @@ version = VERSION
|
||||
core = 7.x
|
||||
files[] = block.test
|
||||
configure = admin/structure/block
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -79,7 +79,7 @@ function block_schema() {
|
||||
),
|
||||
'title' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Custom title for the block. (Empty string will use block default title, <none> will remove the title, text will cause block to use specified title.)',
|
||||
@ -472,6 +472,22 @@ function block_update_7008() {
|
||||
db_drop_field('block', 'throttle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase {block}.title length to 255 characters.
|
||||
*/
|
||||
function block_update_7009() {
|
||||
db_change_field('block', 'title', 'title',
|
||||
array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Custom title for the block. (Empty string will use block default title, <none> will remove the title, text will cause block to use specified title.)',
|
||||
'translatable' => TRUE,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-7.x-extra".
|
||||
*/
|
||||
|
@ -66,7 +66,7 @@ function block_help($path, $arg) {
|
||||
$demo_theme = !empty($arg[4]) ? $arg[4] : variable_get('theme_default', 'bartik');
|
||||
$themes = list_themes();
|
||||
$output = '<p>' . t('This page provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions. Since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis. Remember that your changes will not be saved until you click the <em>Save blocks</em> button at the bottom of the page. Click the <em>configure</em> link next to each block to configure its specific title and visibility settings.') . '</p>';
|
||||
$output .= '<p>' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '</p>';
|
||||
$output .= '<p>' . l(t('Demonstrate block regions (!theme)', array('!theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@ -143,7 +143,7 @@ function block_menu() {
|
||||
);
|
||||
foreach (list_themes() as $key => $theme) {
|
||||
$items['admin/structure/block/list/' . $key] = array(
|
||||
'title' => check_plain($theme->info['name']),
|
||||
'title' => $theme->info['name'],
|
||||
'page arguments' => array($key),
|
||||
'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
|
||||
'weight' => $key == $default_theme ? -10 : 0,
|
||||
@ -162,7 +162,7 @@ function block_menu() {
|
||||
);
|
||||
}
|
||||
$items['admin/structure/block/demo/' . $key] = array(
|
||||
'title' => check_plain($theme->info['name']),
|
||||
'title' => $theme->info['name'],
|
||||
'page callback' => 'block_admin_demo',
|
||||
'page arguments' => array($key),
|
||||
'type' => MENU_CALLBACK,
|
||||
@ -401,23 +401,27 @@ function _block_rehash($theme = NULL) {
|
||||
}
|
||||
// Save the blocks defined in code for alter context.
|
||||
$code_blocks = $current_blocks;
|
||||
$database_blocks = db_select('block', 'b')
|
||||
$database_blocks = db_select('block', 'b', array('fetch' => PDO::FETCH_ASSOC))
|
||||
->fields('b')
|
||||
->condition($or)
|
||||
->condition('theme', $theme)
|
||||
->execute();
|
||||
$original_database_blocks = array();
|
||||
foreach ($database_blocks as $block) {
|
||||
// Preserve info which is not in the database.
|
||||
$block->info = $current_blocks[$block->module][$block->delta]['info'];
|
||||
$module = $block['module'];
|
||||
$delta = $block['delta'];
|
||||
$original_database_blocks[$module][$delta] = $block;
|
||||
// The cache mode can only by set from hook_block_info(), so that has
|
||||
// precedence over the database's value.
|
||||
if (isset($current_blocks[$block->module][$block->delta]['cache'])) {
|
||||
$block->cache = $current_blocks[$block->module][$block->delta]['cache'];
|
||||
if (isset($current_blocks[$module][$delta]['cache'])) {
|
||||
$block['cache'] = $current_blocks[$module][$delta]['cache'];
|
||||
}
|
||||
// Preserve info which is not in the database.
|
||||
$block['info'] = $current_blocks[$module][$delta]['info'];
|
||||
// Blocks stored in the database override the blocks defined in code.
|
||||
$current_blocks[$block->module][$block->delta] = get_object_vars($block);
|
||||
$current_blocks[$module][$delta] = $block;
|
||||
// Preserve this block.
|
||||
$bids[$block->bid] = $block->bid;
|
||||
$bids[$block['bid']] = $block['bid'];
|
||||
}
|
||||
drupal_alter('block_info', $current_blocks, $theme, $code_blocks);
|
||||
foreach ($current_blocks as $module => $module_blocks) {
|
||||
@ -456,7 +460,15 @@ function _block_rehash($theme = NULL) {
|
||||
else {
|
||||
$primary_keys = array();
|
||||
}
|
||||
drupal_write_record('block', $block, $primary_keys);
|
||||
// If the block is new or differs from the original database block, save
|
||||
// it. To determine whether there was a change it is enough to examine
|
||||
// the values for the keys in the original database record as that
|
||||
// contained every database field.
|
||||
if (!$primary_keys || array_diff_assoc($original_database_blocks[$module][$delta], $block)) {
|
||||
drupal_write_record('block', $block, $primary_keys);
|
||||
// Make it possible to test this.
|
||||
$block['saved'] = TRUE;
|
||||
}
|
||||
// Add to the list of blocks we return.
|
||||
$blocks[] = $block;
|
||||
}
|
||||
@ -680,6 +692,9 @@ function block_list($region) {
|
||||
/**
|
||||
* Loads a block object from the database.
|
||||
*
|
||||
* This function returns the first block matching the module and delta
|
||||
* parameters, so it should not be used for theme-specific functionality.
|
||||
*
|
||||
* @param $module
|
||||
* Name of the module that implements the block to load.
|
||||
* @param $delta
|
||||
@ -740,7 +755,7 @@ function _block_load_blocks() {
|
||||
/**
|
||||
* Implements hook_block_list_alter().
|
||||
*
|
||||
* Checks the page, user role, and user-specific visibilty settings.
|
||||
* Checks the page, user role, and user-specific visibility settings.
|
||||
* Removes the block if the visibility conditions are not met.
|
||||
*/
|
||||
function block_block_list_alter(&$blocks) {
|
||||
@ -836,26 +851,64 @@ function block_block_list_alter(&$blocks) {
|
||||
* An array of visible blocks as expected by drupal_render().
|
||||
*/
|
||||
function _block_render_blocks($region_blocks) {
|
||||
// Block caching is not compatible with node access modules. We also
|
||||
// preserve the submission of forms in blocks, by fetching from cache only
|
||||
$cacheable = TRUE;
|
||||
|
||||
// We preserve the submission of forms in blocks, by fetching from cache only
|
||||
// if the request method is 'GET' (or 'HEAD').
|
||||
$cacheable = !count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') {
|
||||
$cacheable = FALSE;
|
||||
}
|
||||
// Block caching is not usually compatible with node access modules, so by
|
||||
// default it is disabled when node access modules exist. However, it can be
|
||||
// allowed by using the variable 'block_cache_bypass_node_grants'.
|
||||
elseif (!variable_get('block_cache_bypass_node_grants', FALSE) && count(module_implements('node_grants'))) {
|
||||
$cacheable = FALSE;
|
||||
}
|
||||
|
||||
// Proceed to loop over all blocks in order to compute their respective cache
|
||||
// identifiers; this allows us to do one single cache_get_multiple() call
|
||||
// instead of doing one cache_get() call per block.
|
||||
$cached_blocks = array();
|
||||
$cids = array();
|
||||
|
||||
if ($cacheable) {
|
||||
foreach ($region_blocks as $key => $block) {
|
||||
if (!isset($block->content)) {
|
||||
if (($cid = _block_get_cache_id($block))) {
|
||||
$cids[$key] = $cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($cids) {
|
||||
// We cannot pass $cids in directly because cache_get_multiple() will
|
||||
// modify it, and we need to use it later on in this function.
|
||||
$cid_values = array_values($cids);
|
||||
$cached_blocks = cache_get_multiple($cid_values, 'cache_block');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($region_blocks as $key => $block) {
|
||||
// Render the block content if it has not been created already.
|
||||
if (!isset($block->content)) {
|
||||
// Erase the block from the static array - we'll put it back if it has
|
||||
// content.
|
||||
unset($region_blocks[$key]);
|
||||
// Try fetching the block from cache.
|
||||
if ($cacheable && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
|
||||
$array = $cache->data;
|
||||
|
||||
$cid = empty($cids[$key]) ? NULL : $cids[$key];
|
||||
|
||||
// Try fetching the block from the previously loaded cache entries.
|
||||
if (isset($cached_blocks[$cid])) {
|
||||
$array = $cached_blocks[$cid]->data;
|
||||
}
|
||||
else {
|
||||
$array = module_invoke($block->module, 'block_view', $block->delta);
|
||||
|
||||
// Valid PHP function names cannot contain hyphens.
|
||||
$delta = str_replace('-', '_', $block->delta);
|
||||
// Allow modules to modify the block before it is viewed, via either
|
||||
// hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
|
||||
drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
|
||||
drupal_alter(array('block_view', "block_view_{$block->module}_{$delta}"), $array, $block);
|
||||
|
||||
if (isset($cid)) {
|
||||
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
|
||||
@ -1013,7 +1066,7 @@ function block_menu_delete($menu) {
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function block_form_system_performance_settings_alter(&$form, &$form_state) {
|
||||
$disabled = count(module_implements('node_grants'));
|
||||
$disabled = (!variable_get('block_cache_bypass_node_grants', FALSE) && count(module_implements('node_grants')));
|
||||
$form['caching']['block_cache'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Cache blocks'),
|
||||
|
@ -75,7 +75,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
||||
$bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
|
||||
|
||||
// Check to see if the custom block was created by checking that it's in the database.
|
||||
$this->assertNotNull($bid, 'Custom block found in database');
|
||||
$this->assertTrue($bid, 'Custom block found in database');
|
||||
|
||||
// Check that block_block_view() returns the correct title and content.
|
||||
$data = block_block_view($bid);
|
||||
@ -193,7 +193,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test block visibility when using "pages" restriction but leaving
|
||||
* Test block visibility when using "pages" restriction but leaving
|
||||
* "pages" textarea empty
|
||||
*/
|
||||
function testBlockVisibilityListedEmpty() {
|
||||
@ -305,7 +305,7 @@ class BlockTestCase extends DrupalWebTestCase {
|
||||
))->fetchField();
|
||||
|
||||
// Check to see if the block was created by checking that it's in the database.
|
||||
$this->assertNotNull($bid, 'Block found in database');
|
||||
$this->assertTrue($bid, 'Block found in database');
|
||||
|
||||
// Check whether the block can be moved to all available regions.
|
||||
foreach ($this->regions as $region) {
|
||||
@ -752,6 +752,48 @@ class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for hook_block_view_MODULE_DELTA_alter().
|
||||
*/
|
||||
class BlockViewModuleDeltaAlterWebTest extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Block view module delta alter',
|
||||
'description' => 'Test the hook_block_view_MODULE_DELTA_alter() hook.',
|
||||
'group' => 'Block',
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp(array('block_test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the alter hook is called, even if the delta contains a hyphen.
|
||||
*/
|
||||
public function testBlockViewModuleDeltaAlter() {
|
||||
$block = new stdClass;
|
||||
$block->module = 'block_test';
|
||||
$block->delta = 'test_underscore';
|
||||
$block->title = '';
|
||||
$render_array = _block_render_blocks(array('region' => $block));
|
||||
$render = array_pop($render_array);
|
||||
$test_underscore = $render->content['#markup'];
|
||||
$this->assertEqual($test_underscore, 'hook_block_view_MODULE_DELTA_alter', 'Found expected altered block content for delta with underscore');
|
||||
|
||||
$block = new stdClass;
|
||||
$block->module = 'block_test';
|
||||
$block->delta = 'test-hyphen';
|
||||
$block->title = '';
|
||||
$render_array = _block_render_blocks(array('region' => $block));
|
||||
$render = array_pop($render_array);
|
||||
$test_hyphen = $render->content['#markup'];
|
||||
$this->assertEqual($test_hyphen, 'hook_block_view_MODULE_DELTA_alter', 'Hyphens (-) in block delta were replaced by underscore (_)');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that hidden regions do not inherit blocks when a theme is enabled.
|
||||
*/
|
||||
@ -857,3 +899,81 @@ class BlockInvalidRegionTestCase extends DrupalWebTestCase {
|
||||
$this->assertNoRaw($warning_message, 'Disabled block in the invalid region will not trigger the warning.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that block rehashing works correctly.
|
||||
*/
|
||||
class BlockHashTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Block rehash',
|
||||
'description' => 'Checks _block_rehash() functionality.',
|
||||
'group' => 'Block',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('block'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that block rehashing does not write to the database too often.
|
||||
*/
|
||||
function testBlockRehash() {
|
||||
// No hook_block_info_alter(), no save.
|
||||
$this->doRehash();
|
||||
module_enable(array('block_test'), FALSE);
|
||||
// Save the new blocks, check that the new blocks exist by checking weight.
|
||||
_block_rehash();
|
||||
$this->assertWeight(0);
|
||||
// Now hook_block_info_alter() exists but no blocks are saved on a second
|
||||
// rehash.
|
||||
$this->doRehash();
|
||||
$this->assertWeight(0);
|
||||
// Now hook_block_info_alter() exists and is changing one block which
|
||||
// should be saved.
|
||||
$GLOBALS['conf']['block_test_info_alter'] = 1;
|
||||
$this->doRehash(TRUE);
|
||||
$this->assertWeight(10000);
|
||||
// Now hook_block_info_alter() exists but already changed the block's
|
||||
// weight before, so it should not be saved again.
|
||||
$this->doRehash();
|
||||
$this->assertWeight(10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a block rehash and checks several related assertions.
|
||||
*
|
||||
* @param $alter_active
|
||||
* Set to TRUE if the block_test module's hook_block_info_alter()
|
||||
* implementation is expected to make a change that results in an existing
|
||||
* block needing to be resaved to the database. Defaults to FALSE.
|
||||
*/
|
||||
function doRehash($alter_active = FALSE) {
|
||||
$saves = 0;
|
||||
foreach (_block_rehash() as $block) {
|
||||
$module = $block['module'];
|
||||
$delta = $block['delta'];
|
||||
if ($alter_active && $module == 'block_test' && $delta == 'test_html_id') {
|
||||
$this->assertFalse(empty($block['saved']), "$module $delta saved");
|
||||
$saves++;
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(empty($block['saved']), "$module $delta not saved");
|
||||
}
|
||||
}
|
||||
$this->assertEqual($alter_active, $saves);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the block_test module's block has a given weight.
|
||||
*
|
||||
* @param $weight
|
||||
* The expected weight.
|
||||
*/
|
||||
function assertWeight($weight) {
|
||||
$db_weight = db_query('SELECT weight FROM {block} WHERE module = :module AND delta = :delta', array(':module' => 'block_test', ':delta' => 'test_html_id'))->fetchField();
|
||||
// By casting to string the assert fails on FALSE.
|
||||
$this->assertIdentical((string) $db_weight, (string) $weight);
|
||||
}
|
||||
}
|
||||
|
@ -4,3 +4,9 @@ package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -22,6 +22,14 @@ function block_test_block_info() {
|
||||
'cache' => variable_get('block_test_caching', DRUPAL_CACHE_PER_ROLE),
|
||||
);
|
||||
|
||||
$blocks['test_underscore'] = array(
|
||||
'info' => t('Test underscore'),
|
||||
);
|
||||
|
||||
$blocks['test-hyphen'] = array(
|
||||
'info' => t('Test hyphen'),
|
||||
);
|
||||
|
||||
$blocks['test_html_id'] = array(
|
||||
'info' => t('Test block html id'),
|
||||
);
|
||||
@ -34,3 +42,26 @@ function block_test_block_info() {
|
||||
function block_test_block_view($delta = 0) {
|
||||
return array('content' => variable_get('block_test_content', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view_MODULE_DELTA_alter().
|
||||
*/
|
||||
function block_test_block_view_block_test_test_underscore_alter(&$data, $block) {
|
||||
$data['content'] = 'hook_block_view_MODULE_DELTA_alter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_view_MODULE_DELTA_alter().
|
||||
*/
|
||||
function block_test_block_view_block_test_test_hyphen_alter(&$data, $block) {
|
||||
$data['content'] = 'hook_block_view_MODULE_DELTA_alter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_block_info_alter().
|
||||
*/
|
||||
function block_test_block_info_alter(&$blocks) {
|
||||
if (variable_get('block_test_info_alter')) {
|
||||
$blocks['block_test']['test_html_id']['weight'] = 10000;
|
||||
}
|
||||
}
|
||||
|
@ -12,3 +12,9 @@ regions[header] = Header
|
||||
regions[footer] = Footer
|
||||
regions[highlighted] = Highlighted
|
||||
regions[help] = Help
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -4,3 +4,9 @@ package = Core
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
files[] = blog.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -42,8 +42,8 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
|
||||
$this->drupalGet('blog/' . $this->big_user->uid);
|
||||
$this->assertResponse(200);
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($this->big_user))) . ' | Drupal', t('Blog title was displayed'));
|
||||
$this->assertText(t('You are not allowed to post a new blog entry.'), t('No new entries can be posted without the right permission'));
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($this->big_user))) . ' | Drupal', 'Blog title was displayed');
|
||||
$this->assertText(t('You are not allowed to post a new blog entry.'), 'No new entries can be posted without the right permission');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,8 +54,8 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
|
||||
$this->drupalGet('blog/' . $this->own_user->uid);
|
||||
$this->assertResponse(200);
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($this->own_user))) . ' | Drupal', t('Blog title was displayed'));
|
||||
$this->assertText(t('@author has not created any blog entries.', array('@author' => format_username($this->own_user))), t('Users blog displayed with no entries'));
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($this->own_user))) . ' | Drupal', 'Blog title was displayed');
|
||||
$this->assertText(t('@author has not created any blog entries.', array('@author' => format_username($this->own_user))), 'Users blog displayed with no entries');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +73,7 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
$edit = array();
|
||||
$edit['blog_block_count'] = 5;
|
||||
$this->drupalPost('admin/structure/block/manage/blog/recent/configure', $edit, t('Save block'));
|
||||
$this->assertEqual(variable_get('blog_block_count', 10), 5, t('Number of recent blog posts changed.'));
|
||||
$this->assertEqual(variable_get('blog_block_count', 10), 5, 'Number of recent blog posts changed.');
|
||||
|
||||
// Do basic tests for each user.
|
||||
$this->doBasicTests($this->any_user, TRUE);
|
||||
@ -132,31 +132,31 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
$this->drupalGet('admin/help/blog');
|
||||
$this->assertResponse($response2);
|
||||
if ($response2 == 200) {
|
||||
$this->assertTitle(t('Blog | Drupal'), t('Blog help node was displayed'));
|
||||
$this->assertText(t('Blog'), t('Blog help node was displayed'));
|
||||
$this->assertTitle(t('Blog | Drupal'), 'Blog help node was displayed');
|
||||
$this->assertText(t('Blog'), 'Blog help node was displayed');
|
||||
}
|
||||
|
||||
// Verify the blog block was displayed.
|
||||
$this->drupalGet('');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('Recent blog posts'), t('Blog block was displayed'));
|
||||
$this->assertText(t('Recent blog posts'), 'Blog block was displayed');
|
||||
|
||||
// View blog node.
|
||||
$this->drupalGet('node/' . $node->nid);
|
||||
$this->assertResponse(200);
|
||||
$this->assertTitle($node->title . ' | Drupal', t('Blog node was displayed'));
|
||||
$this->assertTitle($node->title . ' | Drupal', 'Blog node was displayed');
|
||||
$breadcrumb = array(
|
||||
l(t('Home'), NULL),
|
||||
l(t('Blogs'), 'blog'),
|
||||
l(t("!name's blog", array('!name' => format_username($node_user))), 'blog/' . $node_user->uid),
|
||||
);
|
||||
$this->assertRaw(theme('breadcrumb', array('breadcrumb' => $breadcrumb)), t('Breadcrumbs were displayed'));
|
||||
$this->assertRaw(theme('breadcrumb', array('breadcrumb' => $breadcrumb)), 'Breadcrumbs were displayed');
|
||||
|
||||
// View blog edit node.
|
||||
$this->drupalGet('node/' . $node->nid . '/edit');
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertTitle('Edit Blog entry ' . $node->title . ' | Drupal', t('Blog edit node was displayed'));
|
||||
$this->assertTitle('Edit Blog entry ' . $node->title . ' | Drupal', 'Blog edit node was displayed');
|
||||
}
|
||||
|
||||
if ($response == 200) {
|
||||
@ -166,12 +166,12 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
$edit["title"] = 'node/' . $node->nid;
|
||||
$edit["body[$langcode][0][value]"] = $this->randomName(256);
|
||||
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||
$this->assertRaw(t('Blog entry %title has been updated.', array('%title' => $edit["title"])), t('Blog node was edited'));
|
||||
$this->assertRaw(t('Blog entry %title has been updated.', array('%title' => $edit["title"])), 'Blog node was edited');
|
||||
|
||||
// Delete blog node.
|
||||
$this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
|
||||
$this->assertResponse($response);
|
||||
$this->assertRaw(t('Blog entry %title has been deleted.', array('%title' => $edit["title"])), t('Blog node was deleted'));
|
||||
$this->assertRaw(t('Blog entry %title has been deleted.', array('%title' => $edit["title"])), 'Blog node was deleted');
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,29 +185,29 @@ class BlogTestCase extends DrupalWebTestCase {
|
||||
// Confirm blog entries link exists on the user page.
|
||||
$this->drupalGet('user/' . $user->uid);
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('View recent blog entries'), t('View recent blog entries link was displayed'));
|
||||
$this->assertText(t('View recent blog entries'), 'View recent blog entries link was displayed');
|
||||
|
||||
// Confirm the recent blog entries link goes to the user's blog page.
|
||||
$this->clickLink('View recent blog entries');
|
||||
$this->assertTitle(t("@name's blog | Drupal", array('@name' => format_username($user))), t('View recent blog entries link target was correct'));
|
||||
$this->assertTitle(t("@name's blog | Drupal", array('@name' => format_username($user))), 'View recent blog entries link target was correct');
|
||||
|
||||
// Confirm a blog page was displayed.
|
||||
$this->drupalGet('blog');
|
||||
$this->assertResponse(200);
|
||||
$this->assertTitle('Blogs | Drupal', t('Blog page was displayed'));
|
||||
$this->assertText(t('Home'), t('Breadcrumbs were displayed'));
|
||||
$this->assertTitle('Blogs | Drupal', 'Blog page was displayed');
|
||||
$this->assertText(t('Home'), 'Breadcrumbs were displayed');
|
||||
$this->assertLink(t('Create new blog entry'));
|
||||
|
||||
// Confirm a blog page was displayed per user.
|
||||
$this->drupalGet('blog/' . $user->uid);
|
||||
$this->assertTitle(t("@name's blog | Drupal", array('@name' => format_username($user))), t('User blog node was displayed'));
|
||||
$this->assertTitle(t("@name's blog | Drupal", array('@name' => format_username($user))), 'User blog node was displayed');
|
||||
|
||||
// Confirm a blog feed was displayed.
|
||||
$this->drupalGet('blog/feed');
|
||||
$this->assertTitle(t('Drupal blogs'), t('Blog feed was displayed'));
|
||||
$this->assertTitle(t('Drupal blogs'), 'Blog feed was displayed');
|
||||
|
||||
// Confirm a blog feed was displayed per user.
|
||||
$this->drupalGet('blog/' . $user->uid . '/feed');
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($user))), t('User blog feed was displayed'));
|
||||
$this->assertTitle(t("@name's blog", array('@name' => format_username($user))), 'User blog feed was displayed');
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @file
|
||||
* Right-to-Left styling for the Book module.
|
||||
*/
|
||||
|
||||
.book-navigation .menu {
|
||||
padding: 1em 3em 0 0;
|
||||
|
@ -2,11 +2,16 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Admin page callbacks for the book module.
|
||||
* Administration page callbacks for the Book module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an administrative overview of all books.
|
||||
*
|
||||
* @return string
|
||||
* A HTML-formatted string with the administrative page content.
|
||||
*
|
||||
* @see book_menu()
|
||||
*/
|
||||
function book_admin_overview() {
|
||||
$rows = array();
|
||||
@ -53,6 +58,8 @@ function book_admin_settings() {
|
||||
|
||||
/**
|
||||
* Form validation handler for book_admin_settings().
|
||||
*
|
||||
* @see book_admin_settings_submit()
|
||||
*/
|
||||
function book_admin_settings_validate($form, &$form_state) {
|
||||
$child_type = $form_state['values']['book_child_type'];
|
||||
@ -149,7 +156,7 @@ function book_admin_edit_submit($form, &$form_state) {
|
||||
* @param $node
|
||||
* The node of the top-level page in the book.
|
||||
* @param $form
|
||||
* The form that is being modified.
|
||||
* The form that is being modified, passed by reference.
|
||||
*
|
||||
* @see book_admin_edit()
|
||||
*/
|
||||
@ -184,10 +191,10 @@ function _book_admin_table($node, &$form) {
|
||||
* @param $tree
|
||||
* A subtree of the book menu hierarchy.
|
||||
* @param $form
|
||||
* The form that is being modified.
|
||||
* The form that is being modified, passed by reference.
|
||||
*
|
||||
* @return
|
||||
* The form that is being modified.
|
||||
* The modified form array.
|
||||
*
|
||||
* @see book_admin_edit()
|
||||
*/
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @file
|
||||
* Styling for the Book module.
|
||||
*/
|
||||
|
||||
.book-navigation .menu {
|
||||
border-top: 1px solid #888;
|
||||
|
@ -6,3 +6,9 @@ core = 7.x
|
||||
files[] = book.test
|
||||
configure = admin/content/book/settings
|
||||
stylesheets[all][] = book.css
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
* Javascript behaviors for the Book module.
|
||||
*/
|
||||
|
||||
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.bookFieldsetSummaries = {
|
||||
|
@ -221,6 +221,9 @@ function _book_outline_remove_access($node) {
|
||||
*
|
||||
* A node can be removed from a book if it is actually in a book and it either
|
||||
* is not a top-level page or is a top-level page with no children.
|
||||
*
|
||||
* @param $node
|
||||
* The node to remove from the outline.
|
||||
*/
|
||||
function _book_node_is_removable($node) {
|
||||
return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children']));
|
||||
@ -734,7 +737,7 @@ function book_get_flat_menu($book_link) {
|
||||
* @param $tree
|
||||
* A tree of menu links in an array.
|
||||
* @param $flat
|
||||
* A flat array of the menu links from $tree.
|
||||
* A flat array of the menu links from $tree, passed by reference.
|
||||
*
|
||||
* @see book_get_flat_menu().
|
||||
*/
|
||||
@ -1062,8 +1065,9 @@ function _book_link_defaults($nid) {
|
||||
* to the structured data but can also simply iterate over all elements and
|
||||
* render them (as in the default template).
|
||||
*
|
||||
* The $variables array contains the following elements:
|
||||
* - book_menus
|
||||
* @param $variables
|
||||
* An associative array containing the following key:
|
||||
* - book_menus
|
||||
*
|
||||
* @see book-all-books-block.tpl.php
|
||||
*/
|
||||
@ -1079,8 +1083,9 @@ function template_preprocess_book_all_books_block(&$variables) {
|
||||
/**
|
||||
* Processes variables for book-navigation.tpl.php.
|
||||
*
|
||||
* The $variables array contains the following elements:
|
||||
* - book_link
|
||||
* @param $variables
|
||||
* An associative array containing the following key:
|
||||
* - book_link
|
||||
*
|
||||
* @see book-navigation.tpl.php
|
||||
*/
|
||||
@ -1151,8 +1156,9 @@ function template_preprocess_book_navigation(&$variables) {
|
||||
* Reference to the table of contents array. This is modified in place, so the
|
||||
* function does not have a return value.
|
||||
* @param $exclude
|
||||
* Optional array of menu link ID values. Any link whose menu link ID is in
|
||||
* this array will be excluded (along with its children).
|
||||
* (optional) An array of menu link ID values. Any link whose menu link ID is
|
||||
* in this array will be excluded (along with its children). Defaults to an
|
||||
* empty array.
|
||||
* @param $depth_limit
|
||||
* Any link deeper than this value will be excluded (along with its children).
|
||||
*/
|
||||
@ -1198,10 +1204,11 @@ function book_toc($bid, $depth_limit, $exclude = array()) {
|
||||
/**
|
||||
* Processes variables for book-export-html.tpl.php.
|
||||
*
|
||||
* The $variables array contains the following elements:
|
||||
* - title
|
||||
* - contents
|
||||
* - depth
|
||||
* @param $variables
|
||||
* An associative array containing the following keys:
|
||||
* - title
|
||||
* - contents
|
||||
* - depth
|
||||
*
|
||||
* @see book-export-html.tpl.php
|
||||
*/
|
||||
@ -1261,7 +1268,8 @@ function book_export_traverse($tree, $visit_func) {
|
||||
* @param $node
|
||||
* The node that will be output.
|
||||
* @param $children
|
||||
* All the rendered child nodes within the current node.
|
||||
* (optional) All the rendered child nodes within the current node. Defaults
|
||||
* to an empty string.
|
||||
*
|
||||
* @return
|
||||
* The HTML generated for the given node.
|
||||
@ -1280,9 +1288,10 @@ function book_node_export($node, $children = '') {
|
||||
/**
|
||||
* Processes variables for book-node-export-html.tpl.php.
|
||||
*
|
||||
* The $variables array contains the following elements:
|
||||
* - node
|
||||
* - children
|
||||
* @param $variables
|
||||
* An associative array containing the following keys:
|
||||
* - node
|
||||
* - children
|
||||
*
|
||||
* @see book-node-export-html.tpl.php
|
||||
*/
|
||||
@ -1294,6 +1303,12 @@ function template_preprocess_book_node_export_html(&$variables) {
|
||||
|
||||
/**
|
||||
* Determine if a given node type is in the list of types allowed for books.
|
||||
*
|
||||
* @param $type
|
||||
* A node type.
|
||||
*
|
||||
* @return
|
||||
* A Boolean TRUE if the node type can be included in books; otherwise, FALSE.
|
||||
*/
|
||||
function book_type_is_allowed($type) {
|
||||
return in_array($type, variable_get('book_allowed_types', array('book')));
|
||||
@ -1336,7 +1351,7 @@ function book_node_type_update($type) {
|
||||
*
|
||||
* @return
|
||||
* A menu link, with the link translated for rendering and data added from the
|
||||
* {book} table.
|
||||
* {book} table. FALSE if there is an error.
|
||||
*/
|
||||
function book_link_load($mlid) {
|
||||
if ($item = db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(
|
||||
@ -1360,7 +1375,7 @@ function book_link_load($mlid) {
|
||||
* A fully loaded menu link.
|
||||
*
|
||||
* @return
|
||||
* An subtree of menu links in an array, in the order they should be rendered.
|
||||
* A subtree of menu links in an array, in the order they should be rendered.
|
||||
*/
|
||||
function book_menu_subtree_data($link) {
|
||||
$tree = &drupal_static(__FUNCTION__, array());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user