updated core to 7.67

This commit is contained in:
Bachir Soussi Chiadmi 2019-07-09 11:56:03 +02:00
parent aa5c4a5a74
commit cc3b64a193
175 changed files with 2420 additions and 428 deletions

View File

@ -1,3 +1,29 @@
Drupal 7.xx, xxxx-xx-xx (development version)
-----------------------
Drupal 7.67, 2019-05-08
-----------------------
- Fixed security issues:
- SA-CORE-2019-007
Drupal 7.66, 2019-04-17
-----------------------
- Fixed security issues:
- SA-CORE-2019-006
Drupal 7.65, 2019-03-20
-----------------------
- Fixed security issues:
- SA-CORE-2019-004
Drupal 7.64, 2019-02-06
-----------------------
- [regression] Unset the 'host' header in drupal_http_request() during redirect
- Fixed: 7.x does not have Phar protection and Phar tests are failing on Drupal 7
- Fixed: Notice: Undefined index: display_field in file_field_widget_value() (line 582 of /module/file/file.field.inc)
- Performance improvement: Registry rebuild should not parse the same file twice in the same request
- Fixed _registry_update() to clear caches after transaction is committed
Drupal 7.63, 2019-01-16
-----------------------
- Fixed a fatal error for some Drush users introduced by SA-CORE-2019-002.

View File

@ -8,7 +8,7 @@
/**
* The current system version.
*/
define('VERSION', '7.63');
define('VERSION', '7.67');
/**
* Core API compatibility.

View File

@ -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;
}

View File

@ -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',

View File

@ -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.

View File

@ -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) {

View File

@ -0,0 +1,4 @@
/vendor/
/phpunit.xml
/.composer.lock

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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"
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Brumann\Polyfill Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,58 @@
<?php
namespace Brumann\Polyfill;
final class Unserialize
{
/**
* @see https://secure.php.net/manual/en/function.unserialize.php
*
* @param string $serialized Serialized data
* @param array $options Associative array containing options
*
* @return mixed
*/
public static function unserialize($serialized, array $options = array())
{
if (PHP_VERSION_ID >= 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);
}
}

112
misc/jquery-extend-3.4.0.js Normal file
View File

@ -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);

View File

@ -0,0 +1,3 @@
.idea
vendor/
composer.lock

View File

@ -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`.

View File

@ -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": {

View File

@ -0,0 +1,37 @@
<?php
namespace TYPO3\PharStreamWrapper;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Resolver\PharInvocation;
interface Collectable
{
/**
* @param PharInvocation $invocation
* @return bool
*/
public function has(PharInvocation $invocation);
/**
* @param PharInvocation $invocation
* @param null $flags
* @return bool
*/
public function collect(PharInvocation $invocation, $flags = null);
/**
* @param callable $callback
* @param bool $reverse
* @return null|PharInvocation
*/
public function findByCallback($callback, $reverse = false);
}

View File

@ -11,6 +11,13 @@ namespace TYPO3\PharStreamWrapper;
* The TYPO3 project - inspiring people to share!
*/
/**
* Helper provides low-level tools on file name resolving. However it does not
* (and should not) maintain any runtime state information. In order to resolve
* Phar archive paths according resolvers have to be used.
*
* @see \TYPO3\PharStreamWrapper\Resolvable::resolve()
*/
class Helper
{
/*
@ -54,6 +61,15 @@ class Helper
return null;
}
/**
* @param string $path
* @return bool
*/
public static function hasPharPrefix($path)
{
return stripos($path, 'phar://') === 0;
}
/**
* @param string $path
* @return string
@ -61,7 +77,7 @@ class Helper
public static function removePharPrefix($path)
{
$path = trim($path);
if (stripos($path, 'phar://') !== 0) {
if (!static::hasPharPrefix($path)) {
return $path;
}
return substr($path, 7);
@ -77,7 +93,7 @@ class Helper
public static function normalizePath($path)
{
return rtrim(
static::getCanonicalPath(
static::normalizeWindowsPath(
static::removePharPrefix($path)
),
'/'

View File

@ -0,0 +1,88 @@
<?php
namespace TYPO3\PharStreamWrapper\Interceptor;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Assertable;
use TYPO3\PharStreamWrapper\Exception;
class ConjunctionInterceptor implements Assertable
{
/**
* @var Assertable[]
*/
private $assertions;
public function __construct(array $assertions)
{
$this->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;
}
}

View File

@ -12,8 +12,8 @@ namespace TYPO3\PharStreamWrapper\Interceptor;
*/
use TYPO3\PharStreamWrapper\Assertable;
use TYPO3\PharStreamWrapper\Helper;
use TYPO3\PharStreamWrapper\Exception;
use TYPO3\PharStreamWrapper\Manager;
class PharExtensionInterceptor implements Assertable
{
@ -45,11 +45,11 @@ class PharExtensionInterceptor implements Assertable
*/
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';
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace TYPO3\PharStreamWrapper\Interceptor;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Assertable;
use TYPO3\PharStreamWrapper\Exception;
use TYPO3\PharStreamWrapper\Manager;
use TYPO3\PharStreamWrapper\Phar\DeserializationException;
use TYPO3\PharStreamWrapper\Phar\Reader;
/**
* @internal Experimental implementation of checking against serialized objects in Phar meta-data
* @internal This functionality has not been 100% pentested...
*/
class PharMetaDataInterceptor implements Assertable
{
/**
* Determines whether the according Phar archive contains
* (potential insecure) serialized objects.
*
* @param string $path
* @param string $command
* @return bool
* @throws Exception
*/
public function assert($path, $command)
{
if ($this->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;
}
}

View File

@ -11,7 +11,11 @@ namespace TYPO3\PharStreamWrapper;
* 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 @@ class Manager implements Assertable
/**
* @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 @@ class Manager implements Assertable
{
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;
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
class Container
{
/**
* @var Stub
*/
private $stub;
/**
* @var Manifest
*/
private $manifest;
/**
* @param Stub $stub
* @param Manifest $manifest
*/
public function __construct(Stub $stub, Manifest $manifest)
{
$this->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();
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Exception;
class DeserializationException extends Exception
{
}

View File

@ -0,0 +1,176 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use Brumann\Polyfill\Unserialize;
class Manifest
{
/**
* @param string $content
* @return self
* @see http://php.net/manual/en/phar.fileformat.phar.php
*/
public static function fromContent($content)
{
$target = new static();
$target->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;
}
}

View File

@ -0,0 +1,220 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
class Reader
{
/**
* @var string
*/
private $fileName;
/**
* @var string
*/
private $fileType;
/**
* @param string $fileName
*/
public function __construct($fileName)
{
if (strpos($fileName, '://') !== false) {
throw new ReaderException(
'File name must not contain stream prefix',
1539623708
);
}
$this->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];
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Exception;
class ReaderException extends Exception
{
}

View File

@ -0,0 +1,65 @@
<?php
namespace TYPO3\PharStreamWrapper\Phar;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
/**
* @internal Experimental implementation of Phar archive internals
*/
class Stub
{
/**
* @param string $content
* @return self
*/
public static function fromContent($content)
{
$target = new static();
$target->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;
}
}

View File

@ -11,6 +11,8 @@ namespace TYPO3\PharStreamWrapper;
* 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 @@ class PharStreamWrapper
*/
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 @@ class PharStreamWrapper
}
/**
* @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()
{

View File

@ -0,0 +1,24 @@
<?php
namespace TYPO3\PharStreamWrapper;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Resolver\PharInvocation;
interface Resolvable
{
/**
* @param string $path
* @param null|int $flags
* @return null|PharInvocation
*/
public function resolve($path, $flags = null);
}

View File

@ -0,0 +1,125 @@
<?php
namespace TYPO3\PharStreamWrapper\Resolver;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Exception;
class PharInvocation
{
/**
* @var string
*/
private $baseName;
/**
* @var string
*/
private $alias;
/**
* @var bool
* @see \TYPO3\PharStreamWrapper\PharStreamWrapper::collectInvocation()
*/
private $confirmed = false;
/**
* Arbitrary variables to be used by interceptors as registry
* (e.g. in order to avoid duplicate processing and assertions)
*
* @var array
*/
private $variables;
/**
* @param string $baseName
* @param string $alias
*/
public function __construct($baseName, $alias = '')
{
if ($baseName === '') {
throw new Exception(
'Base-name cannot be empty',
1551283689
);
}
$this->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;
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace TYPO3\PharStreamWrapper\Resolver;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Collectable;
class PharInvocationCollection implements Collectable
{
const UNIQUE_INVOCATION = 1;
const UNIQUE_BASE_NAME = 2;
const DUPLICATE_ALIAS_WARNING = 32;
/**
* @var PharInvocation[]
*/
private $invocations = array();
/**
* @param PharInvocation $invocation
* @return bool
*/
public function has(PharInvocation $invocation)
{
return in_array($invocation, $this->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;
}
}

View File

@ -0,0 +1,241 @@
<?php
namespace TYPO3\PharStreamWrapper\Resolver;
/*
* This file is part of the TYPO3 project.
*
* It is free software; you can redistribute it and/or modify it under the terms
* of the MIT License (MIT). For the full copyright and license information,
* please read the LICENSE file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\PharStreamWrapper\Helper;
use TYPO3\PharStreamWrapper\Manager;
use TYPO3\PharStreamWrapper\Phar\Reader;
use TYPO3\PharStreamWrapper\Resolvable;
class PharInvocationResolver implements Resolvable
{
const RESOLVE_REALPATH = 1;
const RESOLVE_ALIAS = 2;
const ASSERT_INTERNAL_INVOCATION = 32;
/**
* @var string[]
*/
private $invocationFunctionNames = array(
'include',
'include_once',
'require',
'require_once'
);
/**
* Contains resolved base names in order to reduce file IO.
*
* @var string[]
*/
private $baseNames = array();
/**
* Resolves PharInvocation value object (baseName and optional alias).
*
* Phar aliases are intended to be used only inside Phar archives, however
* PharStreamWrapper needs this information exposed outside of Phar as well
* It is possible that same alias is used for different $baseName values.
* That's why PharInvocationCollection behaves like a stack when resolving
* base-name for a given alias. On the other hand it is not possible that
* one $baseName is referring to multiple aliases.
* @see https://secure.php.net/manual/en/phar.setalias.php
* @see https://secure.php.net/manual/en/phar.mapphar.php
*
* @param string $path
* @param int|null $flags
* @return null|PharInvocation
*/
public function resolve($path, $flags = null)
{
$hasPharPrefix = Helper::hasPharPrefix($path);
if ($flags === null) {
$flags = static::RESOLVE_REALPATH | static::RESOLVE_ALIAS | static::ASSERT_INTERNAL_INVOCATION;
}
if ($hasPharPrefix && $flags & static::RESOLVE_ALIAS) {
$invocation = $this->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
);
}
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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(

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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.');
}
}

View File

@ -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"

View File

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -3012,7 +3012,7 @@ class DrupalWebTestCase extends DrupalTestCase {
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 @@ class DrupalWebTestCase extends DrupalTestCase {
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);
}
/**

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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.

View File

@ -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"

Some files were not shown because too many files have changed in this diff Show More