Révision cd5c298a
Ajouté par Geoffroy Desvernay il y a environ 5 ans
drupal7/CHANGELOG.txt | ||
---|---|---|
1 |
Drupal 7.63, 2019-01-16 |
|
2 |
----------------------- |
|
3 |
- Fixed a fatal error for some Drush users introduced by SA-CORE-2019-002. |
|
4 |
|
|
5 |
Drupal 7.62, 2019-01-15 |
|
6 |
----------------------- |
|
7 |
- Fixed security issues: |
|
8 |
- SA-CORE-2019-001 |
|
9 |
- SA-CORE-2019-002 |
|
10 |
|
|
11 |
Drupal 7.61, 2018-11-07 |
|
12 |
----------------------- |
|
13 |
- File upload validation functions and hook_file_validate() implementations are |
|
14 |
now always passed the correct file URI. |
|
15 |
- The default form cache expiration of 6 hours is now configurable (API |
|
16 |
addition: https://www.drupal.org/node/2857751). |
|
17 |
- Allowed callers of drupal_http_request() to optionally specify an explicit |
|
18 |
Host header. |
|
19 |
- Allowed the + character to appear in usernames. |
|
20 |
- PHP 7.2: Fixed Archive_Tar incompatibility. |
|
21 |
- PHP 7.2: Removed deprecated function each(). |
|
22 |
- PHP 7.2: Avoid count() calls on uncountable variables. |
|
23 |
- PHP 7.2: Removed deprecated create_function() call. |
|
24 |
- PHP 7.2: Make sure variables are arrays in theme_links(). |
|
25 |
- Fixed theme-settings.php not being loaded on cached forms |
|
26 |
- Fixed problem with IE11 & Chrome(PointerEvents enabled) & some Firefox scroll to the top of the page after dragging the bottom item with jquery 1.5 <-> 1.11 |
|
27 |
|
|
1 | 28 |
Drupal 7.60, 2018-10-18 |
2 | 29 |
------------------------ |
3 | 30 |
- Fixed security issues. See SA-CORE-2018-006. |
... | ... | |
8 | 35 |
|
9 | 36 |
Drupal 7.58, 2018-03-28 |
10 | 37 |
----------------------- |
11 |
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-002.
|
|
38 |
- Fixed security issues (remote code execution). See SA-CORE-2018-002.
|
|
12 | 39 |
|
13 | 40 |
Drupal 7.57, 2018-02-21 |
14 | 41 |
----------------------- |
drupal7/MAINTAINERS.txt | ||
---|---|---|
15 | 15 |
- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx |
16 | 16 |
- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein |
17 | 17 |
- Stefan Ruijsenaars 'stefan.r' https://www.drupal.org/u/stefanr-0 |
18 |
- (provisional) Pol Dellaiera 'Pol' https://www.drupal.org/u/pol |
|
18 | 19 |
|
19 | 20 |
|
20 | 21 |
Component maintainers |
... | ... | |
44 | 45 |
- Derek Wright 'dww' https://www.drupal.org/u/dww |
45 | 46 |
|
46 | 47 |
Database system |
47 |
- Larry Garfield 'Crell' https://www.drupal.org/u/crell
|
|
48 |
- ?
|
|
48 | 49 |
|
49 | 50 |
- MySQL driver |
50 |
- Larry Garfield 'Crell' https://www.drupal.org/u/crell |
|
51 | 51 |
- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss |
52 | 52 |
|
53 | 53 |
- PostgreSQL driver |
drupal7/includes/bootstrap.inc | ||
---|---|---|
8 | 8 |
/** |
9 | 9 |
* The current system version. |
10 | 10 |
*/ |
11 |
define('VERSION', '7.60');
|
|
11 |
define('VERSION', '7.63');
|
|
12 | 12 |
|
13 | 13 |
/** |
14 | 14 |
* Core API compatibility. |
... | ... | |
704 | 704 |
// Set sane locale settings, to ensure consistent string, dates, times and |
705 | 705 |
// numbers handling. |
706 | 706 |
setlocale(LC_ALL, 'C'); |
707 |
|
|
708 |
// PHP's built-in phar:// stream wrapper is not sufficiently secure. Override |
|
709 |
// it with a more secure one, which requires PHP 5.3.3. For lower versions, |
|
710 |
// unregister the built-in one without replacing it. Sites needing phar |
|
711 |
// support for lower PHP versions must implement hook_stream_wrappers() to |
|
712 |
// register their desired implementation. |
|
713 |
if (in_array('phar', stream_get_wrappers(), TRUE)) { |
|
714 |
stream_wrapper_unregister('phar'); |
|
715 |
if (version_compare(PHP_VERSION, '5.3.3', '>=')) { |
|
716 |
include_once DRUPAL_ROOT . '/includes/file.phar.inc'; |
|
717 |
file_register_phar_wrapper(); |
|
718 |
} |
|
719 |
} |
|
707 | 720 |
} |
708 | 721 |
|
709 | 722 |
/** |
... | ... | |
3785 | 3798 |
chdir(DRUPAL_ROOT); |
3786 | 3799 |
|
3787 | 3800 |
try { |
3788 |
while (list($key, $callback) = each($callbacks)) { |
|
3801 |
// Manually iterate over the array instead of using a foreach loop. |
|
3802 |
// A foreach operates on a copy of the array, so any shutdown functions that |
|
3803 |
// were added from other shutdown functions would never be called. |
|
3804 |
while ($callback = current($callbacks)) { |
|
3789 | 3805 |
call_user_func_array($callback['callback'], $callback['arguments']); |
3806 |
next($callbacks); |
|
3790 | 3807 |
} |
3791 | 3808 |
} |
3792 | 3809 |
catch (Exception $exception) { |
drupal7/includes/common.inc | ||
---|---|---|
867 | 867 |
// Make the socket connection to a proxy server. |
868 | 868 |
$socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080); |
869 | 869 |
// The Host header still needs to match the real request. |
870 |
$options['headers']['Host'] = $uri['host']; |
|
871 |
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : ''; |
|
870 |
if (!isset($options['headers']['Host'])) { |
|
871 |
$options['headers']['Host'] = $uri['host']; |
|
872 |
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : ''; |
|
873 |
} |
|
872 | 874 |
break; |
873 | 875 |
|
874 | 876 |
case 'http': |
... | ... | |
878 | 880 |
// RFC 2616: "non-standard ports MUST, default ports MAY be included". |
879 | 881 |
// We don't add the standard port to prevent from breaking rewrite rules |
880 | 882 |
// checking the host that do not take into account the port number. |
881 |
$options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : ''); |
|
883 |
if (!isset($options['headers']['Host'])) { |
|
884 |
$options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : ''); |
|
885 |
} |
|
882 | 886 |
break; |
883 | 887 |
|
884 | 888 |
case 'https': |
885 | 889 |
// Note: Only works when PHP is compiled with OpenSSL support. |
886 | 890 |
$port = isset($uri['port']) ? $uri['port'] : 443; |
887 | 891 |
$socket = 'ssl://' . $uri['host'] . ':' . $port; |
888 |
$options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : ''); |
|
892 |
if (!isset($options['headers']['Host'])) { |
|
893 |
$options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : ''); |
|
894 |
} |
|
889 | 895 |
break; |
890 | 896 |
|
891 | 897 |
default: |
drupal7/includes/file.inc | ||
---|---|---|
1534 | 1534 |
// rename filename.php.foo and filename.php to filename.php.foo.txt and |
1535 | 1535 |
// filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads' |
1536 | 1536 |
// evaluates to TRUE. |
1537 |
if (!variable_get('allow_insecure_uploads', 0) && preg_match('/\.(php|pl|py|cgi|asp|js)(\.|$)/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { |
|
1537 |
if (!variable_get('allow_insecure_uploads', 0) && preg_match('/\.(php|phar|pl|py|cgi|asp|js)(\.|$)/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
|
|
1538 | 1538 |
$file->filemime = 'text/plain'; |
1539 |
$file->uri .= '.txt';
|
|
1539 |
// The destination filename will also later be used to create the URI.
|
|
1540 | 1540 |
$file->filename .= '.txt'; |
1541 | 1541 |
// The .txt extension may not be in the allowed list of extensions. We have |
1542 | 1542 |
// to add it here or else the file upload will fail. |
drupal7/includes/file.phar.inc | ||
---|---|---|
1 |
<?php |
|
2 |
|
|
3 |
use Drupal\Core\Security\PharExtensionInterceptor; |
|
4 |
use TYPO3\PharStreamWrapper\Manager as PharStreamWrapperManager; |
|
5 |
use TYPO3\PharStreamWrapper\Behavior as PharStreamWrapperBehavior; |
|
6 |
use TYPO3\PharStreamWrapper\PharStreamWrapper; |
|
7 |
|
|
8 |
/** |
|
9 |
* Registers a phar stream wrapper that is more secure than PHP's built-in one. |
|
10 |
* |
|
11 |
* @see file_get_stream_wrappers() |
|
12 |
*/ |
|
13 |
function file_register_phar_wrapper() { |
|
14 |
$directory = DRUPAL_ROOT . '/misc/typo3/phar-stream-wrapper/src'; |
|
15 |
include_once $directory . '/Assertable.php'; |
|
16 |
include_once $directory . '/Behavior.php'; |
|
17 |
include_once $directory . '/Exception.php'; |
|
18 |
include_once $directory . '/Helper.php'; |
|
19 |
include_once $directory . '/Manager.php'; |
|
20 |
include_once $directory . '/PharStreamWrapper.php'; |
|
21 |
include_once DRUPAL_ROOT . '/misc/typo3/drupal-security/PharExtensionInterceptor.php'; |
|
22 |
|
|
23 |
// Set up a stream wrapper to handle insecurities due to PHP's built-in |
|
24 |
// phar stream wrapper. |
|
25 |
try { |
|
26 |
$behavior = new PharStreamWrapperBehavior(); |
|
27 |
PharStreamWrapperManager::initialize( |
|
28 |
$behavior->withAssertion(new PharExtensionInterceptor()) |
|
29 |
); |
|
30 |
} |
|
31 |
catch (\LogicException $e) { |
|
32 |
// Continue if the PharStreamWrapperManager is already initialized. |
|
33 |
// For example, this occurs following a drupal_static_reset(), such |
|
34 |
// as during tests. |
|
35 |
}; |
|
36 |
|
|
37 |
// To prevent file_stream_wrapper_valid_scheme() treating "phar" as a valid |
|
38 |
// scheme, this is registered with PHP only, not with hook_stream_wrappers() |
|
39 |
// or the internal storage of file_get_stream_wrappers(). |
|
40 |
stream_wrapper_register('phar', '\\TYPO3\\PharStreamWrapper\\PharStreamWrapper'); |
|
41 |
} |
drupal7/includes/form.inc | ||
---|---|---|
555 | 555 |
* Stores a form in the cache. |
556 | 556 |
*/ |
557 | 557 |
function form_set_cache($form_build_id, $form, $form_state) { |
558 |
// 6 hours cache life time for forms should be plenty. |
|
559 |
$expire = 21600; |
|
558 |
// The default cache_form expiration is 6 hours. On busy sites, the cache_form |
|
559 |
// table can become very large. A shorter cache lifetime can help to keep the |
|
560 |
// table's size under control. |
|
561 |
$expire = variable_get('form_cache_expiration', 21600); |
|
560 | 562 |
|
561 | 563 |
// Ensure that the form build_id embedded in the form structure is the same as |
562 | 564 |
// the one passed in as a parameter. This is an additional safety measure to |
... | ... | |
1438 | 1440 |
// length if it's a string, and the item count if it's an array. |
1439 | 1441 |
// An unchecked checkbox has a #value of integer 0, different than string |
1440 | 1442 |
// '0', which could be a valid value. |
1441 |
$is_empty_multiple = (!count($elements['#value'])); |
|
1443 |
$is_countable = is_array($elements['#value']) || $elements['#value'] instanceof Countable; |
|
1444 |
$is_empty_multiple = $is_countable && count($elements['#value']) == 0; |
|
1442 | 1445 |
$is_empty_string = (is_string($elements['#value']) && drupal_strlen(trim($elements['#value'])) == 0); |
1443 | 1446 |
$is_empty_value = ($elements['#value'] === 0); |
1444 |
if ($is_empty_multiple || $is_empty_string || $is_empty_value) { |
|
1447 |
$is_empty_null = is_null($elements['#value']); |
|
1448 |
if ($is_empty_multiple || $is_empty_string || $is_empty_value || $is_empty_null) { |
|
1445 | 1449 |
// Although discouraged, a #title is not mandatory for form elements. In |
1446 | 1450 |
// case there is no #title, we cannot set a form error message. |
1447 | 1451 |
// Instead of setting no #title, form constructors are encouraged to set |
drupal7/includes/install.inc | ||
---|---|---|
779 | 779 |
$module_list = array_flip(array_values($module_list)); |
780 | 780 |
|
781 | 781 |
$profile = drupal_get_profile(); |
782 |
while (list($module) = each($module_list)) {
|
|
782 |
foreach (array_keys($module_list) as $module) {
|
|
783 | 783 |
if (!isset($module_data[$module]) || drupal_get_installed_schema_version($module) == SCHEMA_UNINSTALLED) { |
784 | 784 |
// This module doesn't exist or is already uninstalled. Skip it. |
785 | 785 |
unset($module_list[$module]); |
drupal7/includes/menu.inc | ||
---|---|---|
576 | 576 |
// 'load arguments' in the hook_menu() entry, but they need |
577 | 577 |
// some processing. In this case the $function is the key to the |
578 | 578 |
// load_function array, and the value is the list of arguments. |
579 |
list($function, $args) = each($function); |
|
579 |
$args = current($function); |
|
580 |
$function = key($function); |
|
580 | 581 |
$load_functions[$index] = $function; |
581 | 582 |
|
582 | 583 |
// Some arguments are placeholders for dynamic items to process. |
... | ... | |
2402 | 2403 |
// a stripped down menu tree containing the active trail only, in case |
2403 | 2404 |
// the given menu has not been built in this request yet. |
2404 | 2405 |
$tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE); |
2405 |
list($key, $curr) = each($tree); |
|
2406 |
$curr = current($tree); |
|
2407 |
next($tree); |
|
2406 | 2408 |
} |
2407 | 2409 |
// There is no link for the current path. |
2408 | 2410 |
else { |
... | ... | |
2432 | 2434 |
} |
2433 | 2435 |
$tree = $curr['below'] ? $curr['below'] : array(); |
2434 | 2436 |
} |
2435 |
list($key, $curr) = each($tree); |
|
2437 |
$curr = current($tree); |
|
2438 |
next($tree); |
|
2436 | 2439 |
} |
2437 | 2440 |
// Make sure the current page is in the trail to build the page title, by |
2438 | 2441 |
// appending either the preferred link or the menu router item for the |
drupal7/includes/module.inc | ||
---|---|---|
404 | 404 |
// Create an associative array with weights as values. |
405 | 405 |
$module_list = array_flip(array_values($module_list)); |
406 | 406 |
|
407 |
while (list($module) = each($module_list)) { |
|
407 |
// The array is iterated over manually (instead of using a foreach) because |
|
408 |
// modules may be added to the list within the loop and we need to process |
|
409 |
// them. |
|
410 |
while ($module = key($module_list)) { |
|
411 |
next($module_list); |
|
408 | 412 |
if (!isset($module_data[$module])) { |
409 | 413 |
// This module is not found in the filesystem, abort. |
410 | 414 |
return FALSE; |
... | ... | |
540 | 544 |
$module_list = array_flip(array_values($module_list)); |
541 | 545 |
|
542 | 546 |
$profile = drupal_get_profile(); |
543 |
while (list($module) = each($module_list)) { |
|
547 |
// The array is iterated over manually (instead of using a foreach) because |
|
548 |
// modules may be added to the list within the loop and we need to process |
|
549 |
// them. |
|
550 |
while ($module = key($module_list)) { |
|
551 |
next($module_list); |
|
544 | 552 |
if (!isset($module_data[$module]) || !$module_data[$module]->status) { |
545 | 553 |
// This module doesn't exist or is already disabled, skip it. |
546 | 554 |
unset($module_list[$module]); |
drupal7/includes/theme.inc | ||
---|---|---|
1776 | 1776 |
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. |
1777 | 1777 |
*/ |
1778 | 1778 |
function theme_links($variables) { |
1779 |
$links = $variables['links']; |
|
1780 |
$attributes = $variables['attributes']; |
|
1779 |
$links = (array) $variables['links'];
|
|
1780 |
$attributes = (array) $variables['attributes'];
|
|
1781 | 1781 |
$heading = $variables['heading']; |
1782 | 1782 |
global $language_url; |
1783 | 1783 |
$output = ''; |
1784 | 1784 |
|
1785 |
if (count($links) > 0) {
|
|
1785 |
if (!empty($links)) {
|
|
1786 | 1786 |
// Treat the heading first if it is present to prepend it to the |
1787 | 1787 |
// list of links. |
1788 | 1788 |
if (!empty($heading)) { |
... | ... | |
1995 | 1995 |
$empty = $variables['empty']; |
1996 | 1996 |
|
1997 | 1997 |
// Add sticky headers, if applicable. |
1998 |
if (count($header) && $sticky) {
|
|
1998 |
if (!empty($header) && $sticky) {
|
|
1999 | 1999 |
drupal_add_js('misc/tableheader.js'); |
2000 | 2000 |
// Add 'sticky-enabled' class to the table to identify it for JS. |
2001 | 2001 |
// This is needed to target tables constructed by this function. |
... | ... | |
2009 | 2009 |
} |
2010 | 2010 |
|
2011 | 2011 |
// Format the table columns: |
2012 |
if (count($colgroups)) {
|
|
2012 |
if (!empty($colgroups)) {
|
|
2013 | 2013 |
foreach ($colgroups as $number => $colgroup) { |
2014 | 2014 |
$attributes = array(); |
2015 | 2015 |
|
... | ... | |
2044 | 2044 |
} |
2045 | 2045 |
|
2046 | 2046 |
// Add the 'empty' row message if available. |
2047 |
if (!count($rows) && $empty) {
|
|
2047 |
if (empty($rows) && $empty) {
|
|
2048 | 2048 |
$header_count = 0; |
2049 |
foreach ($header as $header_cell) { |
|
2050 |
if (is_array($header_cell)) { |
|
2051 |
$header_count += isset($header_cell['colspan']) ? $header_cell['colspan'] : 1; |
|
2052 |
} |
|
2053 |
else { |
|
2054 |
$header_count++; |
|
2049 |
if (!empty($header)) { |
|
2050 |
foreach ($header as $header_cell) { |
|
2051 |
if (is_array($header_cell)) { |
|
2052 |
$header_count += isset($header_cell['colspan']) ? $header_cell['colspan'] : 1; |
|
2053 |
} |
|
2054 |
else { |
|
2055 |
$header_count++; |
|
2056 |
} |
|
2055 | 2057 |
} |
2056 | 2058 |
} |
2057 | 2059 |
$rows[] = array(array('data' => $empty, 'colspan' => $header_count, 'class' => array('empty', 'message'))); |
2058 | 2060 |
} |
2059 | 2061 |
|
2060 | 2062 |
// Format the table header: |
2061 |
if (count($header)) {
|
|
2063 |
if (!empty($header)) {
|
|
2062 | 2064 |
$ts = tablesort_init($header); |
2063 | 2065 |
// HTML requires that the thead tag has tr tags in it followed by tbody |
2064 | 2066 |
// tags. Using ternary operator to check and see if we have any rows. |
2065 |
$output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
|
|
2067 |
$output .= (!empty($rows) ? ' <thead><tr>' : ' <tr>');
|
|
2066 | 2068 |
foreach ($header as $cell) { |
2067 | 2069 |
$cell = tablesort_header($cell, $header, $ts); |
2068 | 2070 |
$output .= _theme_table_cell($cell, TRUE); |
2069 | 2071 |
} |
2070 | 2072 |
// Using ternary operator to close the tags based on whether or not there are rows |
2071 |
$output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
|
|
2073 |
$output .= (!empty($rows) ? " </tr></thead>\n" : "</tr>\n");
|
|
2072 | 2074 |
} |
2073 | 2075 |
else { |
2074 | 2076 |
$ts = array(); |
2075 | 2077 |
} |
2076 | 2078 |
|
2077 | 2079 |
// Format the table rows: |
2078 |
if (count($rows)) {
|
|
2080 |
if (!empty($rows)) {
|
|
2079 | 2081 |
$output .= "<tbody>\n"; |
2080 | 2082 |
$flip = array('even' => 'odd', 'odd' => 'even'); |
2081 | 2083 |
$class = 'even'; |
... | ... | |
2095 | 2097 |
$attributes = array(); |
2096 | 2098 |
$no_striping = FALSE; |
2097 | 2099 |
} |
2098 |
if (count($cells)) {
|
|
2100 |
if (!empty($cells)) {
|
|
2099 | 2101 |
// Add odd/even class |
2100 | 2102 |
if (!$no_striping) { |
2101 | 2103 |
$class = $flip[$class]; |
drupal7/misc/tabledrag.js | ||
---|---|---|
580 | 580 |
* Get the mouse coordinates from the event (allowing for browser differences). |
581 | 581 |
*/ |
582 | 582 |
Drupal.tableDrag.prototype.mouseCoords = function (event) { |
583 |
|
|
584 |
// Match both null and undefined, but not zero, by using != null. |
|
585 |
// See https://stackoverflow.com/questions/2647867/how-to-determine-if-variable-is-undefined-or-null |
|
586 |
if (event.pageX != null && event.pageY != null) { |
|
587 |
return {x: event.pageX, y: event.pageY}; |
|
588 |
} |
|
589 |
|
|
583 | 590 |
// Complete support for pointer events was only introduced to jQuery in |
584 | 591 |
// version 1.11.1; between versions 1.7 and 1.11.0 pointer events have the |
585 |
// clientX and clientY properties undefined. In those cases, the properties |
|
586 |
// must be retrieved from the event.originalEvent object instead. |
|
587 |
var clientX = event.clientX || event.originalEvent.clientX; |
|
588 |
var clientY = event.clientY || event.originalEvent.clientY; |
|
592 |
// pageX and pageY properties undefined. In those cases, the properties must |
|
593 |
// be retrieved from the event.originalEvent object instead. |
|
594 |
if (event.originalEvent && event.originalEvent.pageX != null && event.originalEvent.pageY != null) { |
|
595 |
return {x: event.originalEvent.pageX, y: event.originalEvent.pageY}; |
|
596 |
} |
|
589 | 597 |
|
590 |
if (event.pageX || event.pageY) { |
|
591 |
return { x: event.pageX, y: event.pageY }; |
|
598 |
// Some old browsers do not support MouseEvent.pageX and *.pageY at all. |
|
599 |
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY |
|
600 |
// For those, we look at event.clientX and event.clientY instead. |
|
601 |
if (event.clientX == null || event.clientY == null) { |
|
602 |
// In some jQuery versions, some events created by jQuery do not have |
|
603 |
// clientX and clientY. But the original event might have. |
|
604 |
if (!event.originalEvent) { |
|
605 |
throw new Error("The event has no coordinates, and no event.originalEvent."); |
|
606 |
} |
|
607 |
event = event.originalEvent; |
|
608 |
if (event.clientX == null || event.clientY == null) { |
|
609 |
throw new Error("The original event has no coordinates."); |
|
610 |
} |
|
592 | 611 |
} |
593 | 612 |
|
594 |
return { |
|
595 |
x: clientX + document.body.scrollLeft - document.body.clientLeft, |
|
596 |
y: clientY + document.body.scrollTop - document.body.clientTop |
|
597 |
}; |
|
613 |
// Copied from jQuery.event.fix() in jQuery 1.4.1. |
|
614 |
// In newer jQuery versions, this code is in jQuery.event.mouseHooks.filter(). |
|
615 |
var doc = document.documentElement, body = document.body; |
|
616 |
var pageX = event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); |
|
617 |
var pageY = event.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); |
|
618 |
|
|
619 |
return {x: pageX, y: pageY}; |
|
598 | 620 |
}; |
599 | 621 |
|
600 | 622 |
/** |
drupal7/misc/typo3/drupal-security/PharExtensionInterceptor.php | ||
---|---|---|
1 |
<?php |
|
2 |
|
|
3 |
namespace Drupal\Core\Security; |
|
4 |
|
|
5 |
use TYPO3\PharStreamWrapper\Assertable; |
|
6 |
use TYPO3\PharStreamWrapper\Helper; |
|
7 |
use TYPO3\PharStreamWrapper\Exception; |
|
8 |
|
|
9 |
/** |
|
10 |
* An alternate PharExtensionInterceptor to support phar-based CLI tools. |
|
11 |
* |
|
12 |
* @see \TYPO3\PharStreamWrapper\Interceptor\PharExtensionInterceptor |
|
13 |
*/ |
|
14 |
class PharExtensionInterceptor implements Assertable { |
|
15 |
|
|
16 |
/** |
|
17 |
* Determines whether phar file is allowed to execute. |
|
18 |
* |
|
19 |
* The phar file is allowed to execute if: |
|
20 |
* - the base file name has a ".phar" suffix. |
|
21 |
* - it is the CLI tool that has invoked the interceptor. |
|
22 |
* |
|
23 |
* @param string $path |
|
24 |
* The path of the phar file to check. |
|
25 |
* @param string $command |
|
26 |
* The command being carried out. |
|
27 |
* |
|
28 |
* @return bool |
|
29 |
* TRUE if the phar file is allowed to execute. |
|
30 |
* |
|
31 |
* @throws Exception |
|
32 |
* Thrown when the file is not allowed to execute. |
|
33 |
*/ |
|
34 |
public function assert($path, $command) { |
|
35 |
if ($this->baseFileContainsPharExtension($path)) { |
|
36 |
return TRUE; |
|
37 |
} |
|
38 |
throw new Exception( |
|
39 |
sprintf( |
|
40 |
'Unexpected file extension in "%s"', |
|
41 |
$path |
|
42 |
), |
|
43 |
1535198703 |
|
44 |
); |
|
45 |
} |
|
46 |
|
|
47 |
/** |
|
48 |
* Determines if a path has a .phar extension or invoked execution. |
|
49 |
* |
|
50 |
* @param string $path |
|
51 |
* The path of the phar file to check. |
|
52 |
* |
|
53 |
* @return bool |
|
54 |
* TRUE if the file has a .phar extension or if the execution has been |
|
55 |
* invoked by the phar file. |
|
56 |
*/ |
|
57 |
private function baseFileContainsPharExtension($path) { |
|
58 |
$baseFile = Helper::determineBaseFile($path); |
|
59 |
if ($baseFile === NULL) { |
|
60 |
return FALSE; |
|
61 |
} |
|
62 |
// If the stream wrapper is registered by invoking a phar file that does |
|
63 |
// not not have .phar extension then this should be allowed. For |
|
64 |
// example, some CLI tools recommend removing the extension. |
|
65 |
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); |
|
66 |
// Find the last entry in the backtrace containing a 'file' key as |
|
67 |
// sometimes the last caller is executed outside the scope of a file. For |
|
68 |
// example, this occurs with shutdown functions. |
|
69 |
do { |
|
70 |
$caller = array_pop($backtrace); |
|
71 |
} while (empty($caller['file']) && !empty($backtrace)); |
|
72 |
if (isset($caller['file']) && $baseFile === Helper::determineBaseFile($caller['file'])) { |
|
73 |
return TRUE; |
|
74 |
} |
|
75 |
$fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION); |
|
76 |
return strtolower($fileExtension) === 'phar'; |
|
77 |
} |
|
78 |
|
|
79 |
} |
drupal7/misc/typo3/phar-stream-wrapper/LICENSE | ||
---|---|---|
1 |
MIT License |
|
2 |
|
|
3 |
Copyright (c) 2018 TYPO3 project - https://typo3.org/ |
|
4 |
|
|
5 |
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
6 |
of this software and associated documentation files (the "Software"), to deal |
|
7 |
in the Software without restriction, including without limitation the rights |
|
8 |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
copies of the Software, and to permit persons to whom the Software is |
|
10 |
furnished to do so, subject to the following conditions: |
|
11 |
|
|
12 |
The above copyright notice and this permission notice shall be included in all |
|
13 |
copies or substantial portions of the Software. |
|
14 |
|
|
15 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
16 |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
17 |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
18 |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
19 |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
20 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
21 |
SOFTWARE. |
drupal7/misc/typo3/phar-stream-wrapper/README.md | ||
---|---|---|
1 |
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/badges/quality-score.png?b=v2)](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/?branch=v2) |
|
2 |
[![Travis CI Build Status](https://travis-ci.org/TYPO3/phar-stream-wrapper.svg?branch=v2)](https://travis-ci.org/TYPO3/phar-stream-wrapper) |
|
3 |
|
|
4 |
# PHP Phar Stream Wrapper |
|
5 |
|
|
6 |
## Abstract & History |
|
7 |
|
|
8 |
Based on Sam Thomas' findings concerning |
|
9 |
[insecure deserialization in combination with obfuscation strategies](https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are) |
|
10 |
allowing to hide Phar files inside valid image resources, the TYPO3 project |
|
11 |
decided back then to introduce a `PharStreamWrapper` to intercept invocations |
|
12 |
of the `phar://` stream in PHP and only allow usage for defined locations in |
|
13 |
the file system. |
|
14 |
|
|
15 |
Since the TYPO3 mission statement is **inspiring people to share**, we thought |
|
16 |
it would be helpful for others to release our `PharStreamWrapper` as standalone |
|
17 |
package to the PHP community. |
|
18 |
|
|
19 |
The mentioned security issue was reported to TYPO3 on 10th June 2018 by Sam Thomas |
|
20 |
and has been addressed concerning the specific attack vector and for this generic |
|
21 |
`PharStreamWrapper` in TYPO3 versions 7.6.30 LTS, 8.7.17 LTS and 9.3.1 on 12th |
|
22 |
July 2018. |
|
23 |
|
|
24 |
* https://typo3.org/security/advisory/typo3-core-sa-2018-002/ |
|
25 |
* https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are |
|
26 |
* https://youtu.be/GePBmsNJw6Y |
|
27 |
|
|
28 |
## License |
|
29 |
|
|
30 |
In general the TYPO3 core is released under the GNU General Public License version |
|
31 |
2 or any later version (`GPL-2.0-or-later`). In order to avoid licensing issues and |
|
32 |
incompatibilities this `PharStreamWrapper` is licenced under the MIT License. In case |
|
33 |
you duplicate or modify source code, credits are not required but really appreciated. |
|
34 |
|
|
35 |
## Credits |
|
36 |
|
|
37 |
Thanks to [Alex Pott](https://github.com/alexpott), Drupal for creating |
|
38 |
back-ports of all sources in order to provide compatibility with PHP v5.3. |
|
39 |
|
|
40 |
## Installation |
|
41 |
|
|
42 |
The `PharStreamWrapper` is provided as composer package `typo3/phar-stream-wrapper` |
|
43 |
and has minimum requirements of PHP v5.3 ([`v2`](https://github.com/TYPO3/phar-stream-wrapper/tree/v2) branch) and PHP v7.0 ([`master`](https://github.com/TYPO3/phar-stream-wrapper) branch). |
|
44 |
|
|
45 |
### Installation for PHP v7.0 |
|
46 |
|
|
47 |
``` |
|
48 |
composer require typo3/phar-stream-wrapper ^3.0 |
|
49 |
``` |
|
50 |
|
|
51 |
### Installation for PHP v5.3 |
|
52 |
|
|
53 |
``` |
|
54 |
composer require typo3/phar-stream-wrapper ^2.0 |
|
55 |
``` |
|
56 |
|
|
57 |
## Example |
|
58 |
|
|
59 |
The following example is bundled within this package, the shown |
|
60 |
`PharExtensionInterceptor` denies all stream wrapper invocations files |
|
61 |
not having the `.phar` suffix. Interceptor logic has to be individual and |
|
62 |
adjusted to according requirements. |
|
63 |
|
|
64 |
``` |
|
65 |
$behavior = new \TYPO3\PharStreamWrapper\Behavior(); |
|
66 |
Manager::initialize( |
|
67 |
$behavior->withAssertion(new PharExtensionInterceptor()) |
|
68 |
); |
|
69 |
|
|
70 |
if (in_array('phar', stream_get_wrappers())) { |
|
71 |
stream_wrapper_unregister('phar'); |
|
72 |
stream_wrapper_register('phar', 'TYPO3\\PharStreamWrapper\\PharStreamWrapper'); |
|
73 |
} |
|
74 |
``` |
|
75 |
|
|
76 |
* `PharStreamWrapper` defined as class reference will be instantiated each time |
|
77 |
`phar://` streams shall be processed. |
|
78 |
* `Manager` as singleton pattern being called by `PharStreamWrapper` instances |
|
79 |
in order to retrieve individual behavior and settings. |
|
80 |
* `Behavior` holds reference to interceptor(s) that shall assert correct/allowed |
|
81 |
invocation of a given `$path` for a given `$command`. Interceptors implement |
|
82 |
the interface `Assertable`. Interceptors can act individually on following |
|
83 |
commands or handle all of them in case not defined specifically: |
|
84 |
+ `COMMAND_DIR_OPENDIR` |
|
85 |
+ `COMMAND_MKDIR` |
|
86 |
+ `COMMAND_RENAME` |
|
87 |
+ `COMMAND_RMDIR` |
|
88 |
+ `COMMAND_STEAM_METADATA` |
|
89 |
+ `COMMAND_STREAM_OPEN` |
|
90 |
+ `COMMAND_UNLINK` |
|
91 |
+ `COMMAND_URL_STAT` |
|
92 |
|
|
93 |
## Interceptor |
|
94 |
|
|
95 |
The following interceptor is shipped with the package and ready to use in order |
|
96 |
to block any Phar invocation of files not having a `.phar` suffix. Besides that |
|
97 |
individual interceptors are possible of course. |
|
98 |
|
|
99 |
``` |
|
100 |
class PharExtensionInterceptor implements Assertable |
|
101 |
{ |
|
102 |
/** |
|
103 |
* Determines whether the base file name has a ".phar" suffix. |
|
104 |
* |
|
105 |
* @param string $path |
|
106 |
* @param string $command |
|
107 |
* @return bool |
|
108 |
* @throws Exception |
|
109 |
*/ |
|
110 |
public function assert($path, $command) |
|
111 |
{ |
|
112 |
if ($this->baseFileContainsPharExtension($path)) { |
|
113 |
return true; |
|
114 |
} |
|
115 |
throw new Exception( |
|
116 |
sprintf( |
|
117 |
'Unexpected file extension in "%s"', |
|
118 |
$path |
|
119 |
), |
|
120 |
1535198703 |
|
121 |
); |
|
122 |
} |
|
123 |
|
|
124 |
/** |
|
125 |
* @param string $path |
|
126 |
* @return bool |
|
127 |
*/ |
|
128 |
private function baseFileContainsPharExtension($path) |
|
129 |
{ |
|
130 |
$baseFile = Helper::determineBaseFile($path); |
|
131 |
if ($baseFile === null) { |
|
132 |
return false; |
|
133 |
} |
|
134 |
$fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION); |
|
135 |
return strtolower($fileExtension) === 'phar'; |
|
136 |
} |
|
137 |
} |
|
138 |
``` |
|
139 |
|
|
140 |
## Helper |
|
141 |
|
|
142 |
* `Helper::determineBaseFile(string $path)`: Determines base file that can be |
|
143 |
accessed using the regular file system. For instance the following path |
|
144 |
`phar:///home/user/bundle.phar/content.txt` would be resolved to |
|
145 |
`/home/user/bundle.phar`. |
|
146 |
* `Helper::resetOpCache()`: Resets PHP's OPcache if enabled as work-around for |
|
147 |
issues in `include()` or `require()` calls and OPcache delivering wrong |
|
148 |
results. More details can be found in PHP's bug tracker, for instance like |
|
149 |
https://bugs.php.net/bug.php?id=66569 |
|
150 |
|
|
151 |
## Security Contact |
|
152 |
|
|
153 |
In case of finding additional security issues in the TYPO3 project or in this |
|
154 |
`PharStreamWrapper` package in particular, please get in touch with the |
|
155 |
[TYPO3 Security Team](mailto:security@typo3.org). |
drupal7/misc/typo3/phar-stream-wrapper/composer.json | ||
---|---|---|
1 |
{ |
|
2 |
"name": "typo3/phar-stream-wrapper", |
|
3 |
"description": "Interceptors for PHP's native phar:// stream handling", |
|
4 |
"type": "library", |
|
5 |
"license": "MIT", |
|
6 |
"homepage": "https://typo3.org/", |
|
7 |
"keywords": ["php", "phar", "stream-wrapper", "security"], |
|
8 |
"require": { |
|
9 |
"php": "^5.3.3|^7.0" |
|
10 |
}, |
|
11 |
"require-dev": { |
|
12 |
"phpunit/phpunit": "^4.8.36" |
|
13 |
}, |
|
14 |
"autoload": { |
|
15 |
"psr-4": { |
|
16 |
"TYPO3\\PharStreamWrapper\\": "src/" |
|
17 |
} |
|
18 |
}, |
|
19 |
"autoload-dev": { |
|
20 |
"psr-4": { |
|
21 |
"TYPO3\\PharStreamWrapper\\Tests\\": "tests/" |
|
22 |
} |
|
23 |
} |
|
24 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Assertable.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
interface Assertable |
|
15 |
{ |
|
16 |
/** |
|
17 |
* @param string $path |
|
18 |
* @param string $command |
|
19 |
* @return bool |
|
20 |
*/ |
|
21 |
public function assert($path, $command); |
|
22 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Behavior.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
class Behavior implements Assertable |
|
15 |
{ |
|
16 |
const COMMAND_DIR_OPENDIR = 'dir_opendir'; |
|
17 |
const COMMAND_MKDIR = 'mkdir'; |
|
18 |
const COMMAND_RENAME = 'rename'; |
|
19 |
const COMMAND_RMDIR = 'rmdir'; |
|
20 |
const COMMAND_STEAM_METADATA = 'stream_metadata'; |
|
21 |
const COMMAND_STREAM_OPEN = 'stream_open'; |
|
22 |
const COMMAND_UNLINK = 'unlink'; |
|
23 |
const COMMAND_URL_STAT = 'url_stat'; |
|
24 |
|
|
25 |
/** |
|
26 |
* @var string[] |
|
27 |
*/ |
|
28 |
private $availableCommands = array( |
|
29 |
self::COMMAND_DIR_OPENDIR, |
|
30 |
self::COMMAND_MKDIR, |
|
31 |
self::COMMAND_RENAME, |
|
32 |
self::COMMAND_RMDIR, |
|
33 |
self::COMMAND_STEAM_METADATA, |
|
34 |
self::COMMAND_STREAM_OPEN, |
|
35 |
self::COMMAND_UNLINK, |
|
36 |
self::COMMAND_URL_STAT, |
|
37 |
); |
|
38 |
|
|
39 |
/** |
|
40 |
* @var Assertable[] |
|
41 |
*/ |
|
42 |
private $assertions; |
|
43 |
|
|
44 |
/** |
|
45 |
* @param Assertable $assertable |
|
46 |
* @return static |
|
47 |
*/ |
|
48 |
public function withAssertion(Assertable $assertable) |
|
49 |
{ |
|
50 |
$commands = func_get_args(); |
|
51 |
array_shift($commands); |
|
52 |
$this->assertCommands($commands); |
|
53 |
$commands = $commands ?: $this->availableCommands; |
|
54 |
|
|
55 |
$target = clone $this; |
|
56 |
foreach ($commands as $command) { |
|
57 |
$target->assertions[$command] = $assertable; |
|
58 |
} |
|
59 |
return $target; |
|
60 |
} |
|
61 |
|
|
62 |
/** |
|
63 |
* @param string $path |
|
64 |
* @param string $command |
|
65 |
* @return bool |
|
66 |
*/ |
|
67 |
public function assert($path, $command) |
|
68 |
{ |
|
69 |
$this->assertCommand($command); |
|
70 |
$this->assertAssertionCompleteness(); |
|
71 |
|
|
72 |
return $this->assertions[$command]->assert($path, $command); |
|
73 |
} |
|
74 |
|
|
75 |
/** |
|
76 |
* @param array $commands |
|
77 |
*/ |
|
78 |
private function assertCommands(array $commands) |
|
79 |
{ |
|
80 |
$unknownCommands = array_diff($commands, $this->availableCommands); |
|
81 |
if (empty($unknownCommands)) { |
|
82 |
return; |
|
83 |
} |
|
84 |
throw new \LogicException( |
|
85 |
sprintf( |
|
86 |
'Unknown commands: %s', |
|
87 |
implode(', ', $unknownCommands) |
|
88 |
), |
|
89 |
1535189881 |
|
90 |
); |
|
91 |
} |
|
92 |
|
|
93 |
private function assertCommand($command) |
|
94 |
{ |
|
95 |
if (in_array($command, $this->availableCommands, true)) { |
|
96 |
return; |
|
97 |
} |
|
98 |
throw new \LogicException( |
|
99 |
sprintf( |
|
100 |
'Unknown command "%s"', |
|
101 |
$command |
|
102 |
), |
|
103 |
1535189882 |
|
104 |
); |
|
105 |
} |
|
106 |
|
|
107 |
private function assertAssertionCompleteness() |
|
108 |
{ |
|
109 |
$undefinedAssertions = array_diff( |
|
110 |
$this->availableCommands, |
|
111 |
array_keys($this->assertions) |
|
112 |
); |
|
113 |
if (empty($undefinedAssertions)) { |
|
114 |
return; |
|
115 |
} |
|
116 |
throw new \LogicException( |
|
117 |
sprintf( |
|
118 |
'Missing assertions for commands: %s', |
|
119 |
implode(', ', $undefinedAssertions) |
|
120 |
), |
|
121 |
1535189883 |
|
122 |
); |
|
123 |
} |
|
124 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Exception.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
class Exception extends \RuntimeException |
|
15 |
{ |
|
16 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Helper.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
class Helper |
|
15 |
{ |
|
16 |
/* |
|
17 |
* Resets PHP's OPcache if enabled as work-around for issues in `include()` |
|
18 |
* or `require()` calls and OPcache delivering wrong results. |
|
19 |
* |
|
20 |
* @see https://bugs.php.net/bug.php?id=66569 |
|
21 |
*/ |
|
22 |
public static function resetOpCache() |
|
23 |
{ |
|
24 |
if (function_exists('opcache_reset') |
|
25 |
&& function_exists('opcache_get_status') |
|
26 |
) { |
|
27 |
$status = opcache_get_status(); |
|
28 |
if (!empty($status['opcache_enabled'])) { |
|
29 |
opcache_reset(); |
|
30 |
} |
|
31 |
} |
|
32 |
} |
|
33 |
|
|
34 |
/** |
|
35 |
* Determines base file that can be accessed using the regular file system. |
|
36 |
* For e.g. "phar:///home/user/bundle.phar/content.txt" that would result |
|
37 |
* into "/home/user/bundle.phar". |
|
38 |
* |
|
39 |
* @param string $path |
|
40 |
* @return string|null |
|
41 |
*/ |
|
42 |
public static function determineBaseFile($path) |
|
43 |
{ |
|
44 |
$parts = explode('/', static::normalizePath($path)); |
|
45 |
|
|
46 |
while (count($parts)) { |
|
47 |
$currentPath = implode('/', $parts); |
|
48 |
if (@is_file($currentPath)) { |
|
49 |
return $currentPath; |
|
50 |
} |
|
51 |
array_pop($parts); |
|
52 |
} |
|
53 |
|
|
54 |
return null; |
|
55 |
} |
|
56 |
|
|
57 |
/** |
|
58 |
* @param string $path |
|
59 |
* @return string |
|
60 |
*/ |
|
61 |
public static function removePharPrefix($path) |
|
62 |
{ |
|
63 |
$path = trim($path); |
|
64 |
if (stripos($path, 'phar://') !== 0) { |
|
65 |
return $path; |
|
66 |
} |
|
67 |
return substr($path, 7); |
|
68 |
} |
|
69 |
|
|
70 |
/** |
|
71 |
* Normalizes a path, removes phar:// prefix, fixes Windows directory |
|
72 |
* separators. Result is without trailing slash. |
|
73 |
* |
|
74 |
* @param string $path |
|
75 |
* @return string |
|
76 |
*/ |
|
77 |
public static function normalizePath($path) |
|
78 |
{ |
|
79 |
return rtrim( |
|
80 |
static::getCanonicalPath( |
|
81 |
static::removePharPrefix($path) |
|
82 |
), |
|
83 |
'/' |
|
84 |
); |
|
85 |
} |
|
86 |
|
|
87 |
/** |
|
88 |
* Fixes a path for windows-backslashes and reduces double-slashes to single slashes |
|
89 |
* |
|
90 |
* @param string $path File path to process |
|
91 |
* @return string |
|
92 |
*/ |
|
93 |
private static function normalizeWindowsPath($path) |
|
94 |
{ |
|
95 |
return str_replace('\\', '/', $path); |
|
96 |
} |
|
97 |
|
|
98 |
/** |
|
99 |
* Resolves all dots, slashes and removes spaces after or before a path... |
|
100 |
* |
|
101 |
* @param string $path Input string |
|
102 |
* @return string Canonical path, always without trailing slash |
|
103 |
*/ |
|
104 |
private static function getCanonicalPath($path) |
|
105 |
{ |
|
106 |
$path = static::normalizeWindowsPath($path); |
|
107 |
|
|
108 |
$absolutePathPrefix = ''; |
|
109 |
if (static::isAbsolutePath($path)) { |
|
110 |
if (static::isWindows() && strpos($path, ':/') === 1) { |
|
111 |
$absolutePathPrefix = substr($path, 0, 3); |
|
112 |
$path = substr($path, 3); |
|
113 |
} else { |
|
114 |
$path = ltrim($path, '/'); |
|
115 |
$absolutePathPrefix = '/'; |
|
116 |
} |
|
117 |
} |
|
118 |
|
|
119 |
$pathParts = explode('/', $path); |
|
120 |
$pathPartsLength = count($pathParts); |
|
121 |
for ($partCount = 0; $partCount < $pathPartsLength; $partCount++) { |
|
122 |
// double-slashes in path: remove element |
|
123 |
if ($pathParts[$partCount] === '') { |
|
124 |
array_splice($pathParts, $partCount, 1); |
|
125 |
$partCount--; |
|
126 |
$pathPartsLength--; |
|
127 |
} |
|
128 |
// "." in path: remove element |
|
129 |
if ((isset($pathParts[$partCount]) ? $pathParts[$partCount] : '') === '.') { |
|
130 |
array_splice($pathParts, $partCount, 1); |
|
131 |
$partCount--; |
|
132 |
$pathPartsLength--; |
|
133 |
} |
|
134 |
// ".." in path: |
|
135 |
if ((isset($pathParts[$partCount]) ? $pathParts[$partCount] : '') === '..') { |
|
136 |
if ($partCount === 0) { |
|
137 |
array_splice($pathParts, $partCount, 1); |
|
138 |
$partCount--; |
|
139 |
$pathPartsLength--; |
|
140 |
} elseif ($partCount >= 1) { |
|
141 |
// Rremove this and previous element |
|
142 |
array_splice($pathParts, $partCount - 1, 2); |
|
143 |
$partCount -= 2; |
|
144 |
$pathPartsLength -= 2; |
|
145 |
} elseif ($absolutePathPrefix) { |
|
146 |
// can't go higher than root dir |
|
147 |
// simply remove this part and continue |
|
148 |
array_splice($pathParts, $partCount, 1); |
|
149 |
$partCount--; |
|
150 |
$pathPartsLength--; |
|
151 |
} |
|
152 |
} |
|
153 |
} |
|
154 |
|
|
155 |
return $absolutePathPrefix . implode('/', $pathParts); |
|
156 |
} |
|
157 |
|
|
158 |
/** |
|
159 |
* Checks if the $path is absolute or relative (detecting either '/' or |
|
160 |
* 'x:/' as first part of string) and returns TRUE if so. |
|
161 |
* |
|
162 |
* @param string $path File path to evaluate |
|
163 |
* @return bool |
|
164 |
*/ |
|
165 |
private static function isAbsolutePath($path) |
|
166 |
{ |
|
167 |
// Path starting with a / is always absolute, on every system |
|
168 |
// On Windows also a path starting with a drive letter is absolute: X:/ |
|
169 |
return (isset($path[0]) ? $path[0] : null) === '/' |
|
170 |
|| static::isWindows() && ( |
|
171 |
strpos($path, ':/') === 1 |
|
172 |
|| strpos($path, ':\\') === 1 |
|
173 |
); |
|
174 |
} |
|
175 |
|
|
176 |
/** |
|
177 |
* @return bool |
|
178 |
*/ |
|
179 |
private static function isWindows() |
|
180 |
{ |
|
181 |
return stripos(PHP_OS, 'WIN') === 0; |
|
182 |
} |
|
183 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Interceptor/PharExtensionInterceptor.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper\Interceptor; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
use TYPO3\PharStreamWrapper\Assertable; |
|
15 |
use TYPO3\PharStreamWrapper\Helper; |
|
16 |
use TYPO3\PharStreamWrapper\Exception; |
|
17 |
|
|
18 |
class PharExtensionInterceptor implements Assertable |
|
19 |
{ |
|
20 |
/** |
|
21 |
* Determines whether the base file name has a ".phar" suffix. |
|
22 |
* |
|
23 |
* @param string $path |
|
24 |
* @param string $command |
|
25 |
* @return bool |
|
26 |
* @throws Exception |
|
27 |
*/ |
|
28 |
public function assert($path, $command) |
|
29 |
{ |
|
30 |
if ($this->baseFileContainsPharExtension($path)) { |
|
31 |
return true; |
|
32 |
} |
|
33 |
throw new Exception( |
|
34 |
sprintf( |
|
35 |
'Unexpected file extension in "%s"', |
|
36 |
$path |
|
37 |
), |
|
38 |
1535198703 |
|
39 |
); |
|
40 |
} |
|
41 |
|
|
42 |
/** |
|
43 |
* @param string $path |
|
44 |
* @return bool |
|
45 |
*/ |
|
46 |
private function baseFileContainsPharExtension($path) |
|
47 |
{ |
|
48 |
$baseFile = Helper::determineBaseFile($path); |
|
49 |
if ($baseFile === null) { |
|
50 |
return false; |
|
51 |
} |
|
52 |
$fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION); |
|
53 |
return strtolower($fileExtension) === 'phar'; |
|
54 |
} |
|
55 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/Manager.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
class Manager implements Assertable |
|
15 |
{ |
|
16 |
/** |
|
17 |
* @var self |
|
18 |
*/ |
|
19 |
private static $instance; |
|
20 |
|
|
21 |
/** |
|
22 |
* @var Behavior |
|
23 |
*/ |
|
24 |
private $behavior; |
|
25 |
|
|
26 |
/** |
|
27 |
* @param Behavior $behaviour |
|
28 |
* @return self |
|
29 |
*/ |
|
30 |
public static function initialize(Behavior $behaviour) |
|
31 |
{ |
|
32 |
if (self::$instance === null) { |
|
33 |
self::$instance = new self($behaviour); |
|
34 |
return self::$instance; |
|
35 |
} |
|
36 |
throw new \LogicException( |
|
37 |
'Manager can only be initialized once', |
|
38 |
1535189871 |
|
39 |
); |
|
40 |
} |
|
41 |
|
|
42 |
/** |
|
43 |
* @return self |
|
44 |
*/ |
|
45 |
public static function instance() |
|
46 |
{ |
|
47 |
if (self::$instance !== null) { |
|
48 |
return self::$instance; |
|
49 |
} |
|
50 |
throw new \LogicException( |
|
51 |
'Manager needs to be initialized first', |
|
52 |
1535189872 |
|
53 |
); |
|
54 |
} |
|
55 |
|
|
56 |
/** |
|
57 |
* @return bool |
|
58 |
*/ |
|
59 |
public static function destroy() |
|
60 |
{ |
|
61 |
if (self::$instance === null) { |
|
62 |
return false; |
|
63 |
} |
|
64 |
self::$instance = null; |
|
65 |
return true; |
|
66 |
} |
|
67 |
|
|
68 |
/** |
|
69 |
* @param Behavior $behaviour |
|
70 |
*/ |
|
71 |
private function __construct(Behavior $behaviour) |
|
72 |
{ |
|
73 |
$this->behavior = $behaviour; |
|
74 |
} |
|
75 |
|
|
76 |
/** |
|
77 |
* @param string $path |
|
78 |
* @param string $command |
|
79 |
* @return bool |
|
80 |
*/ |
|
81 |
public function assert($path, $command) |
|
82 |
{ |
|
83 |
return $this->behavior->assert($path, $command); |
|
84 |
} |
|
85 |
} |
drupal7/misc/typo3/phar-stream-wrapper/src/PharStreamWrapper.php | ||
---|---|---|
1 |
<?php |
|
2 |
namespace TYPO3\PharStreamWrapper; |
|
3 |
|
|
4 |
/* |
|
5 |
* This file is part of the TYPO3 project. |
|
6 |
* |
|
7 |
* It is free software; you can redistribute it and/or modify it under the terms |
|
8 |
* of the MIT License (MIT). For the full copyright and license information, |
|
9 |
* please read the LICENSE file that was distributed with this source code. |
|
10 |
* |
|
11 |
* The TYPO3 project - inspiring people to share! |
|
12 |
*/ |
|
13 |
|
|
14 |
class PharStreamWrapper |
|
15 |
{ |
|
16 |
/** |
|
17 |
* Internal stream constants that are not exposed to PHP, but used... |
|
18 |
* @see https://github.com/php/php-src/blob/e17fc0d73c611ad0207cac8a4a01ded38251a7dc/main/php_streams.h |
|
19 |
*/ |
|
20 |
const STREAM_OPEN_FOR_INCLUDE = 128; |
|
21 |
|
|
22 |
/** |
|
23 |
* @var resource |
|
24 |
*/ |
|
25 |
public $context; |
|
26 |
|
|
27 |
/** |
|
28 |
* @var resource |
|
29 |
*/ |
|
30 |
protected $internalResource; |
|
31 |
|
|
32 |
/** |
|
33 |
* @return bool |
|
34 |
*/ |
|
35 |
public function dir_closedir() |
|
36 |
{ |
|
37 |
if (!is_resource($this->internalResource)) { |
|
38 |
return false; |
|
39 |
} |
|
40 |
|
|
41 |
$this->invokeInternalStreamWrapper( |
|
42 |
'closedir', |
|
43 |
$this->internalResource |
|
44 |
); |
|
45 |
return !is_resource($this->internalResource); |
|
46 |
} |
|
47 |
|
|
48 |
/** |
|
49 |
* @param string $path |
|
50 |
* @param int $options |
|
51 |
* @return bool |
|
52 |
*/ |
|
53 |
public function dir_opendir($path, $options) |
|
54 |
{ |
|
55 |
$this->assert($path, Behavior::COMMAND_DIR_OPENDIR); |
|
56 |
$this->internalResource = $this->invokeInternalStreamWrapper( |
|
57 |
'opendir', |
|
58 |
$path, |
|
59 |
$this->context |
|
60 |
); |
|
61 |
return is_resource($this->internalResource); |
|
62 |
} |
|
63 |
|
|
64 |
/** |
|
65 |
* @return string|false |
|
66 |
*/ |
|
67 |
public function dir_readdir() |
|
68 |
{ |
|
69 |
return $this->invokeInternalStreamWrapper( |
|
70 |
'readdir', |
|
71 |
$this->internalResource |
|
72 |
); |
|
73 |
} |
|
74 |
|
|
75 |
/** |
|
76 |
* @return bool |
|
77 |
*/ |
|
78 |
public function dir_rewinddir() |
|
79 |
{ |
|
80 |
if (!is_resource($this->internalResource)) { |
|
81 |
return false; |
|
82 |
} |
|
83 |
|
|
84 |
$this->invokeInternalStreamWrapper( |
|
85 |
'rewinddir', |
|
86 |
$this->internalResource |
|
87 |
); |
|
88 |
return is_resource($this->internalResource); |
|
89 |
} |
|
90 |
|
|
91 |
/** |
|
92 |
* @param string $path |
|
93 |
* @param int $mode |
|
94 |
* @param int $options |
|
95 |
* @return bool |
|
96 |
*/ |
|
97 |
public function mkdir($path, $mode, $options) |
|
98 |
{ |
|
99 |
$this->assert($path, Behavior::COMMAND_MKDIR); |
|
100 |
return $this->invokeInternalStreamWrapper( |
|
101 |
'mkdir', |
|
102 |
$path, |
|
103 |
$mode, |
|
104 |
(bool) ($options & STREAM_MKDIR_RECURSIVE), |
|
105 |
$this->context |
|
106 |
); |
|
107 |
} |
|
108 |
|
|
109 |
/** |
|
110 |
* @param string $path_from |
|
111 |
* @param string $path_to |
|
112 |
* @return bool |
|
113 |
*/ |
|
114 |
public function rename($path_from, $path_to) |
|
115 |
{ |
|
116 |
$this->assert($path_from, Behavior::COMMAND_RENAME); |
|
117 |
$this->assert($path_to, Behavior::COMMAND_RENAME); |
|
118 |
return $this->invokeInternalStreamWrapper( |
|
119 |
'rename', |
|
120 |
$path_from, |
|
121 |
$path_to, |
|
122 |
$this->context |
|
123 |
); |
|
124 |
} |
|
125 |
|
|
126 |
/** |
|
127 |
* @param string $path |
|
128 |
* @param int $options |
|
129 |
* @return bool |
|
130 |
*/ |
|
131 |
public function rmdir($path, $options) |
|
132 |
{ |
|
133 |
$this->assert($path, Behavior::COMMAND_RMDIR); |
|
134 |
return $this->invokeInternalStreamWrapper( |
|
135 |
'rmdir', |
|
136 |
$path, |
|
137 |
$this->context |
|
138 |
); |
|
139 |
} |
|
140 |
|
|
141 |
/** |
|
142 |
* @param int $cast_as |
|
143 |
*/ |
|
144 |
public function stream_cast($cast_as) |
|
145 |
{ |
|
146 |
throw new Exception( |
|
147 |
'Method stream_select() cannot be used', |
|
148 |
1530103999 |
|
149 |
); |
|
150 |
} |
|
151 |
|
|
152 |
public function stream_close() |
|
153 |
{ |
|
154 |
$this->invokeInternalStreamWrapper( |
|
155 |
'fclose', |
|
156 |
$this->internalResource |
|
157 |
); |
|
158 |
} |
|
159 |
|
|
160 |
/** |
|
161 |
* @return bool |
|
162 |
*/ |
|
163 |
public function stream_eof() |
|
164 |
{ |
|
165 |
return $this->invokeInternalStreamWrapper( |
|
166 |
'feof', |
|
167 |
$this->internalResource |
|
168 |
); |
|
169 |
} |
|
170 |
|
|
171 |
/** |
|
172 |
* @return bool |
|
173 |
*/ |
|
174 |
public function stream_flush() |
|
175 |
{ |
|
176 |
return $this->invokeInternalStreamWrapper( |
|
177 |
'fflush', |
|
178 |
$this->internalResource |
|
179 |
); |
|
180 |
} |
|
181 |
|
Formats disponibles : Unified diff
MAJ 7.60 -> 7.62