diff --git a/www7/includes/bootstrap.inc b/www7/includes/bootstrap.inc
index 6891f1277..8b05bc5c6 100644
--- a/www7/includes/bootstrap.inc
+++ b/www7/includes/bootstrap.inc
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.63');
+define('VERSION', '7.67');
/**
* Core API compatibility.
diff --git a/www7/includes/common.inc b/www7/includes/common.inc
index c5b4ff26e..44ff46078 100644
--- a/www7/includes/common.inc
+++ b/www7/includes/common.inc
@@ -1094,6 +1094,11 @@ function drupal_http_request($url, array $options = array()) {
elseif ($options['max_redirects']) {
// Redirect to the new location.
$options['max_redirects']--;
+
+ // We need to unset the 'Host' header
+ // as we are redirecting to a new location.
+ unset($options['headers']['Host']);
+
$result = drupal_http_request($location, $options);
$result->redirect_code = $code;
}
diff --git a/www7/includes/file.inc b/www7/includes/file.inc
index 50a3b768a..95bb65843 100644
--- a/www7/includes/file.inc
+++ b/www7/includes/file.inc
@@ -993,8 +993,15 @@ function file_build_uri($path) {
* @return
* The destination filepath, or FALSE if the file already exists
* and FILE_EXISTS_ERROR is specified.
+ *
+ * @throws RuntimeException
+ * Thrown if the filename contains invalid UTF-8.
*/
function file_destination($destination, $replace) {
+ $basename = drupal_basename($destination);
+ if (!drupal_validate_utf8($basename)) {
+ throw new RuntimeException(sprintf("Invalid filename '%s'", $basename));
+ }
if (file_exists($destination)) {
switch ($replace) {
case FILE_EXISTS_REPLACE:
@@ -1002,7 +1009,6 @@ function file_destination($destination, $replace) {
break;
case FILE_EXISTS_RENAME:
- $basename = drupal_basename($destination);
$directory = drupal_dirname($destination);
$destination = file_create_filename($basename, $directory);
break;
@@ -1218,11 +1224,20 @@ function file_unmunge_filename($filename) {
* @return
* File path consisting of $directory and a unique filename based off
* of $basename.
+ *
+ * @throws RuntimeException
+ * Thrown if the $basename is not valid UTF-8 or another error occurs
+ * stripping control characters.
*/
function file_create_filename($basename, $directory) {
+ $original = $basename;
// Strip control characters (ASCII value < 32). Though these are allowed in
// some filesystems, not many applications handle them well.
$basename = preg_replace('/[\x00-\x1F]/u', '_', $basename);
+ if (preg_last_error() !== PREG_NO_ERROR) {
+ throw new RuntimeException(sprintf("Invalid filename '%s'", $original));
+ }
+
if (substr(PHP_OS, 0, 3) == 'WIN') {
// These characters are not allowed in Windows filenames
$basename = str_replace(array(':', '*', '?', '"', '<', '>', '|'), '_', $basename);
@@ -1563,7 +1578,13 @@ function file_save_upload($form_field_name, $validators = array(), $destination
if (substr($destination, -1) != '/') {
$destination .= '/';
}
- $file->destination = file_destination($destination . $file->filename, $replace);
+ try {
+ $file->destination = file_destination($destination . $file->filename, $replace);
+ }
+ catch (RuntimeException $e) {
+ drupal_set_message(t('The file %source could not be uploaded because the name is invalid.', array('%source' => $form_field_name)), 'error');
+ return 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) {
@@ -2130,9 +2151,33 @@ function file_download_access($uri) {
* 'filename', and 'name' members corresponding to the matching files.
*/
function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+ // Default nomask option.
+ $nomask = '/(\.\.?|CVS)$/';
+
+ // Overrides the $nomask variable accordingly if $options['nomask'] is set.
+ //
+ // Allow directories specified in settings.php to be ignored. You can use this
+ // to not check for files in common special-purpose directories. For example,
+ // node_modules and bower_components. Ignoring irrelevant directories is a
+ // performance boost.
+ if (!isset($options['nomask'])) {
+ $ignore_directories = variable_get(
+ 'file_scan_ignore_directories',
+ array()
+ );
+
+ foreach ($ignore_directories as $index => $ignore_directory) {
+ $ignore_directories[$index] = preg_quote($ignore_directory, '/');
+ }
+
+ if (!empty($ignore_directories)) {
+ $nomask = '/^(\.\.?)|CVS|' . implode('|', $ignore_directories) . '$/';
+ }
+ }
+
// Merge in defaults.
$options += array(
- 'nomask' => '/(\.\.?|CVS)$/',
+ 'nomask' => $nomask,
'callback' => 0,
'recurse' => TRUE,
'key' => 'uri',
diff --git a/www7/includes/file.phar.inc b/www7/includes/file.phar.inc
index 3d7ba01d4..a0b0e12fa 100644
--- a/www7/includes/file.phar.inc
+++ b/www7/includes/file.phar.inc
@@ -18,7 +18,21 @@ function file_register_phar_wrapper() {
include_once $directory . '/Helper.php';
include_once $directory . '/Manager.php';
include_once $directory . '/PharStreamWrapper.php';
+ include_once $directory . '/Collectable.php';
+ include_once $directory . '/Interceptor/ConjunctionInterceptor.php';
+ include_once $directory . '/Interceptor/PharMetaDataInterceptor.php';
+ include_once $directory . '/Phar/Container.php';
+ include_once $directory . '/Phar/DeserializationException.php';
+ include_once $directory . '/Phar/Manifest.php';
+ include_once $directory . '/Phar/Reader.php';
+ include_once $directory . '/Phar/ReaderException.php';
+ include_once $directory . '/Phar/Stub.php';
+ include_once $directory . '/Resolvable.php';
+ include_once $directory . '/Resolver/PharInvocation.php';
+ include_once $directory . '/Resolver/PharInvocationCollection.php';
+ include_once $directory . '/Resolver/PharInvocationResolver.php';
include_once DRUPAL_ROOT . '/misc/typo3/drupal-security/PharExtensionInterceptor.php';
+ include_once DRUPAL_ROOT . '/misc/brumann/polyfill-unserialize/src/Unserialize.php';
// Set up a stream wrapper to handle insecurities due to PHP's built-in
// phar stream wrapper.
diff --git a/www7/includes/registry.inc b/www7/includes/registry.inc
index 29a1fca8c..ee678e891 100644
--- a/www7/includes/registry.inc
+++ b/www7/includes/registry.inc
@@ -19,7 +19,6 @@
* Does the work for registry_update().
*/
function _registry_update() {
-
// The registry serves as a central autoloader for all classes, including
// the database query builders. However, the registry rebuild process
// requires write ability to the database, which means having access to the
@@ -33,6 +32,11 @@ function _registry_update() {
require_once DRUPAL_ROOT . '/includes/database/select.inc';
require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/query.inc';
+ // During the first registry rebuild in a request, we check all the files.
+ // During subsequent rebuilds, we only add new files. It makes the rebuilding
+ // process faster during installation of modules.
+ static $check_existing_files = TRUE;
+
// Get current list of modules and their files.
$modules = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAll();
// Get the list of files we are going to parse.
@@ -55,6 +59,9 @@ function _registry_update() {
$files["$filename"] = array('module' => '', 'weight' => 0);
}
+ // Initialize an empty array for the unchanged files.
+ $unchanged_files = array();
+
$transaction = db_transaction();
try {
// Allow modules to manually modify the list of files before the registry
@@ -63,10 +70,19 @@ function _registry_update() {
// list can then be added to the list of files that the registry will parse,
// or modify attributes of a file.
drupal_alter('registry_files', $files, $modules);
+
foreach (registry_get_parsed_files() as $filename => $file) {
// Add the hash for those files we have already parsed.
if (isset($files[$filename])) {
- $files[$filename]['hash'] = $file['hash'];
+ if ($check_existing_files === TRUE) {
+ $files[$filename]['hash'] = $file['hash'];
+ }
+ else {
+ // Ignore that file for this request, it has been parsed previously
+ // and it is unlikely it has changed.
+ unset($files[$filename]);
+ $unchanged_files[$filename] = $file;
+ }
}
else {
// Flush the registry of resources in files that are no longer on disc
@@ -79,8 +95,12 @@ function _registry_update() {
->execute();
}
}
+
$parsed_files = _registry_parse_files($files);
+ // Add unchanged files to the files.
+ $files += $unchanged_files;
+
$unchanged_resources = array();
$lookup_cache = array();
if ($cache = cache_get('lookup_cache', 'cache_bootstrap')) {
@@ -89,12 +109,10 @@ function _registry_update() {
foreach ($lookup_cache as $key => $file) {
// If the file for this cached resource is carried over unchanged from
// the last registry build, then we can safely re-cache it.
- if ($file && in_array($file, array_keys($files)) && !in_array($file, $parsed_files)) {
+ if ($file && isset($files[$file]) && !in_array($file, $parsed_files, TRUE)) {
$unchanged_resources[$key] = $file;
}
}
- module_implements('', FALSE, TRUE);
- _registry_check_code(REGISTRY_RESET_LOOKUP_CACHE);
}
catch (Exception $e) {
$transaction->rollback();
@@ -102,6 +120,13 @@ function _registry_update() {
throw $e;
}
+ module_implements('', FALSE, TRUE);
+ _registry_check_code(REGISTRY_RESET_LOOKUP_CACHE);
+
+ // During the next run in this request, don't bother re-checking existing
+ // files.
+ $check_existing_files = FALSE;
+
// We have some unchanged resources, warm up the cache - no need to pay
// for looking them up again.
if (count($unchanged_resources) > 0) {
diff --git a/www7/misc/brumann/polyfill-unserialize/.gitignore b/www7/misc/brumann/polyfill-unserialize/.gitignore
new file mode 100644
index 000000000..767699f1b
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/.gitignore
@@ -0,0 +1,4 @@
+/vendor/
+/phpunit.xml
+/.composer.lock
+
diff --git a/www7/misc/brumann/polyfill-unserialize/.travis.yml b/www7/misc/brumann/polyfill-unserialize/.travis.yml
new file mode 100644
index 000000000..352536f45
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/.travis.yml
@@ -0,0 +1,20 @@
+language: php
+
+sudo: false
+
+php:
+ - '5.3'
+ - '5.4'
+ - '5.5'
+ - '5.6'
+ - '7.0'
+ - '7.1'
+
+before_install:
+ - phpenv config-rm xdebug.ini
+ - composer self-update
+
+install:
+ - composer install
+
+script: phpunit
diff --git a/www7/misc/brumann/polyfill-unserialize/LICENSE b/www7/misc/brumann/polyfill-unserialize/LICENSE
new file mode 100644
index 000000000..0cb53d3b0
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Denis Brumann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/www7/misc/brumann/polyfill-unserialize/README.md b/www7/misc/brumann/polyfill-unserialize/README.md
new file mode 100644
index 000000000..bac25fe04
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/README.md
@@ -0,0 +1,61 @@
+Polyfill unserialize [![Build Status](https://travis-ci.org/dbrumann/polyfill-unserialize.svg?branch=master)](https://travis-ci.org/dbrumann/polyfill-unserialize)
+===
+
+Backports unserialize options introduced in PHP 7.0 to older PHP versions.
+This was originally designed as a Proof of Concept for Symfony Issue [#21090](https://github.com/symfony/symfony/pull/21090).
+
+You can use this package in projects that rely on PHP versions older than PHP 7.0.
+In case you are using PHP 7.0+ the original `unserialize()` will be used instead.
+
+From the [documentation](https://secure.php.net/manual/en/function.unserialize.php):
+
+> Warning: Do not pass untrusted user input to unserialize(). Unserialization can
+> result in code being loaded and executed due to object instantiation
+> and autoloading, and a malicious user may be able to exploit this.
+
+This warning holds true even when `allowed_classes` is used.
+
+Requirements
+------------
+
+ - PHP 5.3+
+
+Installation
+------------
+
+You can install this package via composer:
+
+```
+composer require brumann/polyfill-unserialize "^1.0"
+```
+
+Known Issues
+------------
+
+There is a mismatch in behavior when `allowed_classes` in `$options` is not
+of the correct type (array or boolean). PHP 7.1 will issue a warning, whereas
+PHP 7.0 will not. I opted to copy the behavior of the former.
+
+Tests
+-----
+
+You can run the test suite using PHPUnit. It is intentionally not bundled as
+dev dependency to make sure this package has the lowest restrictions on the
+implementing system as possible.
+
+Please read the [PHPUnit Manual](https://phpunit.de/manual/current/en/installation.html)
+for information how to install it on your system.
+
+You can run the test suite as follows:
+
+```
+phpunit -c phpunit.xml.dist tests/
+```
+
+Contributing
+------------
+
+This package is considered feature complete. As such I will likely not update it
+unless there are security issues.
+
+Should you find any bugs or have questions, feel free to submit an Issue or a Pull Request.
diff --git a/www7/misc/brumann/polyfill-unserialize/composer.json b/www7/misc/brumann/polyfill-unserialize/composer.json
new file mode 100644
index 000000000..ec4a2cf0e
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "brumann/polyfill-unserialize",
+ "description": "Backports unserialize options introduced in PHP 7.0 to older PHP versions.",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Denis Brumann",
+ "email": "denis.brumann@sensiolabs.de"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Brumann\\Polyfill\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\Brumann\\Polyfill\\": "tests/"
+ }
+ },
+ "minimum-stability": "stable",
+ "require": {
+ "php": "^5.3|^7.0"
+ }
+}
diff --git a/www7/misc/brumann/polyfill-unserialize/phpunit.xml.dist b/www7/misc/brumann/polyfill-unserialize/phpunit.xml.dist
new file mode 100644
index 000000000..8fea1bab8
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/phpunit.xml.dist
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ ./tests/
+
+
+
+
+
+ ./src/
+
+
+
diff --git a/www7/misc/brumann/polyfill-unserialize/src/Unserialize.php b/www7/misc/brumann/polyfill-unserialize/src/Unserialize.php
new file mode 100644
index 000000000..e025d55ed
--- /dev/null
+++ b/www7/misc/brumann/polyfill-unserialize/src/Unserialize.php
@@ -0,0 +1,58 @@
+= 70000) {
+ return \unserialize($serialized, $options);
+ }
+ if (!array_key_exists('allowed_classes', $options)) {
+ $options['allowed_classes'] = true;
+ }
+ $allowedClasses = $options['allowed_classes'];
+ if (true === $allowedClasses) {
+ return \unserialize($serialized);
+ }
+ if (false === $allowedClasses) {
+ $allowedClasses = array();
+ }
+ if (!is_array($allowedClasses)) {
+ trigger_error(
+ 'unserialize(): allowed_classes option should be array or boolean',
+ E_USER_WARNING
+ );
+ $allowedClasses = array();
+ }
+
+ $sanitizedSerialized = preg_replace_callback(
+ '/(^|;)O:\d+:"([^"]*)":(\d+):{/',
+ function ($match) use ($allowedClasses) {
+ list($completeMatch, $leftBorder, $className, $objectSize) = $match;
+ if (in_array($className, $allowedClasses)) {
+ return $completeMatch;
+ } else {
+ return sprintf(
+ '%sO:22:"__PHP_Incomplete_Class":%d:{s:27:"__PHP_Incomplete_Class_Name";%s',
+ $leftBorder,
+ $objectSize + 1, // size of object + 1 for added string
+ \serialize($className)
+ );
+ }
+ },
+ $serialized
+ );
+
+ return \unserialize($sanitizedSerialized);
+ }
+}
diff --git a/www7/misc/jquery-extend-3.4.0.js b/www7/misc/jquery-extend-3.4.0.js
new file mode 100644
index 000000000..975910949
--- /dev/null
+++ b/www7/misc/jquery-extend-3.4.0.js
@@ -0,0 +1,112 @@
+/**
+ * For jQuery versions less than 3.4.0, this replaces the jQuery.extend
+ * function with the one from jQuery 3.4.0, slightly modified (documented
+ * below) to be compatible with older jQuery versions and browsers.
+ *
+ * This provides the Object.prototype pollution vulnerability fix to Drupal
+ * installations running older jQuery versions, including the versions shipped
+ * with Drupal core and https://www.drupal.org/project/jquery_update.
+ *
+ * @see https://github.com/jquery/jquery/pull/4333
+ */
+
+(function (jQuery) {
+
+// Do not override jQuery.extend() if the jQuery version is already >=3.4.0.
+var versionParts = jQuery.fn.jquery.split('.');
+var majorVersion = parseInt(versionParts[0]);
+var minorVersion = parseInt(versionParts[1]);
+var patchVersion = parseInt(versionParts[2]);
+var isPreReleaseVersion = (patchVersion.toString() !== versionParts[2]);
+if (
+ (majorVersion > 3) ||
+ (majorVersion === 3 && minorVersion > 4) ||
+ (majorVersion === 3 && minorVersion === 4 && patchVersion > 0) ||
+ (majorVersion === 3 && minorVersion === 4 && patchVersion === 0 && !isPreReleaseVersion)
+) {
+ return;
+}
+
+/**
+ * This is almost verbatim copied from jQuery 3.4.0.
+ *
+ * Only two minor changes have been made:
+ * - The call to isFunction() is changed to jQuery.isFunction().
+ * - The two calls to Array.isArray() is changed to jQuery.isArray().
+ *
+ * The above two changes ensure compatibility with all older jQuery versions
+ * (1.4.4 - 3.3.1) and older browser versions (e.g., IE8).
+ */
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[ 0 ] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
+ target = {};
+ }
+
+ // Extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+
+ // Only deal with non-null/undefined values
+ if ( ( options = arguments[ i ] ) != null ) {
+
+ // Extend the base object
+ for ( name in options ) {
+ copy = options[ name ];
+
+ // Prevent Object.prototype pollution
+ // Prevent never-ending loop
+ if ( name === "__proto__" || target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = jQuery.isArray( copy ) ) ) ) {
+ src = target[ name ];
+
+ // Ensure proper type for the source value
+ if ( copyIsArray && !jQuery.isArray( src ) ) {
+ clone = [];
+ } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
+ clone = {};
+ } else {
+ clone = src;
+ }
+ copyIsArray = false;
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+})(jQuery);
diff --git a/www7/misc/typo3/phar-stream-wrapper/.gitignore b/www7/misc/typo3/phar-stream-wrapper/.gitignore
new file mode 100644
index 000000000..157ff0c59
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/.gitignore
@@ -0,0 +1,3 @@
+.idea
+vendor/
+composer.lock
diff --git a/www7/misc/typo3/phar-stream-wrapper/README.md b/www7/misc/typo3/phar-stream-wrapper/README.md
index b632784bd..179bb6fd7 100644
--- a/www7/misc/typo3/phar-stream-wrapper/README.md
+++ b/www7/misc/typo3/phar-stream-wrapper/README.md
@@ -63,7 +63,7 @@ adjusted to according requirements.
```
$behavior = new \TYPO3\PharStreamWrapper\Behavior();
-Manager::initialize(
+\TYPO3\PharStreamWrapper\Manager::initialize(
$behavior->withAssertion(new PharExtensionInterceptor())
);
@@ -90,7 +90,7 @@ if (in_array('phar', stream_get_wrappers())) {
+ `COMMAND_UNLINK`
+ `COMMAND_URL_STAT`
-## Interceptor
+## Interceptors
The following interceptor is shipped with the package and ready to use in order
to block any Phar invocation of files not having a `.phar` suffix. Besides that
@@ -137,9 +137,72 @@ class PharExtensionInterceptor implements Assertable
}
```
+### ConjunctionInterceptor
+
+This interceptor combines multiple interceptors implementing `Assertable`.
+It succeeds when all nested interceptors succeed as well (logical `AND`).
+
+```
+$behavior = new \TYPO3\PharStreamWrapper\Behavior();
+\TYPO3\PharStreamWrapper\Manager::initialize(
+ $behavior->withAssertion(new ConjunctionInterceptor(array(
+ new PharExtensionInterceptor(),
+ new PharMetaDataInterceptor()
+ )))
+);
+```
+
+### PharExtensionInterceptor
+
+This (basic) interceptor just checks whether the invoked Phar archive has
+an according `.phar` file extension. Resolving symbolic links as well as
+Phar internal alias resolving are considered as well.
+
+```
+$behavior = new \TYPO3\PharStreamWrapper\Behavior();
+\TYPO3\PharStreamWrapper\Manager::initialize(
+ $behavior->withAssertion(new PharExtensionInterceptor())
+);
+```
+
+### PharMetaDataInterceptor
+
+This interceptor is actually checking serialized Phar meta-data against
+PHP objects and would consider a Phar archive malicious in case not only
+scalar values are found. A custom low-level `Phar\Reader` is used in order to
+avoid using PHP's `Phar` object which would trigger the initial vulnerability.
+
+```
+$behavior = new \TYPO3\PharStreamWrapper\Behavior();
+\TYPO3\PharStreamWrapper\Manager::initialize(
+ $behavior->withAssertion(new PharMetaDataInterceptor())
+);
+```
+
+## Reader
+
+* `Phar\Reader::__construct(string $fileName)`: Creates low-level reader for Phar archive
+* `Phar\Reader::resolveContainer(): Phar\Container`: Resolves model representing Phar archive
+* `Phar\Container::getStub(): Phar\Stub`: Resolves (plain PHP) stub section of Phar archive
+* `Phar\Container::getManifest(): Phar\Manifest`: Resolves parsed Phar archive manifest as
+ documented at http://php.net/manual/en/phar.fileformat.manifestfile.php
+* `Phar\Stub::getMappedAlias(): string`: Resolves internal Phar archive alias defined in stub
+ using `Phar::mapPhar('alias.phar')` - actually the plain PHP source is analyzed here
+* `Phar\Manifest::getAlias(): string` - Resolves internal Phar archive alias defined in manifest
+ using `Phar::setAlias('alias.phar')`
+* `Phar\Manifest::getMetaData(): string`: Resolves serialized Phar archive meta-data
+* `Phar\Manifest::deserializeMetaData(): mixed`: Resolves deserialized Phar archive meta-data
+ containing only scalar values - in case an object is determined, an according
+ `Phar\DeserializationException` will be thrown
+
+```
+$reader = new Phar\Reader('example.phar');
+var_dump($reader->resolveContainer()->getManifest()->deserializeMetaData());
+```
+
## Helper
-* `Helper::determineBaseFile(string $path)`: Determines base file that can be
+* `Helper::determineBaseFile(string $path): string`: Determines base file that can be
accessed using the regular file system. For instance the following path
`phar:///home/user/bundle.phar/content.txt` would be resolved to
`/home/user/bundle.phar`.
diff --git a/www7/misc/typo3/phar-stream-wrapper/composer.json b/www7/misc/typo3/phar-stream-wrapper/composer.json
index d308f8c87..8c2241187 100644
--- a/www7/misc/typo3/phar-stream-wrapper/composer.json
+++ b/www7/misc/typo3/phar-stream-wrapper/composer.json
@@ -6,9 +6,13 @@
"homepage": "https://typo3.org/",
"keywords": ["php", "phar", "stream-wrapper", "security"],
"require": {
- "php": "^5.3.3|^7.0"
+ "php": "^5.3.3|^7.0",
+ "ext-fileinfo": "*",
+ "ext-json": "*",
+ "brumann/polyfill-unserialize": "^1.0"
},
"require-dev": {
+ "ext-xdebug": "*",
"phpunit/phpunit": "^4.8.36"
},
"autoload": {
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Collectable.php b/www7/misc/typo3/phar-stream-wrapper/src/Collectable.php
new file mode 100644
index 000000000..4694dc946
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Collectable.php
@@ -0,0 +1,37 @@
+assertAssertions($assertions);
+ $this->assertions = $assertions;
+ }
+
+ /**
+ * Executes assertions based on all contained assertions.
+ *
+ * @param string $path
+ * @param string $command
+ * @return bool
+ * @throws Exception
+ */
+ public function assert($path, $command)
+ {
+ if ($this->invokeAssertions($path, $command)) {
+ return true;
+ }
+ throw new Exception(
+ sprintf(
+ 'Assertion failed in "%s"',
+ $path
+ ),
+ 1539625084
+ );
+ }
+
+ /**
+ * @param Assertable[] $assertions
+ */
+ private function assertAssertions(array $assertions)
+ {
+ foreach ($assertions as $assertion) {
+ if (!$assertion instanceof Assertable) {
+ throw new \InvalidArgumentException(
+ sprintf(
+ 'Instance %s must implement Assertable',
+ get_class($assertion)
+ ),
+ 1539624719
+ );
+ }
+ }
+ }
+
+ /**
+ * @param string $path
+ * @param string $command
+ * @return bool
+ */
+ private function invokeAssertions($path, $command)
+ {
+ try {
+ foreach ($this->assertions as $assertion) {
+ if (!$assertion->assert($path, $command)) {
+ return false;
+ }
+ }
+ } catch (Exception $exception) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharExtensionInterceptor.php b/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharExtensionInterceptor.php
index db500afc8..6e7aeedcb 100644
--- a/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharExtensionInterceptor.php
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharExtensionInterceptor.php
@@ -12,8 +12,8 @@
*/
use TYPO3\PharStreamWrapper\Assertable;
-use TYPO3\PharStreamWrapper\Helper;
use TYPO3\PharStreamWrapper\Exception;
+use TYPO3\PharStreamWrapper\Manager;
class PharExtensionInterceptor implements Assertable
{
@@ -45,11 +45,11 @@ public function assert($path, $command)
*/
private function baseFileContainsPharExtension($path)
{
- $baseFile = Helper::determineBaseFile($path);
- if ($baseFile === null) {
+ $invocation = Manager::instance()->resolve($path);
+ if ($invocation === null) {
return false;
}
- $fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION);
+ $fileExtension = pathinfo($invocation->getBaseName(), PATHINFO_EXTENSION);
return strtolower($fileExtension) === 'phar';
}
}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharMetaDataInterceptor.php b/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharMetaDataInterceptor.php
new file mode 100644
index 000000000..e981dc6a6
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharMetaDataInterceptor.php
@@ -0,0 +1,73 @@
+baseFileDoesNotHaveMetaDataIssues($path)) {
+ return true;
+ }
+ throw new Exception(
+ sprintf(
+ 'Problematic meta-data in "%s"',
+ $path
+ ),
+ 1539632368
+ );
+ }
+
+ /**
+ * @param string $path
+ * @return bool
+ */
+ private function baseFileDoesNotHaveMetaDataIssues($path)
+ {
+ $invocation = Manager::instance()->resolve($path);
+ if ($invocation === null) {
+ return false;
+ }
+ // directly return in case invocation was checked before
+ if ($invocation->getVariable(__CLASS__) === true) {
+ return true;
+ }
+ // otherwise analyze meta-data
+ try {
+ $reader = new Reader($invocation->getBaseName());
+ $reader->resolveContainer()->getManifest()->deserializeMetaData();
+ $invocation->setVariable(__CLASS__, true);
+ } catch (DeserializationException $exception) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Manager.php b/www7/misc/typo3/phar-stream-wrapper/src/Manager.php
index 1eb9735d9..f938ad985 100644
--- a/www7/misc/typo3/phar-stream-wrapper/src/Manager.php
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Manager.php
@@ -11,7 +11,11 @@
* The TYPO3 project - inspiring people to share!
*/
-class Manager implements Assertable
+use TYPO3\PharStreamWrapper\Resolver\PharInvocation;
+use TYPO3\PharStreamWrapper\Resolver\PharInvocationCollection;
+use TYPO3\PharStreamWrapper\Resolver\PharInvocationResolver;
+
+class Manager
{
/**
* @var self
@@ -23,14 +27,29 @@ class Manager implements Assertable
*/
private $behavior;
+ /**
+ * @var Resolvable
+ */
+ private $resolver;
+
+ /**
+ * @var Collectable
+ */
+ private $collection;
+
/**
* @param Behavior $behaviour
+ * @param Resolvable $resolver
+ * @param Collectable $collection
* @return self
*/
- public static function initialize(Behavior $behaviour)
- {
+ public static function initialize(
+ Behavior $behaviour,
+ Resolvable $resolver = null,
+ Collectable $collection = null
+ ) {
if (self::$instance === null) {
- self::$instance = new self($behaviour);
+ self::$instance = new self($behaviour, $resolver, $collection);
return self::$instance;
}
throw new \LogicException(
@@ -67,9 +86,22 @@ public static function destroy()
/**
* @param Behavior $behaviour
+ * @param Resolvable $resolver
+ * @param Collectable $collection
*/
- private function __construct(Behavior $behaviour)
- {
+ private function __construct(
+ Behavior $behaviour,
+ Resolvable $resolver = null,
+ Collectable $collection = null
+ ) {
+ if ($collection === null) {
+ $collection = new PharInvocationCollection();
+ }
+ if ($resolver === null) {
+ $resolver = new PharInvocationResolver();
+ }
+ $this->collection = $collection;
+ $this->resolver = $resolver;
$this->behavior = $behaviour;
}
@@ -82,4 +114,22 @@ public function assert($path, $command)
{
return $this->behavior->assert($path, $command);
}
+
+ /**
+ * @param string $path
+ * @param null|int $flags
+ * @return null|PharInvocation
+ */
+ public function resolve($path, $flags = null)
+ {
+ return $this->resolver->resolve($path, $flags);
+ }
+
+ /**
+ * @return Collectable
+ */
+ public function getCollection()
+ {
+ return $this->collection;
+ }
}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Phar/Container.php b/www7/misc/typo3/phar-stream-wrapper/src/Phar/Container.php
new file mode 100644
index 000000000..f02387d73
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Phar/Container.php
@@ -0,0 +1,59 @@
+stub = $stub;
+ $this->manifest = $manifest;
+ }
+
+ /**
+ * @return Stub
+ */
+ public function getStub()
+ {
+ return $this->stub;
+ }
+
+ /**
+ * @return Manifest
+ */
+ public function getManifest()
+ {
+ return $this->manifest;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAlias()
+ {
+ return $this->manifest->getAlias() ?: $this->stub->getMappedAlias();
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Phar/DeserializationException.php b/www7/misc/typo3/phar-stream-wrapper/src/Phar/DeserializationException.php
new file mode 100644
index 000000000..5a675d34f
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Phar/DeserializationException.php
@@ -0,0 +1,18 @@
+manifestLength = Reader::resolveFourByteLittleEndian($content, 0);
+ $target->amountOfFiles = Reader::resolveFourByteLittleEndian($content, 4);
+ $target->flags = Reader::resolveFourByteLittleEndian($content, 10);
+ $target->aliasLength = Reader::resolveFourByteLittleEndian($content, 14);
+ $target->alias = substr($content, 18, $target->aliasLength);
+ $target->metaDataLength = Reader::resolveFourByteLittleEndian($content, 18 + $target->aliasLength);
+ $target->metaData = substr($content, 22 + $target->aliasLength, $target->metaDataLength);
+
+ $apiVersionNibbles = Reader::resolveTwoByteBigEndian($content, 8);
+ $target->apiVersion = implode('.', array(
+ ($apiVersionNibbles & 0xf000) >> 12,
+ ($apiVersionNibbles & 0x0f00) >> 8,
+ ($apiVersionNibbles & 0x00f0) >> 4,
+ ));
+
+ return $target;
+ }
+
+ /**
+ * @var int
+ */
+ private $manifestLength;
+
+ /**
+ * @var int
+ */
+ private $amountOfFiles;
+
+ /**
+ * @var string
+ */
+ private $apiVersion;
+
+ /**
+ * @var int
+ */
+ private $flags;
+
+ /**
+ * @var int
+ */
+ private $aliasLength;
+
+ /**
+ * @var string
+ */
+ private $alias;
+
+ /**
+ * @var int
+ */
+ private $metaDataLength;
+
+ /**
+ * @var string
+ */
+ private $metaData;
+
+ /**
+ * Avoid direct instantiation.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * @return int
+ */
+ public function getManifestLength()
+ {
+ return $this->manifestLength;
+ }
+
+ /**
+ * @return int
+ */
+ public function getAmountOfFiles()
+ {
+ return $this->amountOfFiles;
+ }
+
+ /**
+ * @return string
+ */
+ public function getApiVersion()
+ {
+ return $this->apiVersion;
+ }
+
+ /**
+ * @return int
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * @return int
+ */
+ public function getAliasLength()
+ {
+ return $this->aliasLength;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMetaDataLength()
+ {
+ return $this->metaDataLength;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMetaData()
+ {
+ return $this->metaData;
+ }
+
+ /**
+ * @return mixed|null
+ */
+ public function deserializeMetaData()
+ {
+ if (empty($this->metaData)) {
+ return null;
+ }
+
+ $result = Unserialize::unserialize($this->metaData, array('allowed_classes' => false));
+
+ $serialized = json_encode($result);
+ if (strpos($serialized, '__PHP_Incomplete_Class_Name') !== false) {
+ throw new DeserializationException(
+ 'Meta-data contains serialized object',
+ 1539623382
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Phar/Reader.php b/www7/misc/typo3/phar-stream-wrapper/src/Phar/Reader.php
new file mode 100644
index 000000000..32e516be3
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Phar/Reader.php
@@ -0,0 +1,220 @@
+fileName = $fileName;
+ $this->fileType = $this->determineFileType();
+ }
+
+ /**
+ * @return Container
+ */
+ public function resolveContainer()
+ {
+ $data = $this->extractData($this->resolveStream() . $this->fileName);
+
+ if ($data['stubContent'] === null) {
+ throw new ReaderException(
+ 'Cannot resolve stub',
+ 1547807881
+ );
+ }
+ if ($data['manifestContent'] === null || $data['manifestLength'] === null) {
+ throw new ReaderException(
+ 'Cannot resolve manifest',
+ 1547807882
+ );
+ }
+ if (strlen($data['manifestContent']) < $data['manifestLength']) {
+ throw new ReaderException(
+ sprintf(
+ 'Exected manifest length %d, got %d',
+ strlen($data['manifestContent']),
+ $data['manifestLength']
+ ),
+ 1547807883
+ );
+ }
+
+ return new Container(
+ Stub::fromContent($data['stubContent']),
+ Manifest::fromContent($data['manifestContent'])
+ );
+ }
+
+ /**
+ * @param string $fileName e.g. '/path/file.phar' or 'compress.zlib:///path/file.phar'
+ * @return array
+ */
+ private function extractData($fileName)
+ {
+ $stubContent = null;
+ $manifestContent = null;
+ $manifestLength = null;
+
+ $resource = fopen($fileName, 'r');
+ if (!is_resource($resource)) {
+ throw new ReaderException(
+ sprintf('Resource %s could not be opened', $fileName),
+ 1547902055
+ );
+ }
+
+ while (!feof($resource)) {
+ $line = fgets($resource);
+ // stop reading file when manifest can be extracted
+ if ($manifestLength !== null && $manifestContent !== null && strlen($manifestContent) >= $manifestLength) {
+ break;
+ }
+
+ $manifestPosition = strpos($line, '__HALT_COMPILER();');
+
+ // first line contains start of manifest
+ if ($stubContent === null && $manifestContent === null && $manifestPosition !== false) {
+ $stubContent = substr($line, 0, $manifestPosition - 1);
+ $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
+ $manifestLength = $this->resolveManifestLength($manifestContent);
+ // line contains start of stub
+ } elseif ($stubContent === null) {
+ $stubContent = $line;
+ // line contains start of manifest
+ } elseif ($manifestContent === null && $manifestPosition !== false) {
+ $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
+ $manifestLength = $this->resolveManifestLength($manifestContent);
+ // manifest has been started (thus is cannot be stub anymore), add content
+ } elseif ($manifestContent !== null) {
+ $manifestContent .= $line;
+ $manifestLength = $this->resolveManifestLength($manifestContent);
+ // stub has been started (thus cannot be manifest here, yet), add content
+ } elseif ($stubContent !== null) {
+ $stubContent .= $line;
+ }
+ }
+ fclose($resource);
+
+ return array(
+ 'stubContent' => $stubContent,
+ 'manifestContent' => $manifestContent,
+ 'manifestLength' => $manifestLength,
+ );
+ }
+
+ /**
+ * Resolves stream in order to handle compressed Phar archives.
+ *
+ * @return string
+ */
+ private function resolveStream()
+ {
+ if ($this->fileType === 'application/x-gzip') {
+ return 'compress.zlib://';
+ } elseif ($this->fileType === 'application/x-bzip2') {
+ return 'compress.bzip2://';
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ private function determineFileType()
+ {
+ $fileInfo = new \finfo();
+ return $fileInfo->file($this->fileName, FILEINFO_MIME_TYPE);
+ }
+
+ /**
+ * @param string $content
+ * @return int|null
+ */
+ private function resolveManifestLength($content)
+ {
+ if (strlen($content) < 4) {
+ return null;
+ }
+ return static::resolveFourByteLittleEndian($content, 0);
+ }
+
+ /**
+ * @param string $content
+ * @param int $start
+ * @return int
+ */
+ public static function resolveFourByteLittleEndian($content, $start)
+ {
+ $payload = substr($content, $start, 4);
+ if (!is_string($payload)) {
+ throw new ReaderException(
+ sprintf('Cannot resolve value at offset %d', $start),
+ 1539614260
+ );
+ }
+
+ $value = unpack('V', $payload);
+ if (!isset($value[1])) {
+ throw new ReaderException(
+ sprintf('Cannot resolve value at offset %d', $start),
+ 1539614261
+ );
+ }
+ return $value[1];
+ }
+
+ /**
+ * @param string $content
+ * @param int $start
+ * @return int
+ */
+ public static function resolveTwoByteBigEndian($content, $start)
+ {
+ $payload = substr($content, $start, 2);
+ if (!is_string($payload)) {
+ throw new ReaderException(
+ sprintf('Cannot resolve value at offset %d', $start),
+ 1539614263
+ );
+ }
+
+ $value = unpack('n', $payload);
+ if (!isset($value[1])) {
+ throw new ReaderException(
+ sprintf('Cannot resolve value at offset %d', $start),
+ 1539614264
+ );
+ }
+ return $value[1];
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Phar/ReaderException.php b/www7/misc/typo3/phar-stream-wrapper/src/Phar/ReaderException.php
new file mode 100644
index 000000000..002afe158
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Phar/ReaderException.php
@@ -0,0 +1,18 @@
+content = $content;
+
+ if (
+ stripos($content, 'Phar::mapPhar(') !== false
+ && preg_match('#Phar\:\:mapPhar\(([^)]+)\)#', $content, $matches)
+ ) {
+ // remove spaces, single & double quotes
+ // @todo `'my' . 'alias' . '.phar'` is not evaluated here
+ $target->mappedAlias = trim($matches[1], ' \'"');
+ }
+
+ return $target;
+ }
+
+ /**
+ * @var string
+ */
+ private $content;
+
+ /**
+ * @var string
+ */
+ private $mappedAlias = '';
+
+ /**
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMappedAlias()
+ {
+ return $this->mappedAlias;
+ }
+}
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php b/www7/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php
index 5a924e4cc..acd5656f4 100644
--- a/www7/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php
+++ b/www7/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php
@@ -11,6 +11,8 @@
* The TYPO3 project - inspiring people to share!
*/
+use TYPO3\PharStreamWrapper\Resolver\PharInvocation;
+
class PharStreamWrapper
{
/**
@@ -29,6 +31,11 @@ class PharStreamWrapper
*/
protected $internalResource;
+ /**
+ * @var PharInvocation
+ */
+ protected $invocation;
+
/**
* @return bool
*/
@@ -409,7 +416,8 @@ public function url_stat($path, $flags)
*/
protected function assert($path, $command)
{
- if ($this->resolveAssertable()->assert($path, $command) === true) {
+ if (Manager::instance()->assert($path, $command) === true) {
+ $this->collectInvocation($path);
return;
}
@@ -424,7 +432,33 @@ protected function assert($path, $command)
}
/**
- * @return Assertable
+ * @param string $path
+ */
+ protected function collectInvocation($path)
+ {
+ if (isset($this->invocation)) {
+ return;
+ }
+
+ $manager = Manager::instance();
+ $this->invocation = $manager->resolve($path);
+ if ($this->invocation === null) {
+ throw new Exception(
+ 'Expected invocation could not be resolved',
+ 1556389591
+ );
+ }
+ // confirm, previous interceptor(s) validated invocation
+ $this->invocation->confirm();
+ $collection = $manager->getCollection();
+ if (!$collection->has($this->invocation)) {
+ $collection->collect($this->invocation);
+ }
+ }
+
+ /**
+ * @return Manager|Assertable
+ * @deprecated Use Manager::instance() directly
*/
protected function resolveAssertable()
{
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Resolvable.php b/www7/misc/typo3/phar-stream-wrapper/src/Resolvable.php
new file mode 100644
index 000000000..5d5fdc63e
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Resolvable.php
@@ -0,0 +1,24 @@
+baseName = $baseName;
+ $this->alias = $alias;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->baseName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBaseName()
+ {
+ return $this->baseName;
+ }
+
+ /**
+ * @return null|string
+ */
+ public function getAlias()
+ {
+ return $this->alias;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isConfirmed()
+ {
+ return $this->confirmed;
+ }
+
+ public function confirm()
+ {
+ $this->confirmed = true;
+ }
+
+ /**
+ * @param string $name
+ * @return mixed|null
+ */
+ public function getVariable($name)
+ {
+ if (!isset($this->variables[$name])) {
+ return null;
+ }
+ return $this->variables[$name];
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ */
+ public function setVariable($name, $value)
+ {
+ $this->variables[$name] = $value;
+ }
+
+ /**
+ * @param PharInvocation $other
+ * @return bool
+ */
+ public function equals(PharInvocation $other)
+ {
+ return $other->baseName === $this->baseName
+ && $other->alias === $this->alias;
+ }
+}
\ No newline at end of file
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationCollection.php b/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationCollection.php
new file mode 100644
index 000000000..e445ff66e
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationCollection.php
@@ -0,0 +1,156 @@
+invocations, true);
+ }
+
+ /**
+ * @param PharInvocation $invocation
+ * @param null|int $flags
+ * @return bool
+ */
+ public function collect(PharInvocation $invocation, $flags = null)
+ {
+ if ($flags === null) {
+ $flags = static::UNIQUE_INVOCATION | static::DUPLICATE_ALIAS_WARNING;
+ }
+ if ($invocation->getBaseName() === ''
+ || $invocation->getAlias() === ''
+ || !$this->assertUniqueBaseName($invocation, $flags)
+ || !$this->assertUniqueInvocation($invocation, $flags)
+ ) {
+ return false;
+ }
+ if ($flags & static::DUPLICATE_ALIAS_WARNING) {
+ $this->triggerDuplicateAliasWarning($invocation);
+ }
+
+ $this->invocations[] = $invocation;
+ return true;
+ }
+
+ /**
+ * @param callable $callback
+ * @param bool $reverse
+ * @return null|PharInvocation
+ */
+ public function findByCallback($callback, $reverse = false)
+ {
+ foreach ($this->getInvocations($reverse) as $invocation) {
+ if (call_user_func($callback, $invocation) === true) {
+ return $invocation;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Asserts that base-name is unique. This disallows having multiple invocations for
+ * same base-name but having different alias names.
+ *
+ * @param PharInvocation $invocation
+ * @param int $flags
+ * @return bool
+ */
+ private function assertUniqueBaseName(PharInvocation $invocation, $flags)
+ {
+ if (!($flags & static::UNIQUE_BASE_NAME)) {
+ return true;
+ }
+ return $this->findByCallback(
+ function (PharInvocation $candidate) use ($invocation) {
+ return $candidate->getBaseName() === $invocation->getBaseName();
+ }
+ ) === null;
+ }
+
+ /**
+ * Asserts that combination of base-name and alias is unique. This allows having multiple
+ * invocations for same base-name but having different alias names (for whatever reason).
+ *
+ * @param PharInvocation $invocation
+ * @param int $flags
+ * @return bool
+ */
+ private function assertUniqueInvocation(PharInvocation $invocation, $flags)
+ {
+ if (!($flags & static::UNIQUE_INVOCATION)) {
+ return true;
+ }
+ return $this->findByCallback(
+ function (PharInvocation $candidate) use ($invocation) {
+ return $candidate->equals($invocation);
+ }
+ ) === null;
+ }
+
+ /**
+ * Triggers warning for invocations with same alias and same confirmation state.
+ *
+ * @param PharInvocation $invocation
+ * @see \TYPO3\PharStreamWrapper\PharStreamWrapper::collectInvocation()
+ */
+ private function triggerDuplicateAliasWarning(PharInvocation $invocation)
+ {
+ $sameAliasInvocation = $this->findByCallback(
+ function (PharInvocation $candidate) use ($invocation) {
+ return $candidate->isConfirmed() === $invocation->isConfirmed()
+ && $candidate->getAlias() === $invocation->getAlias();
+ },
+ true
+ );
+ if ($sameAliasInvocation === null) {
+ return;
+ }
+ trigger_error(
+ sprintf(
+ 'Alias %s cannot be used by %s, already used by %s',
+ $invocation->getAlias(),
+ $invocation->getBaseName(),
+ $sameAliasInvocation->getBaseName()
+ ),
+ E_USER_WARNING
+ );
+ }
+
+ /**
+ * @param bool $reverse
+ * @return PharInvocation[]
+ */
+ private function getInvocations($reverse = false)
+ {
+ if ($reverse) {
+ return array_reverse($this->invocations);
+ }
+ return $this->invocations;
+ }
+}
\ No newline at end of file
diff --git a/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationResolver.php b/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationResolver.php
new file mode 100644
index 000000000..80b86d3db
--- /dev/null
+++ b/www7/misc/typo3/phar-stream-wrapper/src/Resolver/PharInvocationResolver.php
@@ -0,0 +1,241 @@
+findByAlias($path);
+ if ($invocation !== null) {
+ return $invocation;
+ }
+ }
+
+ $baseName = $this->resolveBaseName($path, $flags);
+ if ($baseName === null) {
+ return null;
+ }
+
+ if ($flags & static::RESOLVE_REALPATH) {
+ $baseName = $this->baseNames[$baseName];
+ }
+
+ return $this->retrieveInvocation($baseName, $flags);
+ }
+
+ /**
+ * Retrieves PharInvocation, either existing in collection or created on demand
+ * with resolving a potential alias name used in the according Phar archive.
+ *
+ * @param string $baseName
+ * @param int $flags
+ * @return PharInvocation
+ */
+ private function retrieveInvocation($baseName, $flags)
+ {
+ $invocation = $this->findByBaseName($baseName);
+ if ($invocation !== null) {
+ return $invocation;
+ }
+
+ if ($flags & static::RESOLVE_ALIAS) {
+ $reader = new Reader($baseName);
+ $alias = $reader->resolveContainer()->getAlias();
+ } else {
+ $alias = '';
+ }
+ // add unconfirmed(!) new invocation to collection
+ $invocation = new PharInvocation($baseName, $alias);
+ Manager::instance()->getCollection()->collect($invocation);
+ return $invocation;
+ }
+
+ /**
+ * @param string $path
+ * @param int $flags
+ * @return null|string
+ */
+ private function resolveBaseName($path, $flags)
+ {
+ $baseName = $this->findInBaseNames($path);
+ if ($baseName !== null) {
+ return $baseName;
+ }
+
+ $baseName = Helper::determineBaseFile($path);
+ if ($baseName !== null) {
+ $this->addBaseName($baseName);
+ return $baseName;
+ }
+
+ $possibleAlias = $this->resolvePossibleAlias($path);
+ if (!($flags & static::RESOLVE_ALIAS) || $possibleAlias === null) {
+ return null;
+ }
+
+ $trace = debug_backtrace();
+ foreach ($trace as $item) {
+ if (!isset($item['function']) || !isset($item['args'][0])
+ || !in_array($item['function'], $this->invocationFunctionNames, true)) {
+ continue;
+ }
+ $currentPath = $item['args'][0];
+ if (Helper::hasPharPrefix($currentPath)) {
+ continue;
+ }
+ $currentBaseName = Helper::determineBaseFile($currentPath);
+ if ($currentBaseName === null) {
+ continue;
+ }
+ // ensure the possible alias name (how we have been called initially) matches
+ // the resolved alias name that was retrieved by the current possible base name
+ $reader = new Reader($currentBaseName);
+ $currentAlias = $reader->resolveContainer()->getAlias();
+ if ($currentAlias !== $possibleAlias) {
+ continue;
+ }
+ $this->addBaseName($currentBaseName);
+ return $currentBaseName;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $path
+ * @return null|string
+ */
+ private function resolvePossibleAlias($path)
+ {
+ $normalizedPath = Helper::normalizePath($path);
+ return strstr($normalizedPath, '/', true) ?: null;
+ }
+
+ /**
+ * @param string $baseName
+ * @return null|PharInvocation
+ */
+ private function findByBaseName($baseName)
+ {
+ return Manager::instance()->getCollection()->findByCallback(
+ function (PharInvocation $candidate) use ($baseName) {
+ return $candidate->getBaseName() === $baseName;
+ },
+ true
+ );
+ }
+
+ /**
+ * @param string $path
+ * @return null|string
+ */
+ private function findInBaseNames($path)
+ {
+ // return directly if the resolved base name was submitted
+ if (in_array($path, $this->baseNames, true)) {
+ return $path;
+ }
+
+ $parts = explode('/', Helper::normalizePath($path));
+
+ while (count($parts)) {
+ $currentPath = implode('/', $parts);
+ if (isset($this->baseNames[$currentPath])) {
+ return $currentPath;
+ }
+ array_pop($parts);
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $baseName
+ */
+ private function addBaseName($baseName)
+ {
+ if (isset($this->baseNames[$baseName])) {
+ return;
+ }
+ $this->baseNames[$baseName] = realpath($baseName);
+ }
+
+ /**
+ * Finds confirmed(!) invocations by alias.
+ *
+ * @param string $path
+ * @return null|PharInvocation
+ * @see \TYPO3\PharStreamWrapper\PharStreamWrapper::collectInvocation()
+ */
+ private function findByAlias($path)
+ {
+ $possibleAlias = $this->resolvePossibleAlias($path);
+ if ($possibleAlias === null) {
+ return null;
+ }
+ return Manager::instance()->getCollection()->findByCallback(
+ function (PharInvocation $candidate) use ($possibleAlias) {
+ return $candidate->isConfirmed() && $candidate->getAlias() === $possibleAlias;
+ },
+ true
+ );
+ }
+}
diff --git a/www7/modules/aggregator/aggregator.info b/www7/modules/aggregator/aggregator.info
index a5532dc2f..d96edbdbf 100644
--- a/www7/modules/aggregator/aggregator.info
+++ b/www7/modules/aggregator/aggregator.info
@@ -7,7 +7,7 @@ files[] = aggregator.test
configure = admin/config/services/aggregator/settings
stylesheets[all][] = aggregator.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/aggregator/tests/aggregator_test.info b/www7/modules/aggregator/tests/aggregator_test.info
index 90a8b2f63..e0253ce91 100644
--- a/www7/modules/aggregator/tests/aggregator_test.info
+++ b/www7/modules/aggregator/tests/aggregator_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/block/block.info b/www7/modules/block/block.info
index c9c4171ec..8fccc4881 100644
--- a/www7/modules/block/block.info
+++ b/www7/modules/block/block.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = block.test
configure = admin/structure/block
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/block/tests/block_test.info b/www7/modules/block/tests/block_test.info
index beb9141a0..dbd486261 100644
--- a/www7/modules/block/tests/block_test.info
+++ b/www7/modules/block/tests/block_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/block/tests/themes/block_test_theme/block_test_theme.info b/www7/modules/block/tests/themes/block_test_theme/block_test_theme.info
index 89305fc0e..9fe95fa66 100644
--- a/www7/modules/block/tests/themes/block_test_theme/block_test_theme.info
+++ b/www7/modules/block/tests/themes/block_test_theme/block_test_theme.info
@@ -13,7 +13,7 @@ regions[footer] = Footer
regions[highlighted] = Highlighted
regions[help] = Help
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/blog/blog.info b/www7/modules/blog/blog.info
index 041aadcfe..aade48494 100644
--- a/www7/modules/blog/blog.info
+++ b/www7/modules/blog/blog.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = blog.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/book/book.info b/www7/modules/book/book.info
index a3c5af7eb..95054e461 100644
--- a/www7/modules/book/book.info
+++ b/www7/modules/book/book.info
@@ -7,7 +7,7 @@ files[] = book.test
configure = admin/content/book/settings
stylesheets[all][] = book.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/color/color.info b/www7/modules/color/color.info
index 2f986d902..764e24944 100644
--- a/www7/modules/color/color.info
+++ b/www7/modules/color/color.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = color.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/comment/comment.info b/www7/modules/comment/comment.info
index 7970128c7..8cf5f1673 100644
--- a/www7/modules/comment/comment.info
+++ b/www7/modules/comment/comment.info
@@ -9,7 +9,7 @@ files[] = comment.test
configure = admin/content/comment
stylesheets[all][] = comment.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/contact/contact.info b/www7/modules/contact/contact.info
index 663818e1e..b7c403c8c 100644
--- a/www7/modules/contact/contact.info
+++ b/www7/modules/contact/contact.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = contact.test
configure = admin/structure/contact
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/contextual/contextual.info b/www7/modules/contextual/contextual.info
index d23cc9a81..17a83bd3e 100644
--- a/www7/modules/contextual/contextual.info
+++ b/www7/modules/contextual/contextual.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = contextual.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/dashboard/dashboard.info b/www7/modules/dashboard/dashboard.info
index d3ca72162..4fc749d3c 100644
--- a/www7/modules/dashboard/dashboard.info
+++ b/www7/modules/dashboard/dashboard.info
@@ -7,7 +7,7 @@ files[] = dashboard.test
dependencies[] = block
configure = admin/dashboard/customize
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/dblog/dblog.info b/www7/modules/dblog/dblog.info
index 26e173710..cbc892687 100644
--- a/www7/modules/dblog/dblog.info
+++ b/www7/modules/dblog/dblog.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = dblog.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/field.info b/www7/modules/field/field.info
index 2228c0591..5a60e62ae 100644
--- a/www7/modules/field/field.info
+++ b/www7/modules/field/field.info
@@ -11,7 +11,7 @@ dependencies[] = field_sql_storage
required = TRUE
stylesheets[all][] = theme/field.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/field_sql_storage/field_sql_storage.info b/www7/modules/field/modules/field_sql_storage/field_sql_storage.info
index e43fe820f..ecf448ea6 100644
--- a/www7/modules/field/modules/field_sql_storage/field_sql_storage.info
+++ b/www7/modules/field/modules/field_sql_storage/field_sql_storage.info
@@ -7,7 +7,7 @@ dependencies[] = field
files[] = field_sql_storage.test
required = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/list/list.info b/www7/modules/field/modules/list/list.info
index 851292eb0..433bb72f8 100644
--- a/www7/modules/field/modules/list/list.info
+++ b/www7/modules/field/modules/list/list.info
@@ -7,7 +7,7 @@ dependencies[] = field
dependencies[] = options
files[] = tests/list.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/list/tests/list_test.info b/www7/modules/field/modules/list/tests/list_test.info
index 9a8e792ec..f1a251179 100644
--- a/www7/modules/field/modules/list/tests/list_test.info
+++ b/www7/modules/field/modules/list/tests/list_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/number/number.info b/www7/modules/field/modules/number/number.info
index a7853d595..18b595b1a 100644
--- a/www7/modules/field/modules/number/number.info
+++ b/www7/modules/field/modules/number/number.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = field
files[] = number.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/number/number.test b/www7/modules/field/modules/number/number.test
index 839da36c3..db225855b 100644
--- a/www7/modules/field/modules/number/number.test
+++ b/www7/modules/field/modules/number/number.test
@@ -69,7 +69,7 @@ class NumberFieldTestCase extends DrupalWebTestCase {
preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
- $this->assertRaw(round($value, 2), 'Value is displayed.');
+ $this->assertRaw($value, 'Value is displayed.');
// Try to create entries with more than one decimal separator; assert fail.
$wrong_entries = array(
diff --git a/www7/modules/field/modules/options/options.info b/www7/modules/field/modules/options/options.info
index 77b1359f8..b55064304 100644
--- a/www7/modules/field/modules/options/options.info
+++ b/www7/modules/field/modules/options/options.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = field
files[] = options.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/modules/text/text.info b/www7/modules/field/modules/text/text.info
index 39881eb18..1627800bc 100644
--- a/www7/modules/field/modules/text/text.info
+++ b/www7/modules/field/modules/text/text.info
@@ -7,7 +7,7 @@ dependencies[] = field
files[] = text.test
required = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field/tests/field_test.info b/www7/modules/field/tests/field_test.info
index e0f42e987..a74f7b1d3 100644
--- a/www7/modules/field/tests/field_test.info
+++ b/www7/modules/field/tests/field_test.info
@@ -6,7 +6,7 @@ files[] = field_test.entity.inc
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/field_ui/field_ui.info b/www7/modules/field_ui/field_ui.info
index d7564f5a4..b44f1c96a 100644
--- a/www7/modules/field_ui/field_ui.info
+++ b/www7/modules/field_ui/field_ui.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = field
files[] = field_ui.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/file/file.field.inc b/www7/modules/file/file.field.inc
index d592381bd..fc1a1df20 100644
--- a/www7/modules/file/file.field.inc
+++ b/www7/modules/file/file.field.inc
@@ -599,7 +599,7 @@ function file_field_widget_value($element, $input = FALSE, $form_state) {
// If the display field is present make sure its unchecked value is saved.
$field = field_widget_field($element, $form_state);
if (empty($input['display'])) {
- $input['display'] = $field['settings']['display_field'] ? 0 : 1;
+ $input['display'] = !empty($field['settings']['display_field']) ? 0 : 1;
}
}
diff --git a/www7/modules/file/file.info b/www7/modules/file/file.info
index f2d0872fd..220bae2ae 100644
--- a/www7/modules/file/file.info
+++ b/www7/modules/file/file.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = field
files[] = tests/file.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/file/tests/file.test b/www7/modules/file/tests/file.test
index f764a9033..849451a55 100644
--- a/www7/modules/file/tests/file.test
+++ b/www7/modules/file/tests/file.test
@@ -1875,3 +1875,60 @@ class FileFieldAnonymousSubmission extends FileFieldTestCase {
}
}
+
+/**
+ * Tests the file_scan_directory() function.
+ */
+class FileScanDirectory extends FileFieldTestCase {
+
+ /**
+ * @var string
+ */
+ protected $path;
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => 'File ScanDirectory',
+ 'description' => 'Tests the file_scan_directory() function.',
+ 'group' => 'File',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function setUp() {
+ parent::setUp();
+
+ $this->path = 'modules/file/tests/fixtures/file_scan_ignore';
+ }
+
+ /**
+ * Tests file_scan_directory() obeys 'file_scan_ignore_directories' setting.
+ * If nomask is not passed as argument, it should use the default settings.
+ * If nomask is passed as argument, it should obey this rule.
+ */
+ public function testNoMask() {
+ $files = file_scan_directory($this->path, '/\.txt$/');
+ $this->assertEqual(3, count($files), '3 text files found when not ignoring directories.');
+
+ global $conf;
+ $conf['file_scan_ignore_directories'] = array('frontend_framework');
+
+ $files = file_scan_directory($this->path, '/\.txt$/');
+ $this->assertEqual(1, count($files), '1 text files found when ignoring directories called "frontend_framework".');
+
+ // Make that directories specified by default still work when a new nomask is provided.
+ $files = file_scan_directory($this->path, '/\.txt$/', array('nomask' => '/^c.txt/'));
+ $this->assertEqual(2, count($files), '2 text files found when an "nomask" option is passed in.');
+
+ // Ensure that the directories in file_scan_ignore_directories are escaped using preg_quote.
+ $conf['file_scan_ignore_directories'] = array('frontend.*');
+ $files = file_scan_directory($this->path, '/\.txt$/');
+ $this->assertEqual(3, count($files), '2 text files found when ignoring a directory that is not there.');
+ }
+
+}
diff --git a/www7/modules/file/tests/file_module_test.info b/www7/modules/file/tests/file_module_test.info
index a8b4acc9d..5bad5c83d 100644
--- a/www7/modules/file/tests/file_module_test.info
+++ b/www7/modules/file/tests/file_module_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/file/tests/fixtures/file_scan_ignore/a.txt b/www7/modules/file/tests/fixtures/file_scan_ignore/a.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/www7/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/b.txt b/www7/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/b.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/www7/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/c.txt b/www7/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/c.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/www7/modules/filter/filter.info b/www7/modules/filter/filter.info
index f16777f81..3133b03a9 100644
--- a/www7/modules/filter/filter.info
+++ b/www7/modules/filter/filter.info
@@ -7,7 +7,7 @@ files[] = filter.test
required = TRUE
configure = admin/config/content/formats
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/forum/forum.info b/www7/modules/forum/forum.info
index 758f35b23..d389c244a 100644
--- a/www7/modules/forum/forum.info
+++ b/www7/modules/forum/forum.info
@@ -9,7 +9,7 @@ files[] = forum.test
configure = admin/structure/forum
stylesheets[all][] = forum.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/help/help.info b/www7/modules/help/help.info
index 46ee825cd..18f1cd342 100644
--- a/www7/modules/help/help.info
+++ b/www7/modules/help/help.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = help.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/image/image.info b/www7/modules/image/image.info
index 7903f2c25..b2940584d 100644
--- a/www7/modules/image/image.info
+++ b/www7/modules/image/image.info
@@ -7,7 +7,7 @@ dependencies[] = file
files[] = image.test
configure = admin/config/media/image-styles
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/image/tests/image_module_test.info b/www7/modules/image/tests/image_module_test.info
index 124b6996b..57d065efb 100644
--- a/www7/modules/image/tests/image_module_test.info
+++ b/www7/modules/image/tests/image_module_test.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = image_module_test.module
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/locale/locale.info b/www7/modules/locale/locale.info
index fb257d1aa..f295d8890 100644
--- a/www7/modules/locale/locale.info
+++ b/www7/modules/locale/locale.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = locale.test
configure = admin/config/regional/language
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/locale/tests/locale_test.info b/www7/modules/locale/tests/locale_test.info
index 5727160f2..15f49ec88 100644
--- a/www7/modules/locale/tests/locale_test.info
+++ b/www7/modules/locale/tests/locale_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/menu/menu.info b/www7/modules/menu/menu.info
index 52b127b6f..b24f2966c 100644
--- a/www7/modules/menu/menu.info
+++ b/www7/modules/menu/menu.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = menu.test
configure = admin/structure/menu
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/node/node.info b/www7/modules/node/node.info
index 91e552477..e802aa682 100644
--- a/www7/modules/node/node.info
+++ b/www7/modules/node/node.info
@@ -9,7 +9,7 @@ required = TRUE
configure = admin/structure/types
stylesheets[all][] = node.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/node/tests/node_access_test.info b/www7/modules/node/tests/node_access_test.info
index b4c70c84c..c78209ad4 100644
--- a/www7/modules/node/tests/node_access_test.info
+++ b/www7/modules/node/tests/node_access_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/node/tests/node_test.info b/www7/modules/node/tests/node_test.info
index 162dca0e4..c12a8c154 100644
--- a/www7/modules/node/tests/node_test.info
+++ b/www7/modules/node/tests/node_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/node/tests/node_test_exception.info b/www7/modules/node/tests/node_test_exception.info
index 80032910e..a23c4c7ca 100644
--- a/www7/modules/node/tests/node_test_exception.info
+++ b/www7/modules/node/tests/node_test_exception.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/openid/openid.info b/www7/modules/openid/openid.info
index c6b932514..5e630f9cc 100644
--- a/www7/modules/openid/openid.info
+++ b/www7/modules/openid/openid.info
@@ -5,7 +5,7 @@ package = Core
core = 7.x
files[] = openid.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/openid/tests/openid_test.info b/www7/modules/openid/tests/openid_test.info
index 5f06fc28e..f7ea5dca3 100644
--- a/www7/modules/openid/tests/openid_test.info
+++ b/www7/modules/openid/tests/openid_test.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = openid
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/overlay/overlay.info b/www7/modules/overlay/overlay.info
index d8f9cf62f..00a167bc5 100644
--- a/www7/modules/overlay/overlay.info
+++ b/www7/modules/overlay/overlay.info
@@ -4,7 +4,7 @@ package = Core
version = VERSION
core = 7.x
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/path/path.info b/www7/modules/path/path.info
index 1878b27df..40fb7ea35 100644
--- a/www7/modules/path/path.info
+++ b/www7/modules/path/path.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = path.test
configure = admin/config/search/path
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/php/php.info b/www7/modules/php/php.info
index 8f64cf09a..256116e9b 100644
--- a/www7/modules/php/php.info
+++ b/www7/modules/php/php.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = php.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/poll/poll.info b/www7/modules/poll/poll.info
index 630ba42a1..7224eadcb 100644
--- a/www7/modules/poll/poll.info
+++ b/www7/modules/poll/poll.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = poll.test
stylesheets[all][] = poll.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/profile/profile.info b/www7/modules/profile/profile.info
index 7d1e79147..907b1b0a8 100644
--- a/www7/modules/profile/profile.info
+++ b/www7/modules/profile/profile.info
@@ -11,7 +11,7 @@ configure = admin/config/people/profile
; See user_system_info_alter().
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/rdf/rdf.info b/www7/modules/rdf/rdf.info
index ee1d9c828..5ae8c6569 100644
--- a/www7/modules/rdf/rdf.info
+++ b/www7/modules/rdf/rdf.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
files[] = rdf.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/rdf/tests/rdf_test.info b/www7/modules/rdf/tests/rdf_test.info
index 063514f73..c95e12da9 100644
--- a/www7/modules/rdf/tests/rdf_test.info
+++ b/www7/modules/rdf/tests/rdf_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = blog
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/search/search.info b/www7/modules/search/search.info
index 4806cb8f3..5478e5b96 100644
--- a/www7/modules/search/search.info
+++ b/www7/modules/search/search.info
@@ -8,7 +8,7 @@ files[] = search.test
configure = admin/config/search/settings
stylesheets[all][] = search.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/search/tests/search_embedded_form.info b/www7/modules/search/tests/search_embedded_form.info
index a16393ff2..bc8e49cd5 100644
--- a/www7/modules/search/tests/search_embedded_form.info
+++ b/www7/modules/search/tests/search_embedded_form.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/search/tests/search_extra_type.info b/www7/modules/search/tests/search_extra_type.info
index 85d76cc17..85e45dfb5 100644
--- a/www7/modules/search/tests/search_extra_type.info
+++ b/www7/modules/search/tests/search_extra_type.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/search/tests/search_node_tags.info b/www7/modules/search/tests/search_node_tags.info
index 5f0f84d6c..a62e6f1cf 100644
--- a/www7/modules/search/tests/search_node_tags.info
+++ b/www7/modules/search/tests/search_node_tags.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/shortcut/shortcut.info b/www7/modules/shortcut/shortcut.info
index a8bcc2681..69c95d1b1 100644
--- a/www7/modules/shortcut/shortcut.info
+++ b/www7/modules/shortcut/shortcut.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = shortcut.test
configure = admin/config/user-interface/shortcut
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/drupal_web_test_case.php b/www7/modules/simpletest/drupal_web_test_case.php
index 3124ffe82..a0872c234 100644
--- a/www7/modules/simpletest/drupal_web_test_case.php
+++ b/www7/modules/simpletest/drupal_web_test_case.php
@@ -3012,7 +3012,7 @@ protected function assertRaw($raw, $message = '', $group = 'Other') {
if (!$message) {
$message = t('Raw "@raw" found', array('@raw' => $raw));
}
- return $this->assert(strpos($this->drupalGetContent(), $raw) !== FALSE, $message, $group);
+ return $this->assert(strpos($this->drupalGetContent(), (string) $raw) !== FALSE, $message, $group);
}
/**
@@ -3032,7 +3032,7 @@ protected function assertNoRaw($raw, $message = '', $group = 'Other') {
if (!$message) {
$message = t('Raw "@raw" not found', array('@raw' => $raw));
}
- return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
+ return $this->assert(strpos($this->drupalGetContent(), (string) $raw) === FALSE, $message, $group);
}
/**
diff --git a/www7/modules/simpletest/simpletest.info b/www7/modules/simpletest/simpletest.info
index 7190c6764..783ace447 100644
--- a/www7/modules/simpletest/simpletest.info
+++ b/www7/modules/simpletest/simpletest.info
@@ -57,7 +57,7 @@ files[] = tests/upgrade/update.trigger.test
files[] = tests/upgrade/update.field.test
files[] = tests/upgrade/update.user.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/actions_loop_test.info b/www7/modules/simpletest/tests/actions_loop_test.info
index a7939735b..25db0c71a 100644
--- a/www7/modules/simpletest/tests/actions_loop_test.info
+++ b/www7/modules/simpletest/tests/actions_loop_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/ajax_forms_test.info b/www7/modules/simpletest/tests/ajax_forms_test.info
index d802f30c3..56e2f1a91 100644
--- a/www7/modules/simpletest/tests/ajax_forms_test.info
+++ b/www7/modules/simpletest/tests/ajax_forms_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/ajax_test.info b/www7/modules/simpletest/tests/ajax_test.info
index 6ecc1ca0f..39cf716d9 100644
--- a/www7/modules/simpletest/tests/ajax_test.info
+++ b/www7/modules/simpletest/tests/ajax_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/batch_test.info b/www7/modules/simpletest/tests/batch_test.info
index 579ca641a..ef335ad42 100644
--- a/www7/modules/simpletest/tests/batch_test.info
+++ b/www7/modules/simpletest/tests/batch_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/boot_test_1.info b/www7/modules/simpletest/tests/boot_test_1.info
index b46d19f6b..139fe8f09 100644
--- a/www7/modules/simpletest/tests/boot_test_1.info
+++ b/www7/modules/simpletest/tests/boot_test_1.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/boot_test_2.info b/www7/modules/simpletest/tests/boot_test_2.info
index c2d6f8ced..7e38cc274 100644
--- a/www7/modules/simpletest/tests/boot_test_2.info
+++ b/www7/modules/simpletest/tests/boot_test_2.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/bootstrap.test b/www7/modules/simpletest/tests/bootstrap.test
index 16ac1714f..effd04bf2 100644
--- a/www7/modules/simpletest/tests/bootstrap.test
+++ b/www7/modules/simpletest/tests/bootstrap.test
@@ -729,16 +729,12 @@ class BootstrapMiscTestCase extends DrupalUnitTestCase {
* Tests that the drupal_check_memory_limit() function works as expected.
*/
function testCheckMemoryLimit() {
- $memory_limit = ini_get('memory_limit');
// Test that a very reasonable amount of memory is available.
$this->assertTrue(drupal_check_memory_limit('30MB'), '30MB of memory tested available.');
- // Get the available memory and multiply it by two to make it unreasonably
- // high.
- $twice_avail_memory = ($memory_limit * 2) . 'MB';
-
+ // Test an unlimited memory limit.
// The function should always return true if the memory limit is set to -1.
- $this->assertTrue(drupal_check_memory_limit($twice_avail_memory, -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied');
+ $this->assertTrue(drupal_check_memory_limit('9999999999YB', -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied');
// Test that even though we have 30MB of memory available - the function
// returns FALSE when given an upper limit for how much memory can be used.
diff --git a/www7/modules/simpletest/tests/common_test.info b/www7/modules/simpletest/tests/common_test.info
index 21e565d01..79f8badde 100644
--- a/www7/modules/simpletest/tests/common_test.info
+++ b/www7/modules/simpletest/tests/common_test.info
@@ -7,7 +7,7 @@ stylesheets[all][] = common_test.css
stylesheets[print][] = common_test.print.css
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/common_test_cron_helper.info b/www7/modules/simpletest/tests/common_test_cron_helper.info
index cfe45113e..cf545fa05 100644
--- a/www7/modules/simpletest/tests/common_test_cron_helper.info
+++ b/www7/modules/simpletest/tests/common_test_cron_helper.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/database_test.info b/www7/modules/simpletest/tests/database_test.info
index a88282371..2862e6a60 100644
--- a/www7/modules/simpletest/tests/database_test.info
+++ b/www7/modules/simpletest/tests/database_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info b/www7/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info
index 766405496..da7721609 100644
--- a/www7/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info
+++ b/www7/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info
@@ -7,7 +7,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/www7/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
index d1f3545e4..a5697a704 100644
--- a/www7/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
+++ b/www7/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/www7/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
index 061a14376..4897bbd2f 100644
--- a/www7/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
+++ b/www7/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/entity_cache_test.info b/www7/modules/simpletest/tests/entity_cache_test.info
index 7f52e24b6..3f7211a6a 100644
--- a/www7/modules/simpletest/tests/entity_cache_test.info
+++ b/www7/modules/simpletest/tests/entity_cache_test.info
@@ -6,7 +6,7 @@ core = 7.x
dependencies[] = entity_cache_test_dependency
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/entity_cache_test_dependency.info b/www7/modules/simpletest/tests/entity_cache_test_dependency.info
index 5dc9a367d..8710673f0 100644
--- a/www7/modules/simpletest/tests/entity_cache_test_dependency.info
+++ b/www7/modules/simpletest/tests/entity_cache_test_dependency.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/entity_crud_hook_test.info b/www7/modules/simpletest/tests/entity_crud_hook_test.info
index edc4d5ca4..f2a6b50f8 100644
--- a/www7/modules/simpletest/tests/entity_crud_hook_test.info
+++ b/www7/modules/simpletest/tests/entity_crud_hook_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/entity_query_access_test.info b/www7/modules/simpletest/tests/entity_query_access_test.info
index 21d13156f..dd1fd0f0e 100644
--- a/www7/modules/simpletest/tests/entity_query_access_test.info
+++ b/www7/modules/simpletest/tests/entity_query_access_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/error_test.info b/www7/modules/simpletest/tests/error_test.info
index c7fe885ee..40048ccbe 100644
--- a/www7/modules/simpletest/tests/error_test.info
+++ b/www7/modules/simpletest/tests/error_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/file.test b/www7/modules/simpletest/tests/file.test
index 55dd1906e..032f2cbac 100644
--- a/www7/modules/simpletest/tests/file.test
+++ b/www7/modules/simpletest/tests/file.test
@@ -957,6 +957,15 @@ class FileDirectoryTest extends FileTestCase {
$path = file_create_filename($basename, $directory);
$this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new.', array('%new' => $path, '%original' => $original)), 'File');
+ try {
+ $filename = "a\xFFtest\x80€.txt";
+ file_create_filename($filename, $directory);
+ $this->fail('Expected exception not thrown');
+ }
+ catch (RuntimeException $e) {
+ $this->assertEqual("Invalid filename '$filename'", $e->getMessage());
+ }
+
// @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix.
}
@@ -989,6 +998,14 @@ class FileDirectoryTest extends FileTestCase {
$this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME.', 'File');
$path = file_destination($destination, FILE_EXISTS_ERROR);
$this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FILE_EXISTS_ERROR.', 'File');
+
+ try {
+ file_destination("core/misc/a\xFFtest\x80€.txt", FILE_EXISTS_REPLACE);
+ $this->fail('Expected exception not thrown');
+ }
+ catch (RuntimeException $e) {
+ $this->assertEqual("Invalid filename 'a\xFFtest\x80€.txt'", $e->getMessage());
+ }
}
/**
diff --git a/www7/modules/simpletest/tests/file_test.info b/www7/modules/simpletest/tests/file_test.info
index d73960ce7..849fcb316 100644
--- a/www7/modules/simpletest/tests/file_test.info
+++ b/www7/modules/simpletest/tests/file_test.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = file_test.module
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/filter_test.info b/www7/modules/simpletest/tests/filter_test.info
index 6433ddd3a..3b847858b 100644
--- a/www7/modules/simpletest/tests/filter_test.info
+++ b/www7/modules/simpletest/tests/filter_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/form_test.info b/www7/modules/simpletest/tests/form_test.info
index a2657115f..350ce2595 100644
--- a/www7/modules/simpletest/tests/form_test.info
+++ b/www7/modules/simpletest/tests/form_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/image_test.info b/www7/modules/simpletest/tests/image_test.info
index cc14c8f94..5724949e5 100644
--- a/www7/modules/simpletest/tests/image_test.info
+++ b/www7/modules/simpletest/tests/image_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/menu_test.info b/www7/modules/simpletest/tests/menu_test.info
index c61864d13..717c52580 100644
--- a/www7/modules/simpletest/tests/menu_test.info
+++ b/www7/modules/simpletest/tests/menu_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/module_test.info b/www7/modules/simpletest/tests/module_test.info
index bdf17ea1c..c985a0412 100644
--- a/www7/modules/simpletest/tests/module_test.info
+++ b/www7/modules/simpletest/tests/module_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/path_test.info b/www7/modules/simpletest/tests/path_test.info
index 4f177d4de..259063967 100644
--- a/www7/modules/simpletest/tests/path_test.info
+++ b/www7/modules/simpletest/tests/path_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/psr_0_test/psr_0_test.info b/www7/modules/simpletest/tests/psr_0_test/psr_0_test.info
index 3d01fab31..5d83fcb27 100644
--- a/www7/modules/simpletest/tests/psr_0_test/psr_0_test.info
+++ b/www7/modules/simpletest/tests/psr_0_test/psr_0_test.info
@@ -5,7 +5,7 @@ core = 7.x
hidden = TRUE
package = Testing
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/psr_4_test/psr_4_test.info b/www7/modules/simpletest/tests/psr_4_test/psr_4_test.info
index 0619a2430..ac574e151 100644
--- a/www7/modules/simpletest/tests/psr_4_test/psr_4_test.info
+++ b/www7/modules/simpletest/tests/psr_4_test/psr_4_test.info
@@ -5,7 +5,7 @@ core = 7.x
hidden = TRUE
package = Testing
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/requirements1_test.info b/www7/modules/simpletest/tests/requirements1_test.info
index 783326cf3..2901a6bad 100644
--- a/www7/modules/simpletest/tests/requirements1_test.info
+++ b/www7/modules/simpletest/tests/requirements1_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/requirements2_test.info b/www7/modules/simpletest/tests/requirements2_test.info
index 8312c3a24..8c03a0cc8 100644
--- a/www7/modules/simpletest/tests/requirements2_test.info
+++ b/www7/modules/simpletest/tests/requirements2_test.info
@@ -7,7 +7,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/session_test.info b/www7/modules/simpletest/tests/session_test.info
index 8bf277cfc..37f353849 100644
--- a/www7/modules/simpletest/tests/session_test.info
+++ b/www7/modules/simpletest/tests/session_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_dependencies_test.info b/www7/modules/simpletest/tests/system_dependencies_test.info
index 2a82092ac..de4b98122 100644
--- a/www7/modules/simpletest/tests/system_dependencies_test.info
+++ b/www7/modules/simpletest/tests/system_dependencies_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = _missing_dependency
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info b/www7/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info
index a385a05ac..e0bd91bd9 100644
--- a/www7/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info
+++ b/www7/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = system_incompatible_core_version_test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_incompatible_core_version_test.info b/www7/modules/simpletest/tests/system_incompatible_core_version_test.info
index e12847471..6afe2e4fa 100644
--- a/www7/modules/simpletest/tests/system_incompatible_core_version_test.info
+++ b/www7/modules/simpletest/tests/system_incompatible_core_version_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 5.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info b/www7/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info
index 29bd5445c..a12a356cb 100644
--- a/www7/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info
+++ b/www7/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info
@@ -7,7 +7,7 @@ hidden = TRUE
; system_incompatible_module_version_test declares version 1.0
dependencies[] = system_incompatible_module_version_test (>2.0)
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_incompatible_module_version_test.info b/www7/modules/simpletest/tests/system_incompatible_module_version_test.info
index 7383a2796..028183805 100644
--- a/www7/modules/simpletest/tests/system_incompatible_module_version_test.info
+++ b/www7/modules/simpletest/tests/system_incompatible_module_version_test.info
@@ -5,7 +5,7 @@ version = 1.0
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_project_namespace_test.info b/www7/modules/simpletest/tests/system_project_namespace_test.info
index 9bc711dc2..136c6b6ad 100644
--- a/www7/modules/simpletest/tests/system_project_namespace_test.info
+++ b/www7/modules/simpletest/tests/system_project_namespace_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = drupal:filter
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/system_test.info b/www7/modules/simpletest/tests/system_test.info
index 5e78b89b4..b66b34b8f 100644
--- a/www7/modules/simpletest/tests/system_test.info
+++ b/www7/modules/simpletest/tests/system_test.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = system_test.module
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/taxonomy_test.info b/www7/modules/simpletest/tests/taxonomy_test.info
index 59f714229..09893faa6 100644
--- a/www7/modules/simpletest/tests/taxonomy_test.info
+++ b/www7/modules/simpletest/tests/taxonomy_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = taxonomy
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/theme_test.info b/www7/modules/simpletest/tests/theme_test.info
index c810edcb2..31faf08cd 100644
--- a/www7/modules/simpletest/tests/theme_test.info
+++ b/www7/modules/simpletest/tests/theme_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/www7/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
index cab073b5a..e3cac6c30 100644
--- a/www7/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
+++ b/www7/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
@@ -6,7 +6,7 @@ hidden = TRUE
settings[basetheme_only] = base theme value
settings[subtheme_override] = base theme value
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/www7/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
index d80c5d0ff..6287d8ed5 100644
--- a/www7/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
+++ b/www7/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
@@ -6,7 +6,7 @@ hidden = TRUE
settings[subtheme_override] = subtheme value
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/themes/test_theme/test_theme.info b/www7/modules/simpletest/tests/themes/test_theme/test_theme.info
index a0e0dd68f..04324c809 100644
--- a/www7/modules/simpletest/tests/themes/test_theme/test_theme.info
+++ b/www7/modules/simpletest/tests/themes/test_theme/test_theme.info
@@ -17,7 +17,7 @@ stylesheets[all][] = system.base.css
settings[theme_test_setting] = default value
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info b/www7/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info
index 49513572f..2276ea896 100644
--- a/www7/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info
+++ b/www7/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info
@@ -4,7 +4,7 @@ core = 7.x
hidden = TRUE
engine = nyan_cat
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/update_script_test.info b/www7/modules/simpletest/tests/update_script_test.info
index ea7b5065f..839b054e5 100644
--- a/www7/modules/simpletest/tests/update_script_test.info
+++ b/www7/modules/simpletest/tests/update_script_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/update_test_1.info b/www7/modules/simpletest/tests/update_test_1.info
index 3e3b36f65..5ed289208 100644
--- a/www7/modules/simpletest/tests/update_test_1.info
+++ b/www7/modules/simpletest/tests/update_test_1.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/update_test_2.info b/www7/modules/simpletest/tests/update_test_2.info
index 3e3b36f65..5ed289208 100644
--- a/www7/modules/simpletest/tests/update_test_2.info
+++ b/www7/modules/simpletest/tests/update_test_2.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/update_test_3.info b/www7/modules/simpletest/tests/update_test_3.info
index 3e3b36f65..5ed289208 100644
--- a/www7/modules/simpletest/tests/update_test_3.info
+++ b/www7/modules/simpletest/tests/update_test_3.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/url_alter_test.info b/www7/modules/simpletest/tests/url_alter_test.info
index 36d1ef401..0d55fbf0b 100644
--- a/www7/modules/simpletest/tests/url_alter_test.info
+++ b/www7/modules/simpletest/tests/url_alter_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/simpletest/tests/xmlrpc_test.info b/www7/modules/simpletest/tests/xmlrpc_test.info
index 2c6d90cc3..488bc50bd 100644
--- a/www7/modules/simpletest/tests/xmlrpc_test.info
+++ b/www7/modules/simpletest/tests/xmlrpc_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/statistics/statistics.info b/www7/modules/statistics/statistics.info
index 617ada790..f078b4143 100644
--- a/www7/modules/statistics/statistics.info
+++ b/www7/modules/statistics/statistics.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = statistics.test
configure = admin/config/system/statistics
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/syslog/syslog.info b/www7/modules/syslog/syslog.info
index 0814a3983..28197ac3e 100644
--- a/www7/modules/syslog/syslog.info
+++ b/www7/modules/syslog/syslog.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = syslog.test
configure = admin/config/development/logging
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/system/system.info b/www7/modules/system/system.info
index dfaf47fef..74c8fa4aa 100644
--- a/www7/modules/system/system.info
+++ b/www7/modules/system/system.info
@@ -12,7 +12,7 @@ files[] = system.test
required = TRUE
configure = admin/config/system
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/system/system.install b/www7/modules/system/system.install
index d5e67435d..3bb07d955 100644
--- a/www7/modules/system/system.install
+++ b/www7/modules/system/system.install
@@ -2870,7 +2870,7 @@ function system_update_7061(&$sandbox) {
if (!db_table_exists('system_update_7061')) {
$table = array(
'description' => t('Stores temporary data for system_update_7061.'),
- 'fields' => array('vid' => array('type' => 'int')),
+ 'fields' => array('vid' => array('type' => 'int', 'not null' => TRUE)),
'primary key' => array('vid'),
);
db_create_table('system_update_7061', $table);
@@ -3285,6 +3285,13 @@ function system_update_7081() {
->execute();
}
+/**
+ * Add 'jquery-extend-3.4.0.js' to the 'jquery' library.
+ */
+function system_update_7082() {
+ // Empty update to force a rebuild of hook_library() and JS aggregates.
+}
+
/**
* @} End of "defgroup updates-7.x-extra".
* The next series of updates should start at 8000.
diff --git a/www7/modules/system/system.module b/www7/modules/system/system.module
index 53844d878..4ce6b9b99 100644
--- a/www7/modules/system/system.module
+++ b/www7/modules/system/system.module
@@ -1182,6 +1182,9 @@ function system_library() {
'version' => '1.4.4',
'js' => array(
'misc/jquery.js' => array('group' => JS_LIBRARY, 'weight' => -20),
+ // This includes a security fix, so assign a weight that makes this load
+ // as soon after jquery.js is loaded as possible.
+ 'misc/jquery-extend-3.4.0.js' => array('group' => JS_LIBRARY, 'weight' => -19),
),
);
diff --git a/www7/modules/system/tests/cron_queue_test.info b/www7/modules/system/tests/cron_queue_test.info
index d574d64dc..f43ee03a8 100644
--- a/www7/modules/system/tests/cron_queue_test.info
+++ b/www7/modules/system/tests/cron_queue_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/system/tests/system_cron_test.info b/www7/modules/system/tests/system_cron_test.info
index d57b6043a..086825f49 100644
--- a/www7/modules/system/tests/system_cron_test.info
+++ b/www7/modules/system/tests/system_cron_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/taxonomy/taxonomy.info b/www7/modules/taxonomy/taxonomy.info
index 34e21b910..28a287ec8 100644
--- a/www7/modules/taxonomy/taxonomy.info
+++ b/www7/modules/taxonomy/taxonomy.info
@@ -8,7 +8,7 @@ files[] = taxonomy.module
files[] = taxonomy.test
configure = admin/structure/taxonomy
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/toolbar/toolbar.info b/www7/modules/toolbar/toolbar.info
index 55f8c5cfc..0fb05069e 100644
--- a/www7/modules/toolbar/toolbar.info
+++ b/www7/modules/toolbar/toolbar.info
@@ -4,7 +4,7 @@ core = 7.x
package = Core
version = VERSION
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/tracker/tracker.info b/www7/modules/tracker/tracker.info
index 098696228..867aa592b 100644
--- a/www7/modules/tracker/tracker.info
+++ b/www7/modules/tracker/tracker.info
@@ -6,7 +6,7 @@ version = VERSION
core = 7.x
files[] = tracker.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/translation/tests/translation_test.info b/www7/modules/translation/tests/translation_test.info
index a4e0bd281..1efe113d9 100644
--- a/www7/modules/translation/tests/translation_test.info
+++ b/www7/modules/translation/tests/translation_test.info
@@ -5,7 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/translation/translation.info b/www7/modules/translation/translation.info
index cab857c4b..7184e9909 100644
--- a/www7/modules/translation/translation.info
+++ b/www7/modules/translation/translation.info
@@ -6,7 +6,7 @@ version = VERSION
core = 7.x
files[] = translation.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/trigger/tests/trigger_test.info b/www7/modules/trigger/tests/trigger_test.info
index b49b6e984..bf83fa084 100644
--- a/www7/modules/trigger/tests/trigger_test.info
+++ b/www7/modules/trigger/tests/trigger_test.info
@@ -4,7 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/trigger/trigger.info b/www7/modules/trigger/trigger.info
index 4baee27e3..92e6fc83c 100644
--- a/www7/modules/trigger/trigger.info
+++ b/www7/modules/trigger/trigger.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = trigger.test
configure = admin/structure/trigger
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/aaa_update_test.info b/www7/modules/update/tests/aaa_update_test.info
index e39841306..3d8718ac9 100644
--- a/www7/modules/update/tests/aaa_update_test.info
+++ b/www7/modules/update/tests/aaa_update_test.info
@@ -4,7 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/bbb_update_test.info b/www7/modules/update/tests/bbb_update_test.info
index bf0ea54bd..9916b5048 100644
--- a/www7/modules/update/tests/bbb_update_test.info
+++ b/www7/modules/update/tests/bbb_update_test.info
@@ -4,7 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/ccc_update_test.info b/www7/modules/update/tests/ccc_update_test.info
index a541d0def..b80db4dbd 100644
--- a/www7/modules/update/tests/ccc_update_test.info
+++ b/www7/modules/update/tests/ccc_update_test.info
@@ -4,7 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info b/www7/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info
index c6507858f..f3bf0a622 100644
--- a/www7/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info
+++ b/www7/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info
@@ -3,7 +3,7 @@ description = Test theme which is used as admin theme.
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/www7/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
index 4f1bb1251..27ca277d3 100644
--- a/www7/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
+++ b/www7/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
@@ -3,7 +3,7 @@ description = Test theme which acts as a base theme for other test subthemes.
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/www7/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
index b3d8ba9d3..9184b5c56 100644
--- a/www7/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
+++ b/www7/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
@@ -4,7 +4,7 @@ core = 7.x
base theme = update_test_basetheme
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/tests/update_test.info b/www7/modules/update/tests/update_test.info
index 4a0ab86a9..6b6a9f7b8 100644
--- a/www7/modules/update/tests/update_test.info
+++ b/www7/modules/update/tests/update_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/update/update.info b/www7/modules/update/update.info
index 0f591346f..9c49f6dcd 100644
--- a/www7/modules/update/update.info
+++ b/www7/modules/update/update.info
@@ -6,7 +6,7 @@ core = 7.x
files[] = update.test
configure = admin/reports/updates/settings
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/user/tests/user_form_test.info b/www7/modules/user/tests/user_form_test.info
index 0526ab2b7..a761b4e4e 100644
--- a/www7/modules/user/tests/user_form_test.info
+++ b/www7/modules/user/tests/user_form_test.info
@@ -5,7 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/modules/user/user.info b/www7/modules/user/user.info
index 6c132a38b..e23c49137 100644
--- a/www7/modules/user/user.info
+++ b/www7/modules/user/user.info
@@ -9,7 +9,7 @@ required = TRUE
configure = admin/config/people
stylesheets[all][] = user.css
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/profiles/minimal/minimal.info b/www7/profiles/minimal/minimal.info
index a4d469df4..9a5c04d81 100644
--- a/www7/profiles/minimal/minimal.info
+++ b/www7/profiles/minimal/minimal.info
@@ -5,7 +5,7 @@ core = 7.x
dependencies[] = block
dependencies[] = dblog
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/profiles/standard/standard.info b/www7/profiles/standard/standard.info
index 9c30220f4..beff9922b 100644
--- a/www7/profiles/standard/standard.info
+++ b/www7/profiles/standard/standard.info
@@ -24,7 +24,7 @@ dependencies[] = field_ui
dependencies[] = file
dependencies[] = rdf
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/www7/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
index 2adcf3dc3..7600c6a30 100644
--- a/www7/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
+++ b/www7/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info
@@ -6,7 +6,7 @@ core = 7.x
hidden = TRUE
files[] = drupal_system_listing_compatible_test.test
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/www7/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
index 8ae9c3fcd..d81c41ded 100644
--- a/www7/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
+++ b/www7/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
@@ -8,7 +8,7 @@ version = VERSION
core = 6.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/profiles/testing/testing.info b/www7/profiles/testing/testing.info
index a8a2c5c98..6646ce611 100644
--- a/www7/profiles/testing/testing.info
+++ b/www7/profiles/testing/testing.info
@@ -4,7 +4,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2019-01-16
-version = "7.63"
+; Information added by Drupal.org packaging script on 2019-05-08
+version = "7.67"
project = "drupal"
-datestamp = "1547681965"
+datestamp = "1557336079"
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.info b/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.info
index 7a8793257..6f50d5a0b 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.info
+++ b/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.info
@@ -10,8 +10,8 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal.test
-; Information added by Drupal.org packaging script on 2018-10-22
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2019-05-06
+version = "7.x-2.7"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1540244884"
+datestamp = "1557130694"
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.module b/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.module
index dad78213f..2a617538f 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.module
+++ b/www7/sites/all/modules/contrib/commerce_paypal/commerce_paypal.module
@@ -488,13 +488,12 @@ function commerce_paypal_reverse_payment_action($payment_action) {
*/
function commerce_paypal_currencies($method_id) {
switch ($method_id) {
- case 'paypal_wpp':
- case 'paypal_ec':
- case 'payflow_link':
- return drupal_map_assoc(array('AUD', 'BRL', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'JPY', 'NOK', 'NZD', 'PLN', 'SEK', 'SGD', 'USD'));
case 'paypal_ppa':
return drupal_map_assoc(array('AUD', 'CAD', 'EUR', 'GBP', 'JPY', 'USD'));
case 'paypal_wps':
+ case 'paypal_wpp':
+ case 'paypal_ec':
+ case 'payflow_link':
return drupal_map_assoc(array('AUD', 'BRL', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'ILS', 'INR', 'JPY', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'TWD', 'USD'));
}
}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/commerce_paypal_checkout.api.php b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/commerce_paypal_checkout.api.php
new file mode 100644
index 000000000..c1ad7eb89
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/commerce_paypal_checkout.api.php
@@ -0,0 +1,32 @@
+ array(
+ 'title' => 'Capture',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('commerce_paypal_checkout_capture_form', 3, 5),
+ 'access callback' => 'commerce_paypal_checkout_capture_void_access',
+ 'access arguments' => array(3, 5),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
+ 'weight' => 2,
+ 'file' => 'includes/commerce_paypal_checkout.admin.inc',
+ ),
+ // Add a menu item for voiding authorizations.
+ 'admin/commerce/orders/%commerce_order/payment/%commerce_payment_transaction/paypal-checkout-void' => array(
+ 'title' => 'Void',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('commerce_paypal_checkout_void_form', 3, 5),
+ 'access callback' => 'commerce_paypal_checkout_capture_void_access',
+ 'access arguments' => array(3, 5),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
+ 'weight' => 4,
+ 'file' => 'includes/commerce_paypal_checkout.admin.inc',
+ ),
+ // Add a menu item for refunding settled transactions.
+ 'admin/commerce/orders/%commerce_order/payment/%commerce_payment_transaction/paypal-checkout-refund' => array(
+ 'title' => 'Refund',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('commerce_paypal_checkout_refund_form', 3, 5),
+ 'access callback' => 'commerce_paypal_checkout_refund_access',
+ 'access arguments' => array(3, 5),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
+ 'weight' => 4,
+ 'file' => 'includes/commerce_paypal_checkout.admin.inc',
+ ),
+ 'commerce-paypal-checkout/create-order/%commerce_order/%commerce_paypal_checkout_method_instance' => array(
+ 'page callback' => 'commerce_paypal_checkout_create_order',
+ 'page arguments' => array(2, 3),
+ 'access callback' => 'commerce_checkout_access',
+ 'access arguments' => array(2),
+ 'type' => MENU_CALLBACK,
+ ),
+ 'commerce-paypal-checkout/approve-order/%commerce_order/%commerce_paypal_checkout_method_instance/%' => array(
+ 'page callback' => 'commerce_paypal_checkout_approve_order',
+ 'page arguments' => array(2, 3, 4),
+ 'access callback' => 'commerce_checkout_access',
+ 'access arguments' => array(2),
+ 'type' => MENU_CALLBACK,
+ ),
+ );
+}
+
+/**
+ * Determines access to the prior authorization capture form or void form for
+ * Paypal Checkout transactions.
+ *
+ * @param $order
+ * The order the transaction is on.
+ * @param $transaction
+ * The payment transaction object to be captured.
+ *
+ * @return
+ * TRUE or FALSE indicating access.
+ */
+function commerce_paypal_checkout_capture_void_access($order, $transaction) {
+ // Return FALSE if the transaction isn't for Paypal Checkout or isn't
+ // awaiting capture.
+ if ($transaction->payment_method != 'paypal_checkout' || strtolower($transaction->remote_status) != 'created') {
+ return FALSE;
+ }
+
+ // Return FALSE if the transaction is not pending.
+ if ($transaction->status != COMMERCE_PAYMENT_STATUS_PENDING) {
+ return FALSE;
+ }
+
+ // Return FALSE if it is more than 29 days past the original authorization.
+ if (REQUEST_TIME - $transaction->created > 86400 * 29) {
+ return FALSE;
+ }
+
+ // Allow access if the user can update payments on this transaction.
+ return commerce_payment_transaction_access('update', $transaction);
+}
+
+/**
+ * Determines access to the refund form for Paypal Checkout transactions.
+ *
+ * @param $order
+ * The order the transaction is on.
+ * @param $transaction
+ * The payment transaction object to be captured.
+ *
+ * @return
+ * TRUE or FALSE indicating access.
+ */
+function commerce_paypal_checkout_refund_access($order, $transaction) {
+ // Return FALSE if the transaction isn't Completed.
+ if ($transaction->payment_method != 'paypal_checkout' || strtolower($transaction->remote_status) != 'completed') {
+ return FALSE;
+ }
+
+ // Return FALSE if the transaction was not a success.
+ if ($transaction->status != COMMERCE_PAYMENT_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ // Return FALSE if it is more than 60 days since the original transaction.
+ if (REQUEST_TIME - $transaction->created > 86400 * 60) {
+ return FALSE;
+ }
+
+ // Allow access if the user can update payments on this transaction.
+ return commerce_payment_transaction_access('update', $transaction);
+}
+
+/**
+ * Load the given PayPal checkout payment method instance.
+ *
+ * @param $rule_name
+ * The enabling's rule name.
+ *
+ * @return
+ * The payment method instance object which is identical to the payment method
+ * object with the addition of the settings array.
+ */
+function commerce_paypal_checkout_method_instance_load($rule_name) {
+ return commerce_payment_method_instance_load("paypal_checkout|$rule_name");
+}
+
+/**
+ * Implements hook_commerce_checkout_page_info().
+ */
+function commerce_paypal_checkout_commerce_checkout_page_info() {
+ $checkout_pages = array();
+
+ $checkout_pages['paypal_checkout'] = array(
+ 'title' => t('Confirm order'),
+ 'help' => t('Confirm your order information and use the button at the bottom of the page to finalize your payment.'),
+ 'status_cart' => FALSE,
+ 'locked' => TRUE,
+ 'buttons' => FALSE,
+ 'weight' => 30,
+ );
+
+ return $checkout_pages;
+}
+
+/**
+ * Implements hook_commerce_checkout_pane_info().
+ */
+function commerce_paypal_checkout_commerce_checkout_pane_info() {
+ $checkout_panes = array();
+
+ $checkout_panes['paypal_checkout_review'] = array(
+ 'title' => t('Review and confirm your order'),
+ 'name' => t('PayPal Checkout review and confirm (only to be used on the confirm order page)'),
+ 'file' => 'includes/commerce_paypal_checkout.checkout_pane.inc',
+ 'base' => 'commerce_paypal_checkout_review_pane',
+ 'page' => 'paypal_checkout',
+ 'fieldset' => FALSE,
+ );
+
+ return $checkout_panes;
+}
+
+/**
+ * Implements hook_commerce_checkout_router().
+ */
+function commerce_paypal_checkout_commerce_checkout_router($order, $checkout_page) {
+ // If the current page is the PayPal Checkout page but the current order did
+ // not use the shortcut Checkout flow...
+ if ($checkout_page['page_id'] == 'paypal_checkout' &&
+ (empty($order->data['commerce_paypal_checkout']['flow']) || $order->data['commerce_paypal_checkout']['flow'] != 'shortcut')) {
+ // Update the order status to the next checkout page.
+ $next_page = $checkout_page['next_page'];
+ $order = commerce_order_status_update($order, 'checkout_' . $next_page, FALSE, FALSE);
+
+ // Inform modules of checkout completion if the next page is Completed.
+ if ($next_page == 'complete') {
+ commerce_checkout_complete($order);
+ }
+
+ // Redirect to the URL for the new checkout page.
+ $target_uri = commerce_checkout_order_uri($order);
+ return drupal_goto($target_uri);
+ }
+}
+
+/**
+ * Returns the checkout pane IDs of checkout panes that should be embedded in
+ * the PayPal Checkout review and confirm page.
+ */
+function commerce_paypal_checkout_embedded_checkout_panes() {
+ return array_filter(variable_get('commerce_paypal_checkout_review_embedded_panes', array()));
+}
+
+/**
+ * Implements hook_commerce_payment_method_info().
+ */
+function commerce_paypal_checkout_commerce_payment_method_info() {
+ $payment_methods = array();
+
+ $payment_methods['paypal_checkout'] = array(
+ 'base' => 'commerce_paypal_checkout',
+ 'title' => t('PayPal Checkout'),
+ 'display_title' => t('PayPal'),
+ 'short_title' => t('PayPal Checkout'),
+ 'description' => t('PayPal Checkout'),
+ 'terminal' => FALSE,
+ 'offsite' => TRUE,
+ 'offsite_autoredirect' => FALSE,
+ );
+
+ return $payment_methods;
+}
+
+/**
+ * Returns the default settings for the PayPal Checkout payment method.
+ */
+function commerce_paypal_checkout_default_settings() {
+ $default_settings = array(
+ 'client_id' => '',
+ 'secret' => '',
+ 'server' => 'sandbox',
+ 'intent' => 'capture',
+ 'disable_funding' => array(),
+ 'disable_card' => array(),
+ 'shipping_preference' => 'get_from_file',
+ 'update_billing_profiles' => TRUE,
+ 'style' => array(),
+ 'enable_on_cart' => TRUE,
+ );
+
+ if (module_exists('commerce_shipping')) {
+ $default_settings['update_shipping_profiles'] = TRUE;
+ }
+
+ return $default_settings;
+}
+
+/**
+ * Payment method callback: settings form.
+ */
+function commerce_paypal_checkout_settings_form($settings = array()) {
+ $form = array();
+
+ // Merge default settings into the stored settings array.
+ $settings = (array) $settings + commerce_paypal_checkout_default_settings();
+ $shipping_module_enabled = module_exists('commerce_shipping');
+
+ $form['client_id'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Client ID'),
+ '#maxlength' => 255,
+ '#default_value' => $settings['client_id'],
+ '#required' => TRUE,
+ );
+ $form['secret'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Secret'),
+ '#maxlength' => 255,
+ '#default_value' => $settings['secret'],
+ '#required' => TRUE,
+ );
+ $form['server'] = array(
+ '#type' => 'radios',
+ '#title' => t('PayPal server'),
+ '#options' => array(
+ 'sandbox' => ('Sandbox - use for testing, requires a PayPal Sandbox account'),
+ 'live' => ('Live - use for processing real transactions'),
+ ),
+ '#default_value' => $settings['server'],
+ );
+ $form['intent'] = array(
+ '#type' => 'radios',
+ '#title' => t('Transaction type'),
+ '#options' => array(
+ 'capture' => t('Capture'),
+ 'authorize' => t('Authorize'),
+ ),
+ '#default_value' => $settings['intent'],
+ );
+ $form['disable_funding'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Disable funding sources'),
+ '#description' => t('The disabled funding sources for the transaction. Any funding sources passed are not displayed in the Smart payment buttons. By default, funding source eligibility is smartly decided based on a variety of factors.'),
+ '#options' => array(
+ 'card' => t('Credit or Debit Cards'),
+ 'credit' => t('PayPal Credit'),
+ 'sepa' => t('SEPA-Lastschrift'),
+ ),
+ '#default_value' => $settings['disable_funding'],
+ '#element_validate' => array('commerce_paypal_checkout_disable_funding_validate'),
+ );
+ $form['disable_card'] = array(
+ '#title' => t('Disable card types'),
+ '#description' => t('The disabled cards for the transaction. Any cards passed do not display in the Smart payment buttons. By default, card eligibility is smartly decided based on a variety of factors.'),
+ '#type' => 'checkboxes',
+ '#options' => array(
+ 'visa' => t('Visa'),
+ 'mastercard' => t('Mastercard'),
+ 'amex' => t('American Express'),
+ 'discover' => t('Discover'),
+ 'jcb' => t('JCB'),
+ 'elo' => t('Elo'),
+ 'hiper' => t('Hiper'),
+ ),
+ '#default_value' => $settings['disable_card'],
+ '#element_validate' => array('commerce_paypal_checkout_disable_card_validate'),
+ );
+ $form['shipping_preference'] = array(
+ '#type' => 'radios',
+ '#title' => t('Shipping address collection'),
+ '#description' => t('PayPal Checkout will only request a shipping address if the Shipping module is enabled to store the address in the order.'),
+ '#options' => array(
+ 'no_shipping' => t('Do not ask for a shipping address at PayPal.'),
+ ),
+ '#default_value' => 'no_shipping',
+ );
+
+ if ($shipping_module_enabled) {
+ $form['shipping_preference']['#options'] += array(
+ 'get_from_file' => t('Ask for a shipping address at PayPal even if the order already has one.'),
+ 'set_provided_address' => t('Ask for a shipping address at PayPal if the order does not have one yet.'),
+ );
+ $form['shipping_preference']['#default_value'] = $settings['shipping_preference'];
+ }
+
+ $form['update_billing_profiles'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Update billing customer profiles with address information the customer enters at PayPal.'),
+ '#default_value' => $settings['update_billing_profiles'],
+ );
+
+ if ($shipping_module_enabled) {
+ $form['update_shipping_profiles'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Update shipping customer profiles with address information the customer enters at PayPal.'),
+ '#default_value' => $settings['update_shipping_profiles'],
+ );
+ }
+
+ $form['customize_buttons'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Smart button style'),
+ '#default_value' => !empty($settings['style']),
+ '#title_display' => 'before',
+ '#field_suffix' => t('Customize'),
+ '#description_display' => 'before',
+ '#element_validate' => array('commerce_paypal_checkout_customize_buttons_validate'),
+ );
+ $form['style'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Settings'),
+ '#description' => t('For more information, please visit customize the PayPal buttons.', array('@url' => 'https://developer.paypal.com/docs/checkout/integration-features/customize-button/#layout')),
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="parameter[payment_method][settings][payment_method][settings][customize_buttons]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ // Define some default values for the style configuration.
+ $settings['style'] += [
+ 'layout' => 'vertical',
+ 'color' => 'gold',
+ 'shape' => 'rect',
+ 'label' => 'paypal',
+ 'tagline' => FALSE,
+ ];
+ $form['style']['layout'] = array(
+ '#type' => 'select',
+ '#title' => t('Layout'),
+ '#default_value' => $settings['style']['layout'],
+ '#options' => array(
+ 'vertical' => t('Vertical (Recommended)'),
+ 'horizontal' => t('Horizontal'),
+ ),
+ );
+ $form['style']['color'] = array(
+ '#type' => 'select',
+ '#title' => t('Color'),
+ '#options' => array(
+ 'gold' => t('Gold (Recommended)'),
+ 'blue' => t('Blue'),
+ 'silver' => t('Silver'),
+ ),
+ '#default_value' => $settings['style']['color'],
+ );
+ $form['style']['shape'] = array(
+ '#type' => 'select',
+ '#title' => t('Shape'),
+ '#options' => array(
+ 'rect' => t('Rect (Default)'),
+ 'pill' => t('Pill'),
+ ),
+ '#default_value' => $settings['style']['shape'],
+ );
+ $form['style']['label'] = array(
+ '#type' => 'select',
+ '#title' => t('Label'),
+ '#options' => array(
+ 'paypal' => t('Displays the PayPal logo (Default)'),
+ 'checkout' => t('Displays the PayPal Checkout button'),
+ 'pay' => t('Displays the Pay With PayPal button and initializes the checkout flow'),
+ ),
+ '#default_value' => $settings['style']['label'],
+ );
+ $form['style']['tagline'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Display tagline'),
+ '#default_value' => $settings['style']['tagline'],
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="parameter[payment_method][settings][payment_method][settings][style][layout]"]' => array('value' => 'horizontal'),
+ ),
+ ),
+ );
+
+ $form['enable_on_cart'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show the Smart payment buttons on the cart form.'),
+ '#default_value' => $settings['enable_on_cart'],
+ );
+
+ return $form;
+}
+
+/**
+ * Element validate callback for the customize_buttons payment method setting.
+ */
+function commerce_paypal_checkout_customize_buttons_validate($element, &$form_state, $form) {
+ // Make sure no style is saved when the the "customize_buttons" checkbox
+ // is unchecked.
+ $parents = $element['#parents'];
+ array_pop($parents);
+ $parents[] = 'style';
+ if (empty($element['#value'])) {
+ drupal_array_set_nested_value($form_state['values'], $parents, array(), TRUE);
+ }
+ else {
+ $style = drupal_array_get_nested_value($form_state['values'], $parents);
+ // The tagline is not allowed for the vertical layout.
+ if ($style['layout'] == 'vertical') {
+ unset($style['tagline']);
+ drupal_array_set_nested_value($form_state['values'], $parents, $style, TRUE);
+ }
+ }
+}
+
+/**
+ * Element validate callback for the disable_funding payment method setting.
+ */
+function commerce_paypal_checkout_disable_funding_validate($element, &$form_state, $form) {
+ form_set_value($element, array_filter($element['#value']), $form_state);
+}
+
+/**
+ * Element validate callback for the disable_card payment method setting.
+ */
+function commerce_paypal_checkout_disable_card_validate($element, &$form_state, $form) {
+ $parents = $element['#parents'];
+ array_pop($parents);
+ $parents[] = 'disable_funding';
+ $disable_funding = drupal_array_get_nested_value($form_state['values'], $parents);
+
+ // When the "card" funding source is disabled, the "disable_card" setting
+ // cannot be specified.
+ if (isset($disable_funding['card'])) {
+ $element['#value'] = array();
+ }
+ form_set_value($element, array_filter($element['#value']), $form_state);
+}
+
+/**
+ * Page callback: Provide the createOrder() callback expected by the SDK.
+ */
+function commerce_paypal_checkout_create_order($order, $payment_method) {
+ $settings = $payment_method['settings'];
+ $api_client = commerce_paypal_checkout_api_client($settings);
+
+ if (!$api_client) {
+ drupal_json_output(array());
+ drupal_exit();
+ }
+ try {
+ $request_body = commerce_paypal_checkout_prepare_order_request($order, $payment_method['settings']);
+ drupal_alter('commerce_paypal_checkout_create_order_request', $request_body, $order);
+ $json = $api_client->createOrder($request_body);
+ drupal_json_output(array('id' => $json['id']));
+ drupal_exit();
+ }
+ catch (\Exception $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ }
+ drupal_json_output(array());
+ drupal_exit();
+}
+
+/**
+ * Page callback: Provide the onApprove() callback expected by the SDK.
+ */
+function commerce_paypal_checkout_approve_order($order, $payment_method, $flow) {
+ $data = drupal_json_decode(file_get_contents('php://input'));
+
+ if (!in_array($flow, array('shortcut', 'mark')) || !isset($data['id'])) {
+ drupal_json_output(array());
+ drupal_exit();
+ }
+ // Store the PayPal order ID, and the "flow" used ("shortcut"|"mark").
+ // Note that we don't perform any validation here, that happens inside
+ // commerce_paypal_checkout_redirect_form_validate().
+ $order->data['commerce_paypal_checkout'] = array(
+ 'flow' => $flow,
+ 'remote_id' => $data['id'],
+ );
+
+ // The payment_redirect key is required in the payment return url.
+ if (empty($order->data['payment_redirect_key'])) {
+ $order->data['payment_redirect_key'] = drupal_hash_base64(time());
+ }
+ // We have to manually set the payment method if empty, it's also required
+ // by the payment redirect form validate callback.
+ if (empty($order->data['payment_method'])) {
+ $order->data['payment_method'] = $payment_method['instance_id'];
+ }
+
+ // Update the order status to the payment page for the shortcut flow.
+ if ($flow == 'shortcut') {
+ commerce_order_status_update($order, 'checkout_payment', FALSE, NULL, t('Customer clicked the Smart payment buttons on the cart page.'));
+ }
+ else {
+ commerce_order_save($order);
+ }
+
+ $return_url = url('checkout/' . $order->order_id . '/payment/return/' . $order->data['payment_redirect_key']);
+ drupal_json_output(array('redirectUri' => $return_url));
+ drupal_exit();
+}
+
+/**
+ * Prepare the request parameters for the create/update order request.
+ *
+ * @param $order
+ * The order to prepare the request for.
+ * @param array $settings
+ * The payment method settings.
+ */
+function commerce_paypal_checkout_prepare_order_request($order, $settings) {
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $product_line_item_types = commerce_product_line_item_types();
+ $item_total = 0;
+ $discount_total = 0;
+ $shipping_total = 0;
+ $items = array();
+ $order_total = $order_wrapper->commerce_order_total->value();
+ $currency_code = $order_total['currency_code'];
+ foreach ($order_wrapper->commerce_line_items as $line_item_wrapper) {
+ if (!$line_item_wrapper->value()) {
+ continue;
+ }
+ $unit_price = $line_item_wrapper->commerce_unit_price->value();
+ if ($line_item_wrapper->getBundle() == 'shipping') {
+ $shipping_total += $unit_price['amount'];
+ }
+ elseif ($line_item_wrapper->getBundle() == 'commerce_discount') {
+ $discount_total += -$unit_price['amount'];
+ }
+ // PayPal Checkout doesn't support passing negative items.
+ elseif ($unit_price['amount'] >= 0) {
+ $item_total += $line_item_wrapper->commerce_total->amount->value();
+ $item = array(
+ 'name' => mb_substr(commerce_line_item_title($line_item_wrapper->value()), 0, 127),
+ 'unit_amount' => array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($unit_price['amount'], $unit_price['currency_code']),
+ ),
+ 'quantity' => intval($line_item_wrapper->quantity->value()),
+ );
+ // Pass the "SKU" for product line items.
+ if (in_array($line_item_wrapper->getBundle(), $product_line_item_types)) {
+ $item['sku'] = $line_item_wrapper->commerce_product->sku->value();
+ }
+ $items[] = $item;
+ }
+ }
+
+ // @todo: Support passing discount in the breakdown when
+ // https://github.com/paypal/paypal-checkout-components/issues/1016 is fixed.
+ $breakdown = array(
+ 'item_total' => array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($item_total, $currency_code),
+ ),
+ );
+
+ if ($shipping_total) {
+ $breakdown['shipping'] = array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($shipping_total, $currency_code),
+ );
+ }
+
+ if (module_exists('commerce_tax')) {
+ $tax_total = commerce_round(COMMERCE_ROUND_HALF_UP, commerce_tax_total_amount($order_total['data']['components'], FALSE, $currency_code));
+ if ($tax_total) {
+ $breakdown['tax_total'] = array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($tax_total, $currency_code),
+ );
+ }
+ }
+
+ if ($discount_total) {
+ $breakdown['discount'] = array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($discount_total, $currency_code),
+ );
+ }
+
+ $payer = array();
+ if (!empty($order->mail)) {
+ $payer['email_address'] = $order->mail;
+ }
+
+ // If we have a billing address, pass it to PayPal.
+ if (isset($order_wrapper->commerce_customer_billing) && !empty($order_wrapper->commerce_customer_billing->commerce_customer_address)) {
+ $address = $order_wrapper->commerce_customer_billing->commerce_customer_address->value();
+ $payer += commerce_paypal_checkout_format_address($address, 'billing');
+ }
+
+ $request_body = array(
+ 'intent' => strtoupper($settings['intent']),
+ 'purchase_units' => array(
+ array(
+ 'reference_id' => 'default',
+ 'custom_id' => $order->order_id,
+ 'invoice_id' => $order->order_id . '-' . time(),
+ 'amount' => array(
+ 'currency_code' => $currency_code,
+ 'value' => commerce_paypal_checkout_price_amount($order_total['amount'], $order_total['currency_code']),
+ 'breakdown' => $breakdown,
+ ),
+ 'items' => $items,
+ ),
+ ),
+ 'application_context' => array(
+ 'brand_name' => mb_substr(variable_get('site_name', ''), 0, 127),
+ ),
+ );
+
+ // Send the payer if not empty.
+ if ($payer) {
+ $request_body['payer'] = $payer;
+ }
+
+ $shipping_exists = module_exists('commerce_shipping');
+ $shipping_address = FALSE;
+ // If the shipping module is enabled...
+ if ($shipping_exists) {
+ // If we have a shipping address, pass it to PayPal.
+ if (isset($order_wrapper->commerce_customer_shipping) && !empty($order_wrapper->commerce_customer_shipping->commerce_customer_address)) {
+ $address = $order_wrapper->commerce_customer_shipping->commerce_customer_address->value();
+ $shipping_address = commerce_paypal_checkout_format_address($address, 'shipping');
+ }
+ }
+ $shipping_preference = $settings['shipping_preference'];
+
+ // The shipping module isn't enabled, override the shipping preference
+ // configured.
+ if (!$shipping_exists) {
+ $shipping_preference = 'no_shipping';
+ }
+ else {
+ // If no shipping address was already collected, override the shipping
+ // preference to "GET_FROM_FILE" so that the shipping address is collected
+ // on the PayPal site.
+ if ($shipping_preference == 'set_provided_address' && !$shipping_address) {
+ $shipping_preference = 'get_from_file';
+ }
+ }
+
+ // No need to pass a shipping_address if the shipping address collection
+ // is configured to "no_shipping".
+ if ($shipping_address && $shipping_preference !== 'no_shipping') {
+ $request_body['purchase_units'][0]['shipping'] = $shipping_address;
+ }
+ $request_body['application_context']['shipping_preference'] = strtoupper($shipping_preference);
+ return $request_body;
+}
+
+/**
+ * Formats the given address into a format expected by PayPal.
+ *
+ * @param array $address
+ * The address to format.
+ * @param $profile_type
+ * The profile type ("billing"|"shipping").
+ *
+ * @return array
+ * The formatted address.
+ */
+function commerce_paypal_checkout_format_address($address, $profile_type) {
+ $return = array(
+ 'address' => array(
+ 'address_line_1' => $address['thoroughfare'],
+ 'address_line_2' => $address['premise'],
+ 'admin_area_2' => mb_substr($address['locality'], 0, 120),
+ 'admin_area_1' => $address['administrative_area'],
+ 'postal_code' => mb_substr($address['postal_code'], 0, 60),
+ 'country_code' => $address['country'],
+ ),
+ );
+ if ($profile_type == 'billing') {
+ $return['name'] = array(
+ 'given_name' => $address['first_name'],
+ 'surname' => $address['last_name'],
+ );
+ }
+ elseif ($profile_type == 'shipping') {
+ $return['name'] = array(
+ 'full_name' => $address['name_line'],
+ );
+ }
+ return $return;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function commerce_paypal_checkout_theme($existing, $type, $theme, $path) {
+ return array(
+ 'commerce_paypal_checkout_smart_payment_buttons' => array(
+ 'variables' => array(
+ 'payment_method' => array(),
+ 'commit' => FALSE,
+ 'order' => NULL,
+ 'flow' => NULL,
+ ),
+ ),
+ );
+}
+
+/**
+ * Returns HTML for the Smart payment buttons.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - payment_method: The payment method instance.
+ * - commit: A boolean indicating whether to commit the transaction.
+ * - order: The order.
+ * - flow: The flow ("shortcut"|"mark").
+ *
+ * @ingroup themeable
+ */
+function theme_commerce_paypal_checkout_smart_payment_buttons($variables) {
+ $payment_method = $variables['payment_method'];
+ $settings = $payment_method['settings'] + commerce_paypal_checkout_default_settings();
+ if (empty($settings['client_id']) || empty($variables['order']) || empty($variables['flow'])) {
+ return;
+ }
+ $order = $variables['order'];
+ $order_total = field_get_items('commerce_order', $order, 'commerce_order_total', LANGUAGE_NONE);
+ if (!isset($order_total[0]['currency_code'])) {
+ return;
+ }
+ $flow = $variables['flow'];
+ list(, $rule_name) = explode('|', $payment_method['instance_id']);
+ $options = array(
+ 'external' => TRUE,
+ 'query' => array(
+ 'client-id' => $settings['client_id'],
+ 'commit' => $variables['commit'] ? 'true' : 'false',
+ 'intent' => $settings['intent'],
+ 'currency' => $order_total[0]['currency_code'],
+ ),
+ );
+ if (!empty($settings['disable_funding'])) {
+ $options['query']['disable-funding'] = implode(',', $settings['disable_funding']);
+ }
+ if (!empty($settings['disable_card'])) {
+ $options['query']['disable-card'] = implode(',', $settings['disable_card']);
+ }
+ $path = drupal_get_path('module', 'commerce_paypal_checkout');
+ $js_settings = array(
+ 'paypalCheckout' => array(
+ 'src' => url('https://www.paypal.com/sdk/js', $options),
+ 'createOrderUri' => url("commerce-paypal-checkout/create-order/$order->order_id/$rule_name"),
+ 'onApproveUri' => url("commerce-paypal-checkout/approve-order/$order->order_id/$rule_name/$flow"),
+ 'style' => $settings['style'],
+ ),
+ );
+ drupal_add_css($path . '/css/commerce_paypal_checkout.css');
+ drupal_add_js($js_settings, 'setting');
+ drupal_add_js($path . '/js/commerce_paypal_checkout.js');
+ $id = drupal_html_id('paypal-buttons-container');
+ return '
';
+}
+
+/**
+ * Returns the first configured PayPal checkout payment method instance for the
+ * given order, if any.
+ *
+ * @param $order
+ * The order that needs to be checked.
+ *
+ * @return array|bool
+ * The first payment method instance found for given order, FALSE otherwise.
+ */
+function commerce_paypal_checkout_get_payment_method_instance($order) {
+ if (empty($order->payment_methods)) {
+ $order->payment_methods = array();
+ rules_invoke_all('commerce_payment_methods', $order);
+
+ // Sort the payment methods array by the enabling Rules' weight values.
+ uasort($order->payment_methods, 'drupal_sort_weight');
+ }
+
+ foreach (array_keys($order->payment_methods) as $instance_id) {
+ // Explode the method key into its component parts.
+ list($method_id) = explode('|', $instance_id);
+ if ($method_id != 'paypal_checkout') {
+ continue;
+ }
+ return commerce_payment_method_instance_load($instance_id);
+ }
+
+ return FALSE;
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function commerce_paypal_checkout_form_alter(&$form, &$form_state, $form_id) {
+ if (!is_string($form_id)) {
+ return;
+ }
+
+ // If we're altering a shopping cart form.
+ if (strpos($form_id, 'views_form_commerce_cart_form_') === 0) {
+ // If the cart form View shows line items...
+ if (!empty($form_state['build_info']['args'][0]->result)) {
+ $order = $form_state['order'];
+ $payment_method = commerce_paypal_checkout_get_payment_method_instance($order);
+
+ // If no PayPal checkout payment method is configured, or if the buttons
+ // are explicitly not shown on the cart page, stop here.
+ if (!$payment_method || empty($payment_method['settings']['enable_on_cart'])) {
+ return;
+ }
+
+ $form['smart_payment_buttons'] = array(
+ '#theme' => 'commerce_paypal_checkout_smart_payment_buttons',
+ '#payment_method' => $payment_method,
+ '#commit' => FALSE,
+ '#flow' => 'shortcut',
+ '#order' => $order,
+ '#weight' => 100,
+ );
+ }
+ }
+}
+
+/**
+ * Returns an instantiated PayPal Checkout API client for the given settings.
+ *
+ * @param array $config
+ * An associative array containing at least the following keys:
+ * - client_id: The client ID.
+ * - secret: The client secret.
+ * - server: The API server ("sandbox or "live").
+ *
+ * @return PayPalCheckoutClient|NULL.
+ * An instantiated PayPalCheckout client, NULL if no client_id/secret were
+ * specified.
+ */
+function commerce_paypal_checkout_api_client($config) {
+ if (!isset($config['client_id']) || !isset($config['secret'])) {
+ return NULL;
+ }
+ $instances = &drupal_static(__FUNCTION__, array());
+
+ if (isset($instances[$config['client_id']])) {
+ return $instances[$config['client_id']];
+ }
+
+ $instances[$config['client_id']] = new PayPalCheckoutClient($config);
+ return $instances[$config['client_id']];
+}
+
+/**
+ * Payment method callback: redirect form.
+ */
+function commerce_paypal_checkout_redirect_form($form, &$form_state, $order, $payment_method) {
+ $form['smart_payment_buttons'] = array(
+ '#theme' => 'commerce_paypal_checkout_smart_payment_buttons',
+ '#payment_method' => $payment_method,
+ '#commit' => TRUE,
+ '#order' => $order,
+ '#flow' => 'mark',
+ );
+ return $form;
+}
+
+/**
+ * Payment method callback: redirect form return validation.
+ */
+function commerce_paypal_checkout_redirect_form_validate($order, $payment_method) {
+ $payment_method['settings'] += commerce_paypal_checkout_default_settings();
+
+ // Check if the PayPal order ID is known, as well as the "flow".
+ if (empty($order->data['commerce_paypal_checkout']['remote_id'] ||
+ !isset($order->data['commerce_paypal_checkout']['flow']))) {
+ return FALSE;
+ }
+ $flow = $order->data['commerce_paypal_checkout']['flow'];
+ $api_client = commerce_paypal_checkout_api_client($payment_method['settings']);
+ if (!$api_client) {
+ return FALSE;
+ }
+ $remote_id = $order->data['commerce_paypal_checkout']['remote_id'];
+ try {
+ $paypal_order = $api_client->getOrder($remote_id);
+ }
+ catch (\Exception $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ return FALSE;
+ }
+ $order_total = field_get_items('commerce_order', $order, 'commerce_order_total', LANGUAGE_NONE);
+ $paypal_amount = $paypal_order['purchase_units'][0]['amount'];
+ $paypal_total = commerce_currency_decimal_to_amount($paypal_amount['value'], $paypal_amount['currency_code']);
+ // Check the remote status, and that the PayPal total matches the order total.
+ if (!in_array($paypal_order['status'], ['APPROVED', 'SAVED']) ||
+ $paypal_total != $order_total[0]['amount'] ||
+ $paypal_amount['currency_code'] != $order_total[0]['currency_code']) {
+ return FALSE;
+ }
+ // Store the intent for later reuse, it can't be updated, so no risk in
+ // being out of sync.
+ $order->data['commerce_paypal_checkout']['intent'] = strtolower($paypal_order['intent']);
+
+ $payer = $paypal_order['payer'];
+ // If the user is anonymous, add their PayPal e-mail to the order.
+ if (empty($order->mail)) {
+ $order->mail = $payer['email_address'];
+ }
+ // Create a billing information profile for the order with the available info.
+ if (!empty($payment_method['settings']['update_billing_profiles'])) {
+ commerce_paypal_checkout_customer_profile($order, 'billing', $paypal_order);
+ }
+ // If the shipping module exists on the site, create a shipping information
+ // profile for the order with the available info.
+ if (module_exists('commerce_shipping') && !empty($payment_method['settings']['update_shipping_profiles'])) {
+ commerce_paypal_checkout_customer_profile($order, 'shipping', $paypal_order);
+ }
+
+ // Recalculate the price of products on the order in case taxes have
+ // changed or prices have otherwise been affected.
+ if ($flow == 'shortcut') {
+ commerce_cart_order_refresh($order);
+ }
+ // Save the changes to the order.
+ commerce_order_save($order);
+
+ if ($flow == 'mark') {
+ return commerce_paypal_checkout_do_payment($order, $payment_method);
+ }
+}
+
+/**
+ * Capture/authorize a PayPal order and create a payment transaction.
+ *
+ * @param $order
+ * The order the payment is for.
+ * @param $payment_method
+ * The PayPal Checkout payment method instance whose settings should
+ * be used to submit the request.
+ *
+ * @return
+ * Boolean indicating the success or failure of the payment request.
+ */
+function commerce_paypal_checkout_do_payment($order, $payment_method) {
+ if (empty($order->data['commerce_paypal_checkout']['remote_id'])) {
+ return FALSE;
+ }
+ $paypal_checkout_data = $order->data['commerce_paypal_checkout'];
+ $intent = isset($paypal_checkout_data['intent']) ? $paypal_checkout_data['intent'] : $payment_method['settings']['intent'];
+ $api_client = commerce_paypal_checkout_api_client($payment_method['settings']);
+ try {
+ if ($intent == 'capture') {
+ $response = $api_client->captureOrder($paypal_checkout_data['remote_id']);
+ $remote_payment = $response['purchase_units'][0]['payments']['captures'][0];
+ }
+ else {
+ $response = $api_client->authorizeOrder($paypal_checkout_data['remote_id']);
+ $remote_payment = $response['purchase_units'][0]['payments']['authorizations'][0];
+ }
+ }
+ catch (\Exception $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ // Display an error message and remain on the same page.
+ drupal_set_message(t('We could not complete your payment with PayPal. Please try again or contact us if the problem persists.'), 'error');
+ watchdog('commerce_paypal_checkout', 'PayPal Checkout transaction failed for order @order_number.', array('@order_number' => $order->order_number), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ $remote_status = strtolower($remote_payment['status']);
+
+ // Prepare a transaction object to log the API response.
+ $transaction = commerce_payment_transaction_new('paypal_checkout', $order->order_id);
+ $transaction->instance_id = $payment_method['instance_id'];
+ $transaction->amount = commerce_currency_decimal_to_amount($remote_payment['amount']['value'], $remote_payment['amount']['currency_code']);
+ $transaction->currency_code = $remote_payment['amount']['currency_code'];
+ $transaction->payload[REQUEST_TIME] = $response;
+ $transaction->remote_id = $remote_payment['id'];
+ $transaction->remote_status = $remote_payment['status'];
+
+ // Store the transaction ID as the parent transaction ID in case subsequent
+ // API operations alter this transaction's remote ID.
+ if (!empty($transaction->remote_id)) {
+ $transaction->data['commerce_paypal_checkout']['original_remote_id'] = $transaction->remote_id;
+ }
+
+ if (in_array($remote_status, ['denied', 'expired', 'declined'])) {
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ commerce_payment_transaction_save($transaction);
+ // Display an error message and remain on the same page.
+ drupal_set_message(t('We could not complete your payment with PayPal. Please try again or contact us if the problem persists.'), 'error');
+ watchdog('commerce_paypal_checkout', 'PayPal Checkout transaction failed for order @order_number.', array('@order_number' => $order->order_number), WATCHDOG_ERROR);
+ return FALSE;
+ }
+
+ // Map the remote status to a Drupal commerce payment status.
+ $status_mapping = array(
+ 'created' => COMMERCE_PAYMENT_STATUS_PENDING,
+ 'pending' => COMMERCE_PAYMENT_STATUS_PENDING,
+ 'completed' => COMMERCE_PAYMENT_STATUS_SUCCESS,
+ );
+
+ // If we do not know how to handle this remote payment status, set the payment
+ // status to failure and stop here.
+ if (!isset($status_mapping[$remote_status])) {
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ commerce_payment_transaction_save($transaction);
+ // Display an error message and remain on the same page.
+ drupal_set_message(t('We could not complete your payment with PayPal. Please try again or contact us if the problem persists.'), 'error');
+ watchdog('commerce_paypal_checkout', 'PayPal Checkout transaction failed for order @order_number.', array('@order_number' => $order->order_number), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ $transaction->status = $status_mapping[$remote_status];
+ commerce_payment_transaction_save($transaction);
+ return TRUE;
+}
+
+/**
+ * Creates or updates a customer profile for an order based on information
+ * obtained from PayPal after a payment via PayPal Checkout.
+ *
+ * @param $order
+ * The order that was paid via PayPal Checkout.
+ * @param $profile_type
+ * The type of the customer profile that should be created or updated.
+ * @param array $paypal_order
+ * The PayPal order retrieved via the getOrder() API call.
+ * @param $skip_save
+ * Boolean indicating whether or not this function should skip saving the
+ * order after setting it to reference the newly created customer profile;
+ * defaults to TRUE, requiring the caller to save the order.
+ */
+function commerce_paypal_checkout_customer_profile($order, $profile_type, $paypal_order, $skip_save = TRUE) {
+ // First check if the order already references a customer profile of the
+ // specified type.
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $field_name = variable_get('commerce_customer_profile_' . $profile_type . '_field', '');
+
+ // If the associated order field has been set and the order currently
+ // references a customer profile through it...
+ if (!empty($field_name) && !empty($order_wrapper->{$field_name})) {
+ // Update the existing customer profile.
+ $profile = $order_wrapper->{$field_name}->value();
+ }
+ elseif (!empty($order->data['profiles']['customer_profile_' . $profile_type])) {
+ // Otherwise look for an association stored in the order's data array.
+ $profile = commerce_customer_profile_load($order->data['profiles']['customer_profile_' . $profile_type]);
+ }
+
+ // Create a new profile if we could not find an existing one.
+ if (empty($profile)) {
+ $profile = commerce_customer_profile_new($profile_type, $order->uid);
+ }
+
+ // Add the order context to the profile to ensure it can be updated without
+ // resulting in customer profile duplication.
+ $profile->entity_context = array(
+ 'entity_type' => 'commerce_order',
+ 'entity_id' => $order->order_id,
+ );
+
+ // Prepare an addressfield array to set to the customer profile.
+ $field = field_info_field('commerce_customer_address');
+ $instance = field_info_instance('commerce_customer_profile', 'commerce_customer_address', $profile_type);
+ $address = addressfield_default_values($field, $instance);
+
+ $paypal_address = array();
+ // Use the first name and last name if the profile is a billing profile.
+ if ($profile_type == 'billing') {
+ $address['first_name'] = $paypal_order['payer']['name']['given_name'];
+ $address['last_name'] = $paypal_order['payer']['name']['surname'];
+ $address['name_line'] = $address['first_name'] . ' ' . $address['last_name'];
+ if (isset($paypal_order['payer']['address'])) {
+ $paypal_address = $paypal_order['payer']['address'];
+ }
+ }
+ // Otherwise if it's a shipping profile, populate the address with all of
+ // the shipping information returned from PayPal.
+ elseif ($profile_type == 'shipping') {
+ // If no shipping info was returned by PayPal.
+ if (empty($paypal_order['purchase_units'][0]['shipping'])) {
+ return;
+ }
+ $shipping_info = $paypal_order['purchase_units'][0]['shipping'];
+ $names = explode(' ', $shipping_info['name']['full_name']);
+ $first_name = array_shift($names);
+ $last_name = implode(' ', $names);
+ $address['first_name'] = $first_name;
+ $address['last_name'] = $last_name;
+ $address['name_line'] = $first_name . ' ' . $last_name;
+ if (isset($shipping_info['address'])) {
+ $paypal_address = $shipping_info['address'];
+ }
+ }
+
+ if ($paypal_address) {
+ // Map PayPal address keys to Address field keys.
+ $mapping = array(
+ 'address_line_1' => 'thoroughfare',
+ 'address_line_2' => 'premise',
+ 'admin_area_1' => 'administrative_area',
+ 'admin_area_2' => 'locality',
+ 'postal_code' => 'postal_code',
+ 'country_code' => 'country',
+ );
+ foreach ($paypal_address as $key => $value) {
+ if (!isset($mapping[$key])) {
+ continue;
+ }
+ // PayPal address fields have a higher maximum length than ours.
+ $value = $key == 'country_code' ? $value : mb_substr($value, 0, 255);
+ $address[$mapping[$key]] = $value;
+ }
+ }
+
+ // Add the addressfield value to the customer profile.
+ $profile_wrapper = entity_metadata_wrapper('commerce_customer_profile', $profile);
+ $profile_wrapper->commerce_customer_address = $address;
+
+ // Save the customer profile and update the order to reference it.
+ $profile_wrapper->save();
+ $order_wrapper->{'commerce_customer_' . $profile_type} = $profile_wrapper;
+
+ // Save the order if specified.
+ if (!$skip_save) {
+ $order_wrapper->save();
+ }
+}
+
+/**
+ * Update the PayPal order.
+ *
+ * @param $order
+ * The order.
+ * @param $payment_method
+ * The payment method instance.
+ *
+ * @return bool
+ * TRUE if the update was successful, FALSE otherwise.
+ *
+ * @see commerce_paypal_checkout_review_pane_checkout_form_submit()
+ */
+function commerce_paypal_checkout_update_order($order, $payment_method) {
+ if (!isset($order->data['commerce_paypal_checkout']['remote_id'])) {
+ return FALSE;
+ }
+ $remote_id = $order->data['commerce_paypal_checkout']['remote_id'];
+ $request_body = commerce_paypal_checkout_prepare_order_request($order, $payment_method['settings']);
+ $update_params = array(
+ array(
+ 'op' => 'replace',
+ 'path' => "/purchase_units/@reference_id=='default'",
+ 'value' => $request_body['purchase_units'][0],
+ ),
+ );
+ drupal_alter('commerce_paypal_checkout_update_order_request', $update_params, $order);
+ $api_client = commerce_paypal_checkout_api_client($payment_method['settings']);
+ try {
+ $api_client->updateOrder($remote_id, $update_params);
+ // Assume the update worked if we ended up here, if the update failed,
+ // an exception was thrown.
+ return TRUE;
+ }
+ catch (\Exception $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ return FALSE;
+ }
+}
+
+/**
+ * Formats a price amount into a decimal value as expected by PayPal.
+ *
+ * @param $amount
+ * An integer price amount.
+ * @param $currency_code
+ * The currency code of the price.
+ *
+ * @return
+ * The decimal price amount as expected by PayPal API servers.
+ */
+function commerce_paypal_checkout_price_amount($amount, $currency_code) {
+ $rounded_amount = commerce_currency_round($amount, commerce_currency_load($currency_code));
+ return number_format(commerce_currency_amount_to_decimal($rounded_amount, $currency_code), 2, '.', '');
+}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/css/commerce_paypal_checkout.css b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/css/commerce_paypal_checkout.css
new file mode 100644
index 000000000..deeda620b
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/css/commerce_paypal_checkout.css
@@ -0,0 +1,9 @@
+@media all and (min-width: 61em) {
+ .page-cart .paypal-buttons-container {
+ float: right;
+ width: 50%;
+ }
+}
+.page-checkout-payment .checkout-help {
+ display: none;
+}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.admin.inc b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.admin.inc
new file mode 100644
index 000000000..668a337ed
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.admin.inc
@@ -0,0 +1,297 @@
+instance_id);
+ $form_state['payment_method'] = $payment_method;
+ $balance = commerce_payment_order_balance($order);
+
+
+ if ($balance['amount'] > 0 && $balance['amount'] < $transaction->amount) {
+ $default_amount = $balance['amount'];
+ }
+ else {
+ $default_amount = $transaction->amount;
+ }
+
+ // Convert the price amount to a user friendly decimal value.
+ $default_amount = number_format(commerce_currency_amount_to_decimal($default_amount, $transaction->currency_code), 2, '.', '');
+
+ $description = implode('
', array(
+ t('Authorization: @amount', array('@amount' => commerce_currency_format($transaction->amount, $transaction->currency_code))),
+ t('Order balance: @balance', array('@balance' => commerce_currency_format($balance['amount'], $balance['currency_code']))),
+ ));
+
+ $form['amount'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Capture amount'),
+ '#description' => $description,
+ '#default_value' => $default_amount,
+ '#field_suffix' => check_plain($transaction->currency_code),
+ '#size' => 16,
+ );
+
+ $form = confirm_form($form,
+ t('What amount do you want to capture?'),
+ 'admin/commerce/orders/' . $order->order_id . '/payment',
+ '',
+ t('Capture'),
+ t('Cancel'),
+ 'confirm'
+ );
+
+ return $form;
+}
+
+/**
+ * Validate handler: ensure a valid amount is given.
+ */
+function commerce_paypal_checkout_capture_form_validate($form, &$form_state) {
+ $transaction = $form_state['transaction'];
+ $amount = $form_state['values']['amount'];
+
+ // Ensure a positive numeric amount has been entered for capture.
+ if (!is_numeric($amount) || $amount <= 0) {
+ form_set_error('amount', t('You must specify a positive numeric amount to capture.'));
+ }
+
+ // Ensure the amount is within the allowed limit for PayPal authorizations.
+ $authorization_amount = commerce_currency_amount_to_decimal($transaction->amount, $transaction->currency_code);
+ $authorization_amount_upper = commerce_currency_amount_to_decimal($transaction->amount, $transaction->currency_code) + 75;
+
+ if ($amount > $authorization_amount * 1.15 || $amount > $authorization_amount_upper) {
+ form_set_error('amount', t('You cannot capture an amount $75 or 115% greater than the authorization amount in PayPal Checkout.'));
+ }
+
+ // If the authorization has expired, display an error message and redirect.
+ if (REQUEST_TIME - $transaction->created > 86400 * 29) {
+ drupal_set_message(t('This authorization has passed its 29 day limit and cannot be captured.'), 'error');
+ drupal_goto('admin/commerce/orders/' . $form_state['order']->order_id . '/payment');
+ }
+}
+
+/**
+ * Submit handler: process a prior authorization capture via PayPal Checkout.
+ */
+function commerce_paypal_checkout_capture_form_submit($form, &$form_state) {
+ $transaction = $form_state['transaction'];
+ $order = $form_state['order'];
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $order_total = $order_wrapper->commerce_order_total->value();
+ $amount = commerce_currency_decimal_to_amount($form_state['values']['amount'], $transaction->currency_code);
+ $api_client = commerce_paypal_checkout_api_client($form_state['payment_method']['settings']);
+
+ $params = array(
+ 'final_capture' => $order_total['amount'] == $amount,
+ 'amount' => array(
+ 'value' => commerce_paypal_checkout_price_amount($amount, $transaction->currency_code),
+ 'currency_code' => $transaction->currency_code,
+ ),
+ );
+
+ try {
+ // If the transaction was authorized more than 3 days ago, we need to
+ // re-authorize the payment.
+ if (time() >= ($transaction->created + (86400 * 3))) {
+ $api_client->reAuthorizePayment($transaction->remote_id, array('amount' => $params['amount']));
+ }
+
+ $response = $api_client->capturePayment($transaction->remote_id, $params);
+ if (strtolower($response['status']) == 'completed') {
+ $transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
+ }
+ else {
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ }
+ $transaction->remote_id = $response['id'];
+ $transaction->amount = $amount;
+ $transaction->remote_status = $response['status'];
+ // Note the capture in the transaction message.
+ $transaction->message .= '
' . t('Captured: @date', array('@date' => format_date(REQUEST_TIME, 'short')));
+ $transaction->payload[REQUEST_TIME . '-capture'] = $response;
+ // Save the updated original transaction.
+ commerce_payment_transaction_save($transaction);
+ }
+ catch (PayPalCheckoutHttpException $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ // Display an error message but leave the transaction pending.
+ drupal_set_message(t('Prior authorization capture failed, so the transaction will remain in a pending status.'), 'error');
+ }
+
+ // Redirect back to the current order payment page.
+ $form_state['redirect'] = 'admin/commerce/orders/' . $form_state['order']->order_id . '/payment';
+}
+
+/**
+ * Form callback: allows the user to void a transaction.
+ */
+function commerce_paypal_checkout_void_form($form, &$form_state, $order, $transaction) {
+ $form_state['order'] = $order;
+ $form_state['transaction'] = $transaction;
+
+ // Load and store the payment method instance for this transaction.
+ $payment_method = commerce_payment_method_instance_load($transaction->instance_id);
+ $form_state['payment_method'] = $payment_method;
+
+ $form['markup'] = array(
+ '#markup' => t('Are you sure that you want to void this transaction?'),
+ );
+
+ $form = confirm_form($form,
+ t('Are you sure that you want to void this transaction?'),
+ 'admin/commerce/orders/' . $order->order_id . '/payment',
+ '',
+ t('Void'),
+ t('Cancel'),
+ 'confirm'
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler: process the void request.
+ */
+function commerce_paypal_checkout_void_form_submit($form, &$form_state) {
+ $transaction = $form_state['transaction'];
+ $api_client = commerce_paypal_checkout_api_client($form_state['payment_method']['settings']);
+
+ try {
+ // This API call doesn't return content, so nothing to check, if no
+ // exception is thrown, this means the void operation succeeded.
+ $api_client->voidPayment($transaction->remote_id);
+ drupal_set_message(t('Transaction successfully voided.'));
+
+ // Set the remote and local status accordingly.
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ $transaction->remote_status = COMMERCE_CREDIT_VOID;
+
+ // Update the transaction message to show that it has been voided.
+ $transaction->message .= '
' . t('Voided: @date', array('@date' => format_date(REQUEST_TIME, 'short')));
+ commerce_payment_transaction_save($transaction);
+ }
+ catch (PayPalCheckoutHttpException $exception) {
+ drupal_set_message(t('The void operation failed, so the transaction will remain in a pending status.'), 'error');
+ }
+ $form_state['redirect'] = 'admin/commerce/orders/' . $form_state['order']->order_id . '/payment';
+}
+
+/**
+ * Form callback: allows the user to issue a credit on a prior transaction.
+ */
+function commerce_paypal_checkout_refund_form($form, &$form_state, $order, $transaction) {
+ $form_state['order'] = $order;
+ $form_state['transaction'] = $transaction;
+
+ // Load and store the payment method instance for this transaction.
+ $payment_method = commerce_payment_method_instance_load($transaction->instance_id);
+ $form_state['payment_method'] = $payment_method;
+
+ $default_amount = number_format(commerce_currency_amount_to_decimal($transaction->amount, $transaction->currency_code), 2, '.', '');
+
+ $form['amount'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Refund amount'),
+ '#description' => t('Enter the amount to be refunded back to the PayPal account.'),
+ '#default_value' => $default_amount,
+ '#field_suffix' => check_plain($transaction->currency_code),
+ '#size' => 16,
+ );
+
+ $form = confirm_form($form,
+ t('What amount do you want to refund?'),
+ 'admin/commerce/orders/' . $order->order_id . '/payment',
+ '',
+ t('Refund'),
+ t('Cancel'),
+ 'confirm'
+ );
+
+ return $form;
+}
+
+/**
+ * Validate handler: check the credit amount before attempting a refund request.
+ */
+function commerce_paypal_checkout_refund_form_validate($form, &$form_state) {
+ $transaction = $form_state['transaction'];
+ $amount = $form_state['values']['amount'];
+
+ // Ensure a positive numeric amount has been entered for refund.
+ if (!is_numeric($amount) || $amount <= 0) {
+ form_set_error('amount', t('You must specify a positive numeric amount to refund.'));
+ }
+
+ // Ensure the amount is less than or equal to the captured amount.
+ if ($amount > commerce_currency_amount_to_decimal($transaction->amount, $transaction->currency_code)) {
+ form_set_error('amount', t('You cannot refund more than you captured.'));
+ }
+
+ // If the transaction is older than 60 days, display an error message and redirect.
+ if (time() - $transaction->created > 86400 * 60) {
+ drupal_set_message(t('This transaction has passed its 60 day limit for issuing refunds.'), 'error');
+ drupal_goto('admin/commerce/orders/' . $form_state['order']->order_id . '/payment');
+ }
+}
+
+/**
+ * Submit handler: process a refund request.
+ */
+function commerce_paypal_checkout_refund_form_submit($form, &$form_state) {
+ $transaction = $form_state['transaction'];
+ $payment_method = $form_state['payment_method'];
+
+ $order = $form_state['order'];
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $order_total = $order_wrapper->commerce_order_total->value();
+ $api_client = commerce_paypal_checkout_api_client($form_state['payment_method']['settings']);
+ $amount = commerce_currency_decimal_to_amount($form_state['values']['amount'], $order_total['currency_code']);
+
+ $params = array(
+ 'amount' => array(
+ 'value' => commerce_paypal_checkout_price_amount($amount, $transaction->currency_code),
+ 'currency_code' => $transaction->currency_code,
+ ),
+ );
+ try {
+ $response = $api_client->refundPayment($transaction->remote_id, $params);
+ // Not sure this can happen...
+ if (strtolower($response['status']) != 'completed') {
+ drupal_set_message(t('Refund failed'));
+ }
+ else {
+ drupal_set_message(t('Refund for @amount issued successfully.', array('@amount' => commerce_currency_format($amount, $transaction->currency_code))));
+
+ // Create a new transaction to record the credit.
+ $credit_transaction = commerce_payment_transaction_new($payment_method['method_id'], $order->order_id);
+ $credit_transaction->instance_id = $payment_method['instance_id'];
+ $credit_transaction->remote_id = $response['id'];
+ $credit_transaction->amount = $amount * -1;
+ $credit_transaction->currency_code = $transaction->currency_code;
+ $credit_transaction->payload[REQUEST_TIME] = $response;
+ $credit_transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
+ $credit_transaction->remote_status = COMMERCE_CREDIT_CREDIT;
+ $credit_transaction->message = t('Refunded to @remote_id.', array('@remote_id' => $transaction->remote_id));
+
+ // Save the credit transaction.
+ commerce_payment_transaction_save($credit_transaction);
+ }
+ }
+ catch (PayPalCheckoutHttpException $exception) {
+ watchdog_exception('commerce_paypal_checkout', $exception);
+ drupal_set_message(t('Refund failed'));
+ }
+
+ $form_state['redirect'] = 'admin/commerce/orders/' . $order->order_id . '/payment';
+}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.checkout_pane.inc b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.checkout_pane.inc
new file mode 100644
index 000000000..fa8d1e530
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/includes/commerce_paypal_checkout.checkout_pane.inc
@@ -0,0 +1,206 @@
+ $checkout_pane) {
+ if (!in_array($pane_id, $excluded_panes) && $checkout_pane['module'] != 'commerce_customer' ) {
+ $options[$pane_id] = check_plain($checkout_pane['name']);
+ }
+ }
+
+ // If we have available checkout panes for this page...
+ if (!empty($options)) {
+ // Allow the administrator to choose which panes the customer should see
+ // upon returning from PayPal Checkout.
+ $form['commerce_paypal_checkout_review_embedded_panes'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Checkout panes to include on the PayPal Checkout review and confirm page'),
+ '#options' => $options,
+ '#default_value' => variable_get('commerce_paypal_checkout_review_embedded_panes', array()),
+ );
+ }
+
+ return $form;
+}
+
+/**
+ * Checkout pane callback: returns a pane allowing the customer to review the
+ * final details of the order and provide any final information required.
+ */
+function commerce_paypal_checkout_review_pane_checkout_form(&$form, &$form_state, $checkout_pane, $order) {
+ $form_state['build_info']['files']['pane'] = drupal_get_path('module', 'commerce_paypal_checkout') . '/includes/commerce_paypal_checkout.checkout_pane.inc';
+ $form_state['order'] = $order;
+
+ // Adjust the weights of the help text and pane form to appear before the
+ // embedded checkout panes.
+ $form['help']['#weight'] = -10;
+
+ $pane_form = array(
+ '#weight' => -5,
+ );
+
+ // Duplicate the review checkout pane's contents.
+ $pane_form['review'] = array(
+ '#theme' => 'commerce_checkout_review',
+ '#data' => array(),
+ );
+
+ // Loop through all the pages before the review page...
+ foreach (commerce_checkout_pages() as $page_id => $checkout_page) {
+ // Exit the loop once the review page is reached.
+ if ($page_id == 'review') {
+ break;
+ }
+
+ // Loop through all the panes on the current page specifying review...
+ foreach (commerce_checkout_panes(array('page' => $page_id, 'enabled' => TRUE, 'review' => TRUE)) as $pane_id => $checkout_pane_local) {
+ // If the pane has a valid review callback...
+ if ($callback = commerce_checkout_pane_callback($checkout_pane_local, 'review')) {
+ // Get the review data for this pane.
+ $pane_data = $callback($form, $form_state, $checkout_pane_local, $order);
+
+ // Only display the pane if there is data in the pane.
+ if (!empty($pane_data)) {
+ // Add a row for it in the review data.
+ $pane_form['review']['#data'][$pane_id] = array(
+ 'title' => $checkout_pane_local['title'],
+ 'data' => $pane_data,
+ );
+ }
+ }
+ }
+ }
+
+ // Embed other specified checkout panes in this checkout pane.
+ foreach (commerce_paypal_checkout_embedded_checkout_panes() as $embedded_pane_id) {
+ $embedded_pane = commerce_checkout_pane_load($embedded_pane_id);
+
+ // If the checkout pane defines a checkout form callback...
+ if ($embedded_pane && $callback = commerce_checkout_pane_callback($embedded_pane, 'checkout_form')) {
+ // Get the form for the embedded checkout pane.
+ $embedded_pane_form = $callback($form, $form_state, $embedded_pane, $order);
+
+ // Embed it on this checkout pane if the form returned data.
+ if (!empty($embedded_pane_form)) {
+ $form[$embedded_pane_id] = array(
+ '#type' => $embedded_pane['fieldset'] ? 'fieldset' : 'container',
+ '#title' => check_plain($embedded_pane['title']),
+ '#collapsible' => $embedded_pane['collapsible'],
+ '#collapsed' => $embedded_pane['collapsed'],
+ '#attributes' => array('class' => array($embedded_pane_id)),
+ '#tree' => TRUE,
+ ) + $embedded_pane_form;
+ }
+ }
+ }
+
+ $form['pay_now'] = array(
+ '#type' => 'submit',
+ '#value' => t('Pay Now'),
+ '#validate' => array('commerce_paypal_checkout_review_pane_checkout_form_validate'),
+ '#submit' => array('commerce_paypal_checkout_review_pane_checkout_form_submit'),
+ );
+
+ return $pane_form;
+}
+
+/**
+ * Validate handler for the PayPal Checkout review and confirm page.
+ */
+function commerce_paypal_checkout_review_pane_checkout_form_validate($form, &$form_state) {
+ $order = $form_state['order'];
+ $form_validate = TRUE;
+
+ // Loop through the enabled checkout panes included in this page to validate
+ // and submit them.
+ foreach (commerce_paypal_checkout_embedded_checkout_panes() as $embedded_pane_id) {
+ $embedded_pane_validate = TRUE;
+
+ // Load the checkout pane to find its checkout pane validate callback.
+ $embedded_checkout_pane = commerce_checkout_pane_load($embedded_pane_id);
+
+ // If it has a validate callback.
+ if ($callback = commerce_checkout_pane_callback($embedded_checkout_pane, 'checkout_form_validate')) {
+ // Give it a chance to process the submitted data.
+ $embedded_pane_validate &= $callback($form, $form_state, $embedded_checkout_pane, $order);
+ }
+
+ // Submit the pane if it validated.
+ if ($embedded_pane_validate && $callback = commerce_checkout_pane_callback($embedded_checkout_pane, 'checkout_form_submit')) {
+ $callback($form, $form_state, $embedded_checkout_pane, $order);
+ }
+
+ // A failed pane makes the form fail.
+ $form_validate &= $embedded_pane_validate;
+ }
+
+ // Save the updated order object.
+ commerce_order_save($order);
+
+ // If a pane failed validation or the form state has otherwise been altered to
+ // initiate a rebuild, return without moving to the next checkout page.
+ if (!$form_validate || $form_state['rebuild']) {
+ $form_state['rebuild'] = TRUE;
+ }
+}
+
+/**
+ * Submit handler for the PayPal Checkout review and confirm page.
+ */
+function commerce_paypal_checkout_review_pane_checkout_form_submit($form, &$form_state) {
+ $order = $form_state['order'];
+ $payment_method = commerce_payment_method_instance_load($order->data['payment_method']);
+ // Update the order in PayPal to make sure it reflects the current state of
+ // the order in Drupal.
+ // If the order could not be updated in PayPal, stop here.
+ if (!commerce_paypal_checkout_update_order($order, $payment_method)) {
+ drupal_set_message(t('We could not complete your payment with PayPal. Please try again or contact us if the problem persists.'), 'error');
+ watchdog('commerce_paypal_checkout', 'Could not update the PayPal order for order @order_number.', array('@order_number' => $order->order_number), WATCHDOG_ERROR);
+ return;
+ }
+
+ // Attempt to process the payment.
+ if (commerce_paypal_checkout_do_payment($order, $payment_method)) {
+ // Proceed to the next page if it succeeded.
+ $order_status = commerce_order_status_load($order->status);
+ $checkout_page = commerce_checkout_page_load($order_status['checkout_page']);
+ $next_page = $checkout_page['next_page'];
+
+ // Update the order status to the next checkout page.
+ $order = commerce_order_status_update($order, 'checkout_' . $next_page, FALSE, FALSE);
+
+ // Inform modules of checkout completion if the next page is completed.
+ if ($next_page == 'complete') {
+ commerce_checkout_complete($order);
+ }
+
+ // Redirect to the URL for the new checkout page.
+ $form_state['redirect'] = commerce_checkout_order_uri($order);
+ }
+}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/js/commerce_paypal_checkout.js b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/js/commerce_paypal_checkout.js
new file mode 100644
index 000000000..308429faf
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/js/commerce_paypal_checkout.js
@@ -0,0 +1,66 @@
+/**
+ * @file
+ * Renders the PayPal Smart payment buttons.
+ */
+
+(function($) {
+
+ Drupal.paypalCheckout = {
+ renderButtons: function(settings) {
+ $('.paypal-buttons-container').once('rendered').each(function() {
+ paypal.Buttons({
+ createOrder: function() {
+ return fetch(settings.createOrderUri)
+ .then(function(res) {
+ return res.json();
+ }).then(function(data) {
+ return data.id ? data.id : '';
+ });
+ },
+ onApprove: function (data) {
+ return fetch(settings.onApproveUri, {
+ method: 'post',
+ body: JSON.stringify({
+ id: data.orderID
+ })
+ }).then(function(res) {
+ return res.json();
+ }).then(function(data) {
+ if (data.hasOwnProperty('redirectUri')) {
+ window.location.href = data.redirectUri;
+ }
+ });
+ },
+ style: settings['style']
+ }).render('#' + $(this).attr('id'));
+ });
+ },
+ initialize: function (context, settings) {
+ if (context === document) {
+ var script = document.createElement('script');
+ script.src = settings.src;
+ script.type = 'text/javascript';
+ script.setAttribute('data-partner-attribution-id', 'CommerceGuys_Cart_SPB');
+ document.getElementsByTagName('head')[0].appendChild(script);
+ }
+ var waitForSdk = function(settings) {
+ if (typeof paypal !== 'undefined') {
+ Drupal.paypalCheckout.renderButtons(settings);
+ }
+ else {
+ setTimeout(function() {
+ waitForSdk(settings)
+ }, 100);
+ }
+ };
+ waitForSdk(settings);
+ }
+ };
+
+ Drupal.behaviors.commercePaypalCheckout = {
+ attach: function(context, settings) {
+ Drupal.paypalCheckout.initialize(context, settings.paypalCheckout);
+ }
+ };
+
+}(jQuery));
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutClient.php b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutClient.php
new file mode 100644
index 000000000..335960d7e
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutClient.php
@@ -0,0 +1,393 @@
+config = $config;
+ $this->logger = $logger;
+ $this->retryCount = 0;
+ $this->headers = array(
+ 'Accept' => 'application/json',
+ // Defaults the "Content-Type" header to application/json.
+ 'Content-Type' => 'application/json',
+ 'PayPal-Partner-Attribution-Id' => 'CommerceGuys_Cart_SPB',
+ );
+ }
+
+ /**
+ * Sets the default cURL options.
+ */
+ public static function setDefaultCurlOptions($ch) {
+ curl_setopt($ch, CURLOPT_HEADER, FALSE);
+ curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
+ curl_setopt($ch, CURLOPT_VERBOSE, FALSE);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 180);
+ }
+
+ /**
+ * Send a message to the logger.
+ *
+ * @param string $message
+ * The message to log.
+ */
+ public function logMessage($message) {
+ if (is_callable($this->logger)) {
+ call_user_func($this->logger, $message);
+ }
+ }
+
+ /**
+ * Returns the base URL for the API, based on the specified mode.
+ *
+ * @return string
+ * The base URL for the API that query parameters will be appended to when
+ * submitting API requests.
+ */
+ public function baseUrl() {
+ switch ($this->config['server']) {
+ case 'live':
+ return 'https://api.paypal.com';
+
+ case 'sandbox':
+ default:
+ return 'https://api.sandbox.paypal.com';
+ }
+ }
+
+ /**
+ * Acquire an access token from PayPal.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ *
+ * @throws PayPalCheckoutAuthenticationException
+ */
+ protected function acquireAccessToken() {
+ $ch = curl_init();
+ static::setDefaultCurlOptions($ch);
+ $headers = array(
+ 'Authorization' => 'Basic ' . base64_encode($this->config['client_id'] . ':' . $this->config['secret']),
+ 'Content-Type' => 'application/x-www-form-urlencoded',
+ ) + $this->headers;
+ $url = $this->baseUrl() . '/v1/oauth2/token';
+ curl_setopt($ch, CURLOPT_HTTPHEADER, static::formatHeaders($headers));
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
+
+ // Submit the request to the PayPal server.
+ $response = curl_exec($ch);
+
+ // Ensure we got a successful response by inspecting the HTTP status code.
+ $response_info = curl_getinfo($ch);
+
+ if (is_resource($ch)) {
+ curl_close($ch);
+ }
+
+ $json = drupal_json_decode($response);
+
+ if ($response_info['http_code'] == 401) {
+ // Throw an exception indicating authentication failed.
+ $message = 'Authentication failed.';
+ if (isset($json['error_description'])) {
+ $message = sprintf('Error description: %s.', $json['error_description']);
+ }
+ throw new PayPalCheckoutAuthenticationException($message);
+ }
+
+ return $json;
+ }
+
+ /**
+ * Returns the access token stored locally if any, or get one from PayPal.
+ *
+ * @return string
+ * The Oauth2 access token.
+ *
+ * @throws PayPalCheckoutAuthenticationException
+ */
+ public function getAccessToken() {
+ $access_token = variable_get('commerce_paypal_checkout_access_token', array());
+ if (!empty($access_token['token']) && $access_token['expires'] > time()) {
+ return $access_token['token'];
+ }
+ $response = $this->acquireAccessToken();
+ variable_set('commerce_paypal_checkout_access_token', array(
+ 'token' => $response['access_token'],
+ 'expires' => time() + $response['expires_in'],
+ ));
+ return $response['access_token'];
+ }
+
+ /**
+ * Creates an order in PayPal.
+ *
+ * @param array $parameters
+ * An array of parameters to include with the request.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function createOrder($parameters) {
+ return $this->submitRequest('POST', 'v2/checkout/orders', $parameters);
+ }
+
+ /**
+ * Get an existing order from PayPal.
+ *
+ * @param $remote_id
+ * The PayPal order ID.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function getOrder($remote_id) {
+ return $this->submitRequest('GET', sprintf('v2/checkout/orders/%s', $remote_id));
+ }
+
+ /**
+ * Updates an existing PayPal order.
+ *
+ * @param $remote_id
+ * The PayPal order ID.
+ * @param array $parameters
+ * An array of parameters to include with the request.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function updateOrder($remote_id, $parameters) {
+ return $this->submitRequest('PATCH', sprintf('v2/checkout/orders/%s', $remote_id), $parameters);
+ }
+
+ /**
+ * Authorize payment for order.
+ *
+ * @param $remote_id
+ * The PayPal order ID.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function authorizeOrder($remote_id) {
+ return $this->submitRequest('POST', sprintf('v2/checkout/orders/%s/authorize', $remote_id));
+
+ }
+
+ /**
+ * Capture payment for order.
+ *
+ * @param $remote_id
+ * The PayPal order ID.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function captureOrder($remote_id) {
+ return $this->submitRequest('POST', sprintf('v2/checkout/orders/%s/capture', $remote_id));
+ }
+
+ /**
+ * Captures an authorized payment, by ID.
+ *
+ * @param $authorization_id
+ * The PayPal-generated ID for the authorized payment to capture.
+ * @param array $parameters
+ * (optional An array of parameters to pass as the request body.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function capturePayment($authorization_id, array $parameters = array()) {
+ return $this->submitRequest('POST', sprintf('v2/payments/authorizations/%s/capture', $authorization_id), $parameters);
+ }
+
+ /**
+ * Reauthorizes an authorized PayPal account payment, by ID.
+ *
+ * @param $authorization_id
+ * The PayPal-generated ID of the authorized payment to reauthorize.
+ * @param array $parameters
+ * (optional An array of parameters to pass as the request body.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function reAuthorizePayment($authorization_id, array $parameters = array()) {
+ return $this->submitRequest('POST', sprintf('v2/payments/authorizations/%s/reauthorize', $authorization_id), $parameters);
+ }
+
+ /**
+ * Refunds a captured payment, by ID.
+ *
+ * @param $capture_id
+ * The PayPal-generated ID for the captured payment to refund.
+ * @param array $parameters
+ * (optional An array of parameters to pass as the request body.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function refundPayment($capture_id, array $parameters = array()) {
+ return $this->submitRequest('POST', sprintf('v2/payments/captures/%s/refund', $capture_id), $parameters);
+ }
+
+ /**
+ * Voids, or cancels, an authorized payment, by ID.
+ *
+ * @param $authorization_id
+ * The PayPal-generated ID of the authorized payment to void.
+ */
+ public function voidPayment($authorization_id) {
+ return $this->submitRequest('POST', sprintf('v2/payments/authorizations/%s/void', $authorization_id));
+ }
+
+ /**
+ * Submits an API request to the PayPal server.
+ *
+ * @param string $method
+ * The HTTP method to use. One of: 'GET', 'POST', 'PATCH', 'PUT', DELETE'.
+ * @param string $path
+ * The remote path. The base URL will be automatically appended.
+ * @param array $parameters
+ * An array of parameters to include with the request. Optional.
+ *
+ * @throws PayPalCheckoutAuthenticationException if the request fails authentication.
+ * @throws PayPalCheckoutHttpServerErrorException if the response status code is 5xx.
+ * @throws PayPalCheckoutHttpClientErrorException if the response status code is 4xx.
+ * @throws PayPalCheckoutHttpRedirectionException if the response status code is 3xx.
+ * @throws PayPalCheckoutInvalidResponseJsonException if the response is not valid JSON.
+ *
+ * @return string[]
+ * The API response JSON converted to an associative array.
+ */
+ public function submitRequest($method, $path, $parameters = array()) {
+ $this->headers['Authorization'] = 'Bearer ' . $this->getAccessToken();
+ $url = $this->baseUrl() . '/' . $path;
+ $ch = curl_init();
+ static::setDefaultCurlOptions($ch);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ if (!empty($parameters)) {
+ if ($this->headers['Content-Type'] == 'application/json') {
+ // JSON encode the fields and set them to the request body.
+ curl_setopt($ch, CURLOPT_POSTFIELDS, drupal_json_encode($parameters));
+ }
+ else {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters, '', '&'));
+ }
+ }
+ curl_setopt($ch, CURLOPT_HTTPHEADER, static::formatHeaders($this->headers));
+
+ // Submit the request to the PayPal server.
+ $this->logMessage(sprintf('Request URL: %s', $url));
+ curl_setopt($ch, CURLOPT_URL, $url);
+ $response = curl_exec($ch);
+
+ // Ensure we got a successful response by inspecting the HTTP status code.
+ $response_info = curl_getinfo($ch);
+
+ if (is_resource($ch)) {
+ curl_close($ch);
+ }
+
+ if ($response_info['http_code'] == 401) {
+ // Attempt to get a new access token if the authentication failed.
+ // This might happen if we're sending an expired access token to PayPal.
+ if ($this->retryCount < static::RETRY_LIMIT) {
+ $this->retryCount++;
+ // Ensure we get a fresh access token next time.
+ variable_del('commerce_paypal_checkout_access_token');
+ return $this->submitRequest($method, $path, $parameters);
+ }
+
+ $json = drupal_json_decode($response);
+ // Throw an exception indicating authentication failed.
+ $message = 'Authentication failed.';
+ if (isset($json['error_description'])) {
+ $message = sprintf('Error description: %s.', $json['error_description']);
+ }
+ throw new PayPalCheckoutAuthenticationException($message);
+ }
+ elseif ($response_info['http_code'] >= 500) {
+ // Throw an exception indicating a server error.
+ throw new PayPalCheckoutHttpServerErrorException('', $response_info['http_code']);
+ }
+ elseif ($response_info['http_code'] >= 400) {
+ // Throw an exception indicating a client error.
+ throw new PayPalCheckoutHttpClientErrorException('', $response_info['http_code']);
+ }
+ elseif ($response_info['http_code'] >= 300) {
+ // Throw an exception indicating a redirection that this library is not
+ // going to automatically follow.
+ throw new PayPalCheckoutHttpRedirectionException('', $response_info['http_code']);
+ }
+
+ // Attempt to convert the response body to an associative array.
+ try {
+ $json = drupal_json_decode($response);
+ }
+ catch (\Exception $e) {
+ throw new PayPalCheckoutInvalidResponseJsonException('The API response string could not be parsed as JSON.');
+ }
+
+ return $json;
+ }
+
+ protected static function formatHeaders(array $headers) {
+ $http_headers = array();
+ foreach ($headers as $key => $value) {
+ $http_headers[] = "$key: $value";
+ }
+ return $http_headers;
+ }
+
+}
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutExceptions.php b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutExceptions.php
new file mode 100644
index 000000000..5006d9d69
--- /dev/null
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/checkout/lib/PayPalCheckoutExceptions.php
@@ -0,0 +1,40 @@
+data['commerce_paypal_ec']['parenttransactionid'] = $transaction->remote_id;
}
+ // Check if there is an error code in the response.
+ if (!empty($response['L_ERRORCODE0'])) {
+ // Log the error in a payment transaction.
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ $transaction->remote_status = '';
+ $message = array();
+ $message[] = '' . t('Payment failed') . '';
+ $message[] = t('Error @code: @message', array('@code' => $response['L_ERRORCODE0'], '@message' => $response['L_SHORTMESSAGE0']));
+ $transaction->message = implode('
', $message);
+ commerce_payment_transaction_save($transaction);
+
+ // If the response error indicates a funding failure, redirect the customer
+ // back to PayPal for another attempt.
+ // @see: https://developer.paypal.com/docs/classic/express-checkout/ht_ec_fundingfailure10486/
+ if ($response['L_ERRORCODE0'] === '10486') {
+ // Log the error in watchdog.
+ watchdog('commerce_paypal_ec', 'PayPal Express Checkout transaction funding failed for order @order_number. Redirecting the user back to PayPal.', array('@order_number' => $order->order_number), WATCHDOG_NOTICE);
+ // Update order.
+ commerce_order_status_update($order, 'checkout_payment', FALSE, NULL, t('Customer payment transaction funding failed. Redirecting customer back to the PayPal Express Checkout page.'));
+ // Redirect the user back to PayPal.
+ drupal_goto(commerce_paypal_ec_checkout_url($payment_method['settings']['server'], $order->data['commerce_paypal_ec']['token']));
+ }
+
+ // Log the error in watchdog.
+ watchdog('commerce_paypal_ec', 'PayPal Express Checkout transaction failed for order @order_number.', array('@order_number' => $order->order_number), WATCHDOG_ERROR);
+
+ return FALSE;
+ }
+
// If we received an unknown response status...
if (!isset($response['PAYMENTINFO_0_PAYMENTSTATUS']) || !in_array($response['PAYMENTINFO_0_PAYMENTSTATUS'], array('Failed', 'Voided', 'Pending', 'Completed', 'Refunded'))) {
// Display an error message and remain on the same page.
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info b/www7/sites/all/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
index 9b1ce3718..954e25c0b 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
@@ -11,8 +11,8 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2018-10-22
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2019-05-06
+version = "7.x-2.7"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1540244884"
+datestamp = "1557130694"
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info b/www7/sites/all/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
index 5651b4993..ee8da4976 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
@@ -11,8 +11,8 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2018-10-22
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2019-05-06
+version = "7.x-2.7"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1540244884"
+datestamp = "1557130694"
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info b/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
index e79cb283b..7711fd3e4 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
@@ -11,8 +11,8 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2018-10-22
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2019-05-06
+version = "7.x-2.7"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1540244884"
+datestamp = "1557130694"
diff --git a/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module b/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
index 818e42893..021358ef2 100644
--- a/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
+++ b/www7/sites/all/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
@@ -545,26 +545,213 @@ function commerce_paypal_wps_server_url($server) {
function commerce_paypal_wps_languages() {
return array(
t('By country') => array(
+ 'AL' => t('Albania'),
+ 'DZ' => t('Algeria'),
+ 'AD' => t('Andorra'),
+ 'AO' => t('Angola'),
+ 'AI' => t('Anguilla'),
+ 'AG' => t('Antigua and Barbuda'),
+ 'AR' => t('Argentina'),
+ 'AM' => t('Armenia'),
+ 'AW' => t('Aruba'),
'AU' => t('Australia'),
'AT' => t('Austria'),
+ 'AZ' => t('Azerbaijan Republic'),
+ 'BS' => t('Bahamas'),
+ 'BH' => t('Bahrain'),
+ 'BB' => t('Barbados'),
+ 'BY' => t('Belarus'),
'BE' => t('Belgium'),
+ 'BZ' => t('Belize'),
+ 'BJ' => t('Benin'),
+ 'BM' => t('Bermuda'),
+ 'BT' => t('Bhutan'),
+ 'BO' => t('Bolivia'),
+ 'BA' => t('Bosnia and Herzegovina'),
+ 'BW' => t('Botswana'),
'BR' => t('Brazil'),
+ 'BN' => t('Brunei'),
+ 'BG' => t('Bulgaria'),
+ 'BF' => t('Burkina Faso'),
+ 'BI' => t('Burundi'),
+ 'KH' => t('Cambodia'),
+ 'CM' => t('Cameroon'),
'CA' => t('Canada'),
- 'CN' => t('China'),
+ 'CV' => t('Cape Verde'),
+ 'KY' => t('Cayman Islands'),
+ 'TD' => t('Chad'),
+ 'CL' => t('Chile'),
+ 'C2' => t('China'),
+ 'CO' => t('Colombia'),
+ 'KM' => t('Comoros'),
+ 'CK' => t('Cook Islands'),
+ 'CR' => t('Costa Rica'),
+ 'CI' => t('Cote D\'Ivoire'),
+ 'HR' => t('Croatia'),
+ 'CY' => t('Cyprus'),
+ 'CZ' => t('Czech Republic'),
+ 'CD' => t('Democratic Republic of the Congo'),
+ 'DK' => t('Denmark'),
+ 'DJ' => t('Djibouti'),
+ 'DM' => t('Dominica'),
+ 'DO' => t('Dominican Republic'),
+ 'EC' => t('Ecuador'),
+ 'EG' => t('Egypt'),
+ 'SV' => t('El Salvador'),
+ 'ER' => t('Eritrea'),
+ 'EE' => t('Estonia'),
+ 'ET' => t('Ethiopia'),
+ 'FK' => t('Falkland Islands'),
+ 'FO' => t('Faroe Islands'),
+ 'FJ' => t('Fiji'),
+ 'FI' => t('Finland'),
'FR' => t('France'),
+ 'GF' => t('French Guiana'),
+ 'PF' => t('French Polynesia'),
+ 'GA' => t('Gabon Republic'),
+ 'GM' => t('Gambia'),
+ 'GE' => t('Georgia'),
'DE' => t('Germany'),
+ 'GI' => t('Gibraltar'),
+ 'GR' => t('Greece'),
+ 'GL' => t('Greenland'),
+ 'GD' => t('Grenada'),
+ 'GP' => t('Guadeloupe'),
+ 'GT' => t('Guatemala'),
+ 'GN' => t('Guinea'),
+ 'GW' => t('Guinea Bissau'),
+ 'GY' => t('Guyana'),
+ 'HN' => t('Honduras'),
+ 'HK' => t('Hong Kong'),
+ 'HU' => t('Hungary'),
+ 'IS' => t('Iceland'),
+ 'IN' => t('India'),
+ 'ID' => t('Indonesia'),
+ 'IE' => t('Ireland'),
+ 'IL' => t('Israel'),
'IT' => t('Italy'),
+ 'JM' => t('Jamaica'),
+ 'JP' => t('Japan'),
+ 'JO' => t('Jordan'),
+ 'KZ' => t('Kazakhstan'),
+ 'KE' => t('Kenya'),
+ 'KI' => t('Kiribati'),
+ 'KW' => t('Kuwait'),
+ 'KG' => t('Kyrgyzstan'),
+ 'LA' => t('Laos'),
+ 'LV' => t('Latvia'),
+ 'LS' => t('Lesotho'),
+ 'LI' => t('Liechtenstein'),
+ 'LT' => t('Lithuania'),
+ 'LU' => t('Luxembourg'),
+ 'MK' => t('Macedonia'),
+ 'MG' => t('Madagascar'),
+ 'MW' => t('Malawi'),
+ 'MY' => t('Malaysia'),
+ 'MV' => t('Maldives'),
+ 'ML' => t('Mali'),
+ 'MT' => t('Malta'),
+ 'MH' => t('Marshall Islands'),
+ 'MQ' => t('Martinique'),
+ 'MR' => t('Mauritania'),
+ 'MU' => t('Mauritius'),
+ 'YT' => t('Mayotte'),
+ 'MX' => t('Mexico'),
+ 'FM' => t('Micronesia'),
+ 'MD' => t('Moldova'),
+ 'MC' => t('Monaco'),
+ 'MN' => t('Mongolia'),
+ 'ME' => t('Montenegro'),
+ 'MS' => t('Montserrat'),
+ 'MA' => t('Morocco'),
+ 'MZ' => t('Mozambique'),
+ 'NA' => t('Namibia'),
+ 'NR' => t('Nauru'),
+ 'NP' => t('Nepal'),
'NL' => t('Netherlands'),
+ 'AN' => t('Netherlands Antilles'),
+ 'NC' => t('New Caledonia'),
+ 'NZ' => t('New Zealand'),
+ 'NI' => t('Nicaragua'),
+ 'NE' => t('Niger'),
+ 'NG' => t('Nigeria'),
+ 'NU' => t('Niue'),
+ 'NF' => t('Norfolk Island'),
+ 'NO' => t('Norway'),
+ 'OM' => t('Oman'),
+ 'PW' => t('Palau'),
+ 'PA' => t('Panama'),
+ 'PG' => t('Papua New Guinea'),
+ 'PY' => t('Paraguay'),
+ 'PE' => t('Peru'),
+ 'PH' => t('Philippines'),
+ 'PN' => t('Pitcairn Islands'),
'PL' => t('Poland'),
'PT' => t('Portugal'),
+ 'QA' => t('Qatar'),
+ 'CG' => t('Republic of the Congo'),
+ 'RE' => t('Reunion'),
+ 'RO' => t('Romania'),
'RU' => t('Russia'),
+ 'RW' => t('Rwanda'),
+ 'KN' => t('Saint Kitts and Nevis Anguilla'),
+ 'PM' => t('Saint Pierre and Miquelon'),
+ 'VC' => t('Saint Vincent and Grenadines'),
+ 'WS' => t('Samoa'),
+ 'SM' => t('San Marino'),
+ 'ST' => t('São Tomé and PrÃncipe'),
+ 'SA' => t('Saudi Arabia'),
+ 'SN' => t('Senegal'),
+ 'RS' => t('Serbia'),
+ 'SC' => t('Seychelles'),
+ 'SL' => t('Sierra Leone'),
+ 'SG' => t('Singapore'),
+ 'SK' => t('Slovakia'),
+ 'SI' => t('Slovenia'),
+ 'SB' => t('Solomon Islands'),
+ 'SO' => t('Somalia'),
+ 'ZA' => t('South Africa'),
+ 'KR' => t('South Korea'),
'ES' => t('Spain'),
+ 'LK' => t('Sri Lanka'),
+ 'SH' => t('St. Helena'),
+ 'LC' => t('St. Lucia'),
+ 'SR' => t('Suriname'),
+ 'SJ' => t('Svalbard and Jan Mayen Islands'),
+ 'SZ' => t('Swaziland'),
+ 'SE' => t('Sweden'),
'CH' => t('Switzerland'),
+ 'TW' => t('Taiwan'),
+ 'TJ' => t('Tajikistan'),
+ 'TZ' => t('Tanzania'),
+ 'TH' => t('Thailand'),
+ 'TG' => t('Togo'),
+ 'TO' => t('Tonga'),
+ 'TT' => t('Trinidad and Tobago'),
+ 'TN' => t('Tunisia'),
+ 'TR' => t('Turkey'),
+ 'TM' => t('Turkmenistan'),
+ 'TC' => t('Turks and Caicos Islands'),
+ 'TV' => t('Tuvalu'),
+ 'UG' => t('Uganda'),
+ 'UA' => t('Ukraine'),
+ 'AE' => t('United Arab Emirates'),
'GB' => t('United Kingdom'),
'US' => t('United States'),
+ 'UY' => t('Uruguay'),
+ 'VU' => t('Vanuatu'),
+ 'VA' => t('Vatican City State'),
+ 'VE' => t('Venezuela'),
+ 'VN' => t('Vietnam'),
+ 'VG' => t('Virgin Islands (British)'),
+ 'WF' => t('Wallis and Futuna Islands'),
+ 'YE' => t('Yemen'),
+ 'ZM' => t('Zambia'),
+ 'ZW' => t('Zimbabwe'),
),
t('By language') => array(
'da_DK' => t('Danish (for Denmark only)'),
+ 'fr_CA' => t('French (for Canada only)'),
'he_IL' => t('Hebrew (for all)'),
'id_ID' => t('Indonesian (for Indonesia only)'),
'jp_JP' => t('Japanese (for Japan only)'),
diff --git a/www7/sites/all/modules/contrib/context/context.info b/www7/sites/all/modules/contrib/context/context.info
index 905805676..eef3a9c10 100644
--- a/www7/sites/all/modules/contrib/context/context.info
+++ b/www7/sites/all/modules/contrib/context/context.info
@@ -8,8 +8,8 @@ files[] = tests/context.test
files[] = tests/context.conditions.test
files[] = tests/context.reactions.test
-; Information added by Drupal.org packaging script on 2018-11-30
-version = "7.x-3.9"
+; Information added by Drupal.org packaging script on 2019-02-26
+version = "7.x-3.10"
core = "7.x"
project = "context"
-datestamp = "1543594688"
+datestamp = "1551220089"
diff --git a/www7/sites/all/modules/contrib/context/context_layouts/context_layouts.info b/www7/sites/all/modules/contrib/context/context_layouts/context_layouts.info
index 5bd844f0c..65880e389 100644
--- a/www7/sites/all/modules/contrib/context/context_layouts/context_layouts.info
+++ b/www7/sites/all/modules/contrib/context/context_layouts/context_layouts.info
@@ -6,8 +6,8 @@ core = 7.x
files[] = plugins/context_layouts_reaction_block.inc
-; Information added by Drupal.org packaging script on 2018-11-30
-version = "7.x-3.9"
+; Information added by Drupal.org packaging script on 2019-02-26
+version = "7.x-3.10"
core = "7.x"
project = "context"
-datestamp = "1543594688"
+datestamp = "1551220089"
diff --git a/www7/sites/all/modules/contrib/context/context_ui/context_ui.info b/www7/sites/all/modules/contrib/context/context_ui/context_ui.info
index b17a8e704..e5d17f8fc 100644
--- a/www7/sites/all/modules/contrib/context/context_ui/context_ui.info
+++ b/www7/sites/all/modules/contrib/context/context_ui/context_ui.info
@@ -8,8 +8,8 @@ configure = admin/structure/context
files[] = context.module
files[] = tests/context_ui.test
-; Information added by Drupal.org packaging script on 2018-11-30
-version = "7.x-3.9"
+; Information added by Drupal.org packaging script on 2019-02-26
+version = "7.x-3.10"
core = "7.x"
project = "context"
-datestamp = "1543594688"
+datestamp = "1551220089"
diff --git a/www7/sites/all/modules/contrib/context/plugins/context_reaction_block.js b/www7/sites/all/modules/contrib/context/plugins/context_reaction_block.js
index fb0f3f162..192b956ff 100644
--- a/www7/sites/all/modules/contrib/context/plugins/context_reaction_block.js
+++ b/www7/sites/all/modules/contrib/context/plugins/context_reaction_block.js
@@ -68,7 +68,7 @@ DrupalContextBlockForm = function(blockForm) {
// Hide enabled blocks from selector that are used
$('table.context-blockform-region tr').each(function() {
- var bid = $(this).attr('id');
+ var bid = Drupal.checkPlain($(this).attr('id'));
$('div.context-blockform-selector input[value="'+bid+'"]').parents('div.form-item').eq(0).hide();
});
// Show blocks in selector that are unused
diff --git a/www7/sites/all/modules/contrib/ctools/bulk_export/bulk_export.info b/www7/sites/all/modules/contrib/ctools/bulk_export/bulk_export.info
index 388cd6f73..9bb339445 100644
--- a/www7/sites/all/modules/contrib/ctools/bulk_export/bulk_export.info
+++ b/www7/sites/all/modules/contrib/ctools/bulk_export/bulk_export.info
@@ -3,11 +3,9 @@ description = Performs bulk exporting of data objects known about by Chaos tools
core = 7.x
dependencies[] = ctools
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/css/dropbutton.css b/www7/sites/all/modules/contrib/ctools/css/dropbutton.css
index 376fc674d..486ac3eda 100644
--- a/www7/sites/all/modules/contrib/ctools/css/dropbutton.css
+++ b/www7/sites/all/modules/contrib/ctools/css/dropbutton.css
@@ -19,7 +19,6 @@
height: auto;
position: absolute;
right: 0;
- text-indent: -9999px; /* LTR */
top: 0;
width: 17px;
}
@@ -50,6 +49,7 @@
right: 6px;
position: absolute;
top: 0.75em;
+ white-space: nowrap;
}
.ctools-dropbutton-processed.open .ctools-twisty {
diff --git a/www7/sites/all/modules/contrib/ctools/ctools.info b/www7/sites/all/modules/contrib/ctools/ctools.info
index c9d0c63a5..188b55dde 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools.info
+++ b/www7/sites/all/modules/contrib/ctools/ctools.info
@@ -19,9 +19,8 @@ files[] = tests/object_cache.test
files[] = tests/object_cache_unit.test
files[] = tests/page_tokens.test
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/ctools.module b/www7/sites/all/modules/contrib/ctools/ctools.module
index 3a805808b..62f291923 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools.module
+++ b/www7/sites/all/modules/contrib/ctools/ctools.module
@@ -22,6 +22,9 @@ define('CTOOLS_API_VERSION', '2.0.9');
* simply include a dependency line in that module's info file, e.g.:
* ; Requires CTools v7.x-1.4 or newer.
* dependencies[] = ctools (>=1.4)
+ *
+ * @deprecated in CTools 1.15 and will be removed before CTools 2.0.0.
+ * Use the version provided by the drupal.org packaging system.
*/
define('CTOOLS_MODULE_VERSION', '7.x-1.13');
diff --git a/www7/sites/all/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info b/www7/sites/all/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
index 84a922fb5..3fc355649 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
+++ b/www7/sites/all/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
@@ -2,12 +2,10 @@ name = Custom rulesets
description = Create custom, exportable, reusable access rulesets for applications like Panels.
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info b/www7/sites/all/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
index 4bb8943cd..c2a52df40 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
+++ b/www7/sites/all/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
@@ -1,13 +1,11 @@
name = Chaos Tools (CTools) AJAX Example
description = Shows how to use the power of Chaos AJAX.
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
core = 7.x
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info b/www7/sites/all/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
index 637bf25d5..2bc73489c 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
+++ b/www7/sites/all/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
@@ -2,12 +2,10 @@ name = Custom content panes
description = Create custom, exportable, reusable content panes for applications like Panels.
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info b/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
index 40f133bc8..3f268dbc0 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
+++ b/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
@@ -1,16 +1,14 @@
name = Chaos Tools (CTools) Plugin Example
description = Shows how an external module can provide ctools plugins (for Panels, etc.).
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
dependencies[] = panels
dependencies[] = page_manager
dependencies[] = advanced_help
core = 7.x
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc b/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
index bbabf2271..ed3ffd776 100644
--- a/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
+++ b/www7/sites/all/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
@@ -95,6 +95,7 @@ function ctools_plugin_example_default_page_manager_pages() {
'access' => array(
'logic' => 'and',
),
+ 'pipeline' => 'standard',
);
$display = new panels_display();
$display->layout = 'threecol_33_34_33_stacked';
@@ -154,7 +155,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->configuration = array(
'title' => 'Long Arg Visibility Block',
'body' => 'This block will be here when the argument is longer than configured arg length. It uses the \'arg_length\' access plugin to test against the length of the argument used for Simplecontext.',
- 'format' => '1',
+ 'format' => 'filtered_html',
'substitute' => 1,
);
$pane->cache = array();
@@ -185,7 +186,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->configuration = array(
'title' => 'Short Arg Visibility',
'body' => 'This block appears when the simplecontext argument is less than the configured length.',
- 'format' => '1',
+ 'format' => 'filtered_html',
'substitute' => 1,
);
$pane->cache = array();
@@ -297,7 +298,7 @@ function ctools_plugin_example_default_page_manager_pages() {
item1 is %sc:item1
item2 is %sc:item2
description is %sc:description',
- 'format' => '1',
+ 'format' => 'filtered_html',
'substitute' => 1,
);
$pane->cache = array();
@@ -363,7 +364,7 @@ function ctools_plugin_example_default_page_manager_pages() {
'body' => 'The CTools Plugin Example module (and this panel page) are just here to demonstrate how to build CTools plugins.
',
- 'format' => '2',
+ 'format' => 'full_html',
'substitute' => 1,
);
$pane->cache = array();
@@ -408,6 +409,7 @@ function ctools_plugin_example_default_page_manager_pages() {
'css' => '',
'contexts' => array(),
'relationships' => array(),
+ 'pipeline' => 'standard',
);
$display = new panels_display();
$display->layout = 'onecol';
@@ -428,7 +430,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->configuration = array(
'title' => 'Use this page with an argument',
'body' => 'This demo page works if you use an argument, like ctools_plugin_example/xxxxx.',
- 'format' => '1',
+ 'format' => 'filtered_html',
'substitute' => NULL,
);
$pane->cache = array();
diff --git a/www7/sites/all/modules/contrib/ctools/drush/ctools.drush.inc b/www7/sites/all/modules/contrib/ctools/drush/ctools.drush.inc
index 3677b1712..34fd4d3a5 100644
--- a/www7/sites/all/modules/contrib/ctools/drush/ctools.drush.inc
+++ b/www7/sites/all/modules/contrib/ctools/drush/ctools.drush.inc
@@ -452,6 +452,7 @@ function ctools_drush_export_info() {
* all arg handling etc in one place.
*/
function ctools_drush_export_op_command() {
+ $args = func_get_args();
// Get all info for the current drush command.
$command = drush_get_command();
$op = '';
@@ -495,7 +496,6 @@ function ctools_drush_export_op_command() {
}
}
else {
- $args = func_get_args();
// Table name should always be first arg...
$table_name = array_shift($args);
// Any additional args are assumed to be exportable names.
diff --git a/www7/sites/all/modules/contrib/ctools/includes/dropbutton.theme.inc b/www7/sites/all/modules/contrib/ctools/includes/dropbutton.theme.inc
index d69c98831..4b95ef0df 100644
--- a/www7/sites/all/modules/contrib/ctools/includes/dropbutton.theme.inc
+++ b/www7/sites/all/modules/contrib/ctools/includes/dropbutton.theme.inc
@@ -104,10 +104,10 @@ function theme_links__ctools_dropbutton($vars) {
$output .= '';
diff --git a/www7/sites/all/modules/contrib/ctools/includes/export-ui.inc b/www7/sites/all/modules/contrib/ctools/includes/export-ui.inc
index 1eb87ae77..72e5a2fdf 100644
--- a/www7/sites/all/modules/contrib/ctools/includes/export-ui.inc
+++ b/www7/sites/all/modules/contrib/ctools/includes/export-ui.inc
@@ -333,7 +333,7 @@ function ctools_export_ui_process(&$plugin, $info) {
$plugin['strings']['confirmation']['delete'] += array(
'question' => t('Are you sure you want to delete %title?'),
- 'information' => t('This action will permanently remove this item from your database..'),
+ 'information' => t('This action will permanently remove this item from your database.'),
'success' => t('The item has been deleted.'),
);
diff --git a/www7/sites/all/modules/contrib/ctools/includes/wizard.inc b/www7/sites/all/modules/contrib/ctools/includes/wizard.inc
index 8b0d061c4..e0b8fbd14 100644
--- a/www7/sites/all/modules/contrib/ctools/includes/wizard.inc
+++ b/www7/sites/all/modules/contrib/ctools/includes/wizard.inc
@@ -503,7 +503,7 @@ function ctools_wizard_defaults(&$form_info) {
$form_info = $form_info + $defaults;
// Set form callbacks if they aren't defined.
foreach ($form_info['forms'] as $step => $params) {
- if (!$params['form id']) {
+ if (empty($params['form id'])) {
$form_callback = $hook . '_' . $step . '_form';
$form_info['forms'][$step]['form id'] = $form_callback;
}
diff --git a/www7/sites/all/modules/contrib/ctools/js/modal.js b/www7/sites/all/modules/contrib/ctools/js/modal.js
index e65f51afa..ec7b02aea 100644
--- a/www7/sites/all/modules/contrib/ctools/js/modal.js
+++ b/www7/sites/all/modules/contrib/ctools/js/modal.js
@@ -378,7 +378,7 @@
}
}
- if (!speed) {
+ if (!speed && 0 !== speed) {
speed = 'fast';
}
@@ -555,7 +555,7 @@
// Create our content div, get the dimensions, and hide it
var modalContent = $('#modalContent').css('top','-1000px');
var $modalHeader = modalContent.find('.modal-header');
- var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2);
+ var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
$('#modalBackdrop').css(css).css('top', 0).css('height', docHeight + 'px').css('width', docWidth + 'px').show();
modalContent.css({top: mdcTop + 'px', left: mdcLeft + 'px'}).hide()[animation](speed);
@@ -588,35 +588,43 @@
$('body').unbind( 'keypress', modalEventHandler );
$('body').unbind( 'keydown', modalTabTrapHandler );
$('.close', $modalHeader).unbind('click', modalContentClose);
- $('body').unbind('keypress', modalEventEscapeCloseHandler);
+ $(document).unbind('keydown', modalEventEscapeCloseHandler);
$(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
- // Set our animation parameters and use them
- if ( animation == 'fadeIn' ) animation = 'fadeOut';
- if ( animation == 'slideDown' ) animation = 'slideUp';
- if ( animation == 'show' ) animation = 'hide';
+ // Closing animation.
+ switch (animation) {
+ case 'fadeIn':
+ modalContent.fadeOut(speed, modalContentRemove);
+ break;
- // Close the content
- modalContent.hide()[animation](speed);
+ case 'slideDown':
+ modalContent.slideUp(speed, modalContentRemove);
+ break;
- // Remove the content
+ case 'show':
+ modalContent.hide(speed, modalContentRemove);
+ break;
+ }
+ }
+
+ // Remove the content.
+ modalContentRemove = function () {
$('#modalContent').remove();
$('#modalBackdrop').remove();
- // Restore focus to where it was before opening the dialog
+ // Restore focus to where it was before opening the dialog.
$(oldFocus).focus();
};
// Move and resize the modalBackdrop and modalContent on window resize.
- modalContentResize = function(){
-
+ modalContentResize = function () {
// Reset the backdrop height/width to get accurate document size.
$('#modalBackdrop').css('height', '').css('width', '');
// Position code lifted from:
// http://www.quirksmode.org/viewport/compatibility.html
if (self.pageYOffset) { // all except Explorer
- var wt = self.pageYOffset;
+ var wt = self.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
var wt = document.documentElement.scrollTop;
} else if (document.body) { // all other Explorers
@@ -632,7 +640,7 @@
// Get where we should move content to
var modalContent = $('#modalContent');
- var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2);
+ var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
// Apply the changes
diff --git a/www7/sites/all/modules/contrib/ctools/page_manager/page_manager.info b/www7/sites/all/modules/contrib/ctools/page_manager/page_manager.info
index 586613851..a56663b8d 100644
--- a/www7/sites/all/modules/contrib/ctools/page_manager/page_manager.info
+++ b/www7/sites/all/modules/contrib/ctools/page_manager/page_manager.info
@@ -3,13 +3,11 @@ description = Provides a UI and API to manage pages within the site.
core = 7.x
dependencies[] = ctools
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
files[] = tests/head_links.test
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/page_manager/plugins/tasks/page.inc b/www7/sites/all/modules/contrib/ctools/page_manager/plugins/tasks/page.inc
index 8d24d3309..100dfd817 100644
--- a/www7/sites/all/modules/contrib/ctools/page_manager/plugins/tasks/page.inc
+++ b/www7/sites/all/modules/contrib/ctools/page_manager/plugins/tasks/page.inc
@@ -261,6 +261,7 @@ function page_manager_page_theme(&$items, $task) {
* creating named arguments in the path.
*/
function page_manager_page_execute($subtask_id) {
+ $func_args = func_get_args();
$page = page_manager_page_load($subtask_id);
$task = page_manager_get_task($page->task);
$subtask = page_manager_get_task_subtask($task, $subtask_id);
@@ -268,7 +269,7 @@ function page_manager_page_execute($subtask_id) {
// Turn the contexts into a properly keyed array.
$contexts = array();
$args = array();
- foreach (func_get_args() as $count => $arg) {
+ foreach ($func_args as $count => $arg) {
if (is_object($arg) && get_class($arg) == 'ctools_context') {
$contexts[$arg->id] = $arg;
$args[] = $arg->original_argument;
@@ -430,7 +431,7 @@ function page_manager_page_save(&$page) {
/**
* Remove a page subtask.
*/
-function page_manager_page_delete($page) {
+function page_manager_page_delete($page, $skip_menu_rebuild = FALSE) {
$task = page_manager_get_task($page->task);
if ($function = ctools_plugin_get_function($task, 'delete')) {
$function($page);
@@ -448,7 +449,11 @@ function page_manager_page_delete($page) {
// rebuild this page again.
ctools_include('export');
ctools_export_load_object_reset('page_manager_pages');
- menu_rebuild();
+ // Allow menu rebuild to be skipped when calling code is deleting multiple
+ // pages.
+ if (!$skip_menu_rebuild) {
+ menu_rebuild();
+ }
}
/**
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_attachments.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_attachments.inc
index c55e0752d..51c95a5e9 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_attachments.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_attachments.inc
@@ -21,7 +21,7 @@ if (module_exists('upload')) {
function ctools_node_form_attachments_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Attach files');
$block->delta = 'url-path-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_author.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_author.inc
index f9e937198..86f3d7314 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_author.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_author.inc
@@ -17,7 +17,7 @@ $plugin = array(
function ctools_node_form_author_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Authoring information');
$block->delta = 'author-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_book.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_book.inc
index af022bfd6..b7ad36bdf 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_book.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_book.inc
@@ -21,7 +21,7 @@ if (module_exists('book')) {
function ctools_node_form_book_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Book outline');
$block->delta = 'book-outline';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_buttons.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_buttons.inc
index 560a01e4f..ed553a67d 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_buttons.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_buttons.inc
@@ -17,7 +17,7 @@ $plugin = array(
function ctools_node_form_buttons_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = '';
$block->delta = 'buttons';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_comment.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_comment.inc
index 352681cc6..eaf5c954c 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_comment.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_comment.inc
@@ -21,7 +21,7 @@ if (module_exists('comment')) {
function ctools_node_form_comment_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Comment options');
$block->delta = 'comment-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_language.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_language.inc
index 76ab3f824..dfef295f5 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_language.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_language.inc
@@ -17,7 +17,7 @@ $plugin = array(
function ctools_node_form_language_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->delta = 'language-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_log.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_log.inc
index 329ea8990..aac42a645 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_log.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_log.inc
@@ -17,7 +17,7 @@ $plugin = array(
function ctools_node_form_log_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Revision information');
if (isset($context->form)) {
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_menu.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_menu.inc
index 576dcd438..9b4df4345 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_menu.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_menu.inc
@@ -21,7 +21,7 @@ if (module_exists('menu')) {
function ctools_node_form_menu_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('Menu options');
$block->delta = 'menu-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_path.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_path.inc
index 9aeeba00a..262851f0a 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_path.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_path.inc
@@ -21,7 +21,7 @@ if (module_exists('path')) {
function ctools_node_form_path_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->title = t('URL path options');
$block->delta = 'url-path-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_publishing.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_publishing.inc
index f8b92aec9..53b584f90 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_publishing.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_publishing.inc
@@ -23,7 +23,7 @@ function ctools_node_form_publishing_content_type_render($subtype, $conf, $panel
$block = new stdClass();
$block->title = t('Publishing options');
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->delta = 'publishing-options';
if (isset($context->form)) {
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_title.inc b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_title.inc
index 2f58ee309..14e79abae 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_title.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/content_types/node_form/node_form_title.inc
@@ -17,7 +17,7 @@ $plugin = array(
function ctools_node_form_title_content_type_render($subtype, $conf, $panel_args, &$context) {
$block = new stdClass();
- $block->module = t('node_form');
+ $block->module = 'node_form';
$block->delta = 'title-options';
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/contexts/user.inc b/www7/sites/all/modules/contrib/ctools/plugins/contexts/user.inc
index 362cfe3b1..bbdbd1a27 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/contexts/user.inc
+++ b/www7/sites/all/modules/contrib/ctools/plugins/contexts/user.inc
@@ -152,6 +152,7 @@ function ctools_context_user_settings_form_submit($form, &$form_state) {
*/
function ctools_context_user_convert_list() {
$tokens = token_info();
+ $list = array();
foreach ($tokens['tokens']['user'] as $id => $info) {
if (!isset($list[$id])) {
$list[$id] = $info['name'];
diff --git a/www7/sites/all/modules/contrib/ctools/plugins/export_ui/ctools_export_ui.class.php b/www7/sites/all/modules/contrib/ctools/plugins/export_ui/ctools_export_ui.class.php
index 3e1aed4ba..0c8145e4b 100644
--- a/www7/sites/all/modules/contrib/ctools/plugins/export_ui/ctools_export_ui.class.php
+++ b/www7/sites/all/modules/contrib/ctools/plugins/export_ui/ctools_export_ui.class.php
@@ -644,6 +644,7 @@ public function redirect($op, $item = NULL) {
}
public function add_page($js, $input, $step = NULL) {
+ $args = func_get_args();
drupal_set_title($this->get_page_title('add'), PASS_THROUGH);
// If a step not set, they are trying to create a new item. If a step
@@ -666,7 +667,7 @@ public function add_page($js, $input, $step = NULL) {
'no_redirect' => TRUE,
'step' => $step,
// Store these in case additional args are needed.
- 'function args' => func_get_args(),
+ 'function args' => $args,
);
$output = $this->edit_execute_form($form_state);
@@ -681,6 +682,7 @@ public function add_page($js, $input, $step = NULL) {
* Main entry point to edit an item.
*/
public function edit_page($js, $input, $item, $step = NULL) {
+ $args = func_get_args();
drupal_set_title($this->get_page_title('edit', $item), PASS_THROUGH);
// Check to see if there is a cached item to get if we're using the wizard.
@@ -702,7 +704,7 @@ public function edit_page($js, $input, $item, $step = NULL) {
'no_redirect' => TRUE,
'step' => $step,
// Store these in case additional args are needed.
- 'function args' => func_get_args(),
+ 'function args' => $args,
);
$output = $this->edit_execute_form($form_state);
@@ -717,6 +719,7 @@ public function edit_page($js, $input, $item, $step = NULL) {
* Main entry point to clone an item.
*/
public function clone_page($js, $input, $original, $step = NULL) {
+ $args = func_get_args();
drupal_set_title($this->get_page_title('clone', $original), PASS_THROUGH);
// If a step not set, they are trying to create a new clone. If a step
@@ -756,7 +759,7 @@ public function clone_page($js, $input, $original, $step = NULL) {
'no_redirect' => TRUE,
'step' => $step,
// Store these in case additional args are needed.
- 'function args' => func_get_args(),
+ 'function args' => $args,
);
$output = $this->edit_execute_form($form_state);
@@ -1237,6 +1240,7 @@ public function export_page($js, $input, $item) {
* Page callback to import information for an exportable item.
*/
public function import_page($js, $input, $step = NULL) {
+ $args = func_get_args();
drupal_set_title($this->get_page_title('import'), PASS_THROUGH);
// Import is basically a multi step wizard form, so let's go ahead and
// use CTools' wizard.inc for it.
@@ -1261,7 +1265,7 @@ public function import_page($js, $input, $step = NULL) {
'no_redirect' => TRUE,
'step' => $step,
// Store these in case additional args are needed.
- 'function args' => func_get_args(),
+ 'function args' => $args,
);
// import always uses the wizard.
diff --git a/www7/sites/all/modules/contrib/ctools/stylizer/stylizer.info b/www7/sites/all/modules/contrib/ctools/stylizer/stylizer.info
index f8b442e49..90204a3de 100644
--- a/www7/sites/all/modules/contrib/ctools/stylizer/stylizer.info
+++ b/www7/sites/all/modules/contrib/ctools/stylizer/stylizer.info
@@ -2,13 +2,11 @@ name = Stylizer
description = Create custom styles for applications such as Panels.
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
dependencies[] = color
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/term_depth/term_depth.info b/www7/sites/all/modules/contrib/ctools/term_depth/term_depth.info
index 326b2aef3..4baee51d8 100644
--- a/www7/sites/all/modules/contrib/ctools/term_depth/term_depth.info
+++ b/www7/sites/all/modules/contrib/ctools/term_depth/term_depth.info
@@ -3,11 +3,9 @@ description = Controls access to context based upon term depth
core = 7.x
dependencies[] = ctools
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/tests/ctools_export_test/ctools_export_test.info b/www7/sites/all/modules/contrib/ctools/tests/ctools_export_test/ctools_export_test.info
index 7abac58cb..a2d0efbd9 100644
--- a/www7/sites/all/modules/contrib/ctools/tests/ctools_export_test/ctools_export_test.info
+++ b/www7/sites/all/modules/contrib/ctools/tests/ctools_export_test/ctools_export_test.info
@@ -2,15 +2,13 @@ name = CTools export test
description = CTools export test module
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
hidden = TRUE
files[] = ctools_export.test
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/tests/ctools_plugin_test.info b/www7/sites/all/modules/contrib/ctools/tests/ctools_plugin_test.info
index 649e8912b..d51a52614 100644
--- a/www7/sites/all/modules/contrib/ctools/tests/ctools_plugin_test.info
+++ b/www7/sites/all/modules/contrib/ctools/tests/ctools_plugin_test.info
@@ -1,14 +1,12 @@
name = Chaos tools plugins test
description = Provides hooks for testing ctools plugins.
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
core = 7.x
dependencies[] = ctools
hidden = TRUE
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/ctools/views_content/plugins/relationships/node_from_view.inc b/www7/sites/all/modules/contrib/ctools/views_content/plugins/relationships/node_from_view.inc
index 0f3fa8e0a..f54cbc6b5 100644
--- a/www7/sites/all/modules/contrib/ctools/views_content/plugins/relationships/node_from_view.inc
+++ b/www7/sites/all/modules/contrib/ctools/views_content/plugins/relationships/node_from_view.inc
@@ -33,7 +33,7 @@ function views_content_node_from_view_context($context, $conf, $placeholder = FA
views_content_context_get_output($context);
$row = intval($conf['row']) - 1;
- if (isset($view->result[$row])) {
+ if (isset($view->result[$row]) && isset($view->base_field) && isset($view->result[$row]->{$view->base_field})) {
$nid = $view->result[$row]->{$view->base_field};
if ($nid) {
$node = node_load($nid);
diff --git a/www7/sites/all/modules/contrib/ctools/views_content/views_content.info b/www7/sites/all/modules/contrib/ctools/views_content/views_content.info
index 254d474b8..68f4d8756 100644
--- a/www7/sites/all/modules/contrib/ctools/views_content/views_content.info
+++ b/www7/sites/all/modules/contrib/ctools/views_content/views_content.info
@@ -5,14 +5,12 @@ dependencies[] = ctools
dependencies[] = views
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
files[] = plugins/views/views_content_plugin_display_ctools_context.inc
files[] = plugins/views/views_content_plugin_display_panel_pane.inc
files[] = plugins/views/views_content_plugin_style_ctools_context.inc
-; Information added by Drupal.org packaging script on 2018-02-24
-version = "7.x-1.14"
+; Information added by Drupal.org packaging script on 2019-02-08
+version = "7.x-1.15"
core = "7.x"
project = "ctools"
-datestamp = "1519455788"
-
+datestamp = "1549603691"
diff --git a/www7/sites/all/modules/contrib/link/link.info b/www7/sites/all/modules/contrib/link/link.info
index 06377f758..351e1782b 100644
--- a/www7/sites/all/modules/contrib/link/link.info
+++ b/www7/sites/all/modules/contrib/link/link.info
@@ -18,8 +18,8 @@ files[] = tests/link.validate.test
files[] = views/link_views_handler_argument_target.inc
files[] = views/link_views_handler_filter_protocol.inc
-; Information added by Drupal.org packaging script on 2018-05-13
-version = "7.x-1.5"
+; Information added by Drupal.org packaging script on 2019-02-20
+version = "7.x-1.6"
core = "7.x"
project = "link"
-datestamp = "1526190487"
+datestamp = "1550680687"
diff --git a/www7/sites/all/modules/contrib/link/link.module b/www7/sites/all/modules/contrib/link/link.module
index 059ec4347..8b3094f36 100644
--- a/www7/sites/all/modules/contrib/link/link.module
+++ b/www7/sites/all/modules/contrib/link/link.module
@@ -315,6 +315,16 @@ function link_field_validate($entity_type, $entity, $field, $instance, $langcode
}
}
+ foreach ($items as $delta => $value) {
+ if (isset($value['attributes']) && is_string($value['attributes'])) {
+ $errors[$field['field_name']][$langcode][$delta][] = array(
+ 'error' => 'link_required',
+ 'message' => t('String values are not acceptable for attributes.'),
+ 'error_element' => array('url' => TRUE, 'title' => FALSE),
+ );
+ }
+ }
+
if ($instance['settings']['url'] === 'optional' && $instance['settings']['title'] === 'optional' && $instance['required'] && !$optional_field_found) {
$errors[$field['field_name']][$langcode][0][] = array(
'error' => 'link_required',
diff --git a/www7/sites/all/modules/contrib/module_filter/js/module_filter_tab.js b/www7/sites/all/modules/contrib/module_filter/js/module_filter_tab.js
index 967eca603..c62b9ef64 100644
--- a/www7/sites/all/modules/contrib/module_filter/js/module_filter_tab.js
+++ b/www7/sites/all/modules/contrib/module_filter/js/module_filter_tab.js
@@ -57,7 +57,7 @@ Drupal.behaviors.moduleFilterTabs = {
// Build tabs from package title rows.
var tabs = '