Projet

Général

Profil

Révision cd5c298a

Ajouté par Geoffroy Desvernay il y a environ 5 ans

MAJ 7.60 -> 7.62

Voir les différences:

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

  
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff