Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  /**
  19   * Abstraction of general file archives.
  20   *
  21   * @package   core_files
  22   * @copyright 2008 Petr Skoda (http://skodak.org)
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Each file archive type must extend this class.
  30   *
  31   * @package   core_files
  32   * @copyright 2008 Petr Skoda (http://skodak.org)
  33   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  abstract class file_archive implements Iterator {
  36  
  37      /** Open archive if exists, fail if does not exist. */
  38      const OPEN      = 1;
  39  
  40      /** Open archive if exists, create if does not. */
  41      const CREATE    = 2;
  42  
  43      /** Always create new archive */
  44      const OVERWRITE = 4;
  45  
  46      /** @var string Encoding of file names - windows usually expects DOS single-byte charset*/
  47      protected $encoding = 'utf-8';
  48  
  49      /**
  50       * Open or create archive (depending on $mode).
  51       *
  52       * @param string $archivepathname archive path name
  53       * @param int $mode OPEN, CREATE or OVERWRITE constant
  54       * @param string $encoding archive local paths encoding
  55       * @return bool success
  56       */
  57      public abstract function open($archivepathname, $mode=file_archive::CREATE, $encoding='utf-8');
  58  
  59      /**
  60       * Close archive.
  61       *
  62       * @return bool success
  63       */
  64      public abstract function close();
  65  
  66      /**
  67       * Returns file stream for reading of content.
  68       *
  69       * @param int $index index of file
  70       * @return stream|bool stream or false if error
  71       */
  72      public abstract function get_stream($index);
  73  
  74      /**
  75       * Returns file information.
  76       *
  77       * @param int $index index of file
  78       * @return stdClass|bool object or false if error
  79       */
  80      public abstract function get_info($index);
  81  
  82      /**
  83       * Returns array of info about all files in archive.
  84       *
  85       * @return array of file infos
  86       */
  87      public abstract function list_files();
  88  
  89      /**
  90       * Returns number of files in archive.
  91       *
  92       * @return int number of files
  93       */
  94      public abstract function count();
  95  
  96      /**
  97       * Add file into archive.
  98       *
  99       * @param string $localname name of file in archive
 100       * @param string $pathname location of file
 101       * @return bool success
 102       */
 103      public abstract function add_file_from_pathname($localname, $pathname);
 104  
 105      /**
 106       * Add content of string into archive.
 107       *
 108       * @param string $localname name of file in archive
 109       * @param string $contents contents
 110       * @return bool success
 111       */
 112      public abstract function add_file_from_string($localname, $contents);
 113  
 114      /**
 115       * Add empty directory into archive.
 116       *
 117       * @param string $localname name of file in archive
 118       * @return bool success
 119       */
 120      public abstract function add_directory($localname);
 121  
 122      /**
 123       * Tries to convert $localname into another encoding,
 124       * please note that it may fail really badly.
 125       *
 126       * @param string $localname name of file in utf-8 encoding
 127       * @return string
 128       */
 129      protected function mangle_pathname($localname) {
 130          if ($this->encoding === 'utf-8') {
 131              return $localname;
 132          }
 133  
 134          $converted = core_text::convert($localname, 'utf-8', $this->encoding);
 135          $original  = core_text::convert($converted, $this->encoding, 'utf-8');
 136  
 137          if ($original === $localname) {
 138              $result = $converted;
 139  
 140          } else {
 141              // try ascii conversion
 142              $converted2 = core_text::specialtoascii($localname);
 143              $converted2 = core_text::convert($converted2, 'utf-8', $this->encoding);
 144              $original2  = core_text::convert($converted, $this->encoding, 'utf-8');
 145  
 146              if ($original2 === $localname) {
 147                  //this looks much better
 148                  $result = $converted2;
 149              } else {
 150                  //bad luck - the file name may not be usable at all
 151                  $result = $converted;
 152              }
 153          }
 154  
 155          $result = preg_replace('/\.\.+\//', '', $result); // Cleanup any potential ../ transversal (any number of dots).
 156          $result = preg_replace('/\.\.+/', '.', $result); // Join together any number of consecutive dots.
 157          $result = ltrim($result); // no leading /
 158  
 159          if ($result === '.') {
 160              $result = '';
 161          }
 162  
 163          return $result;
 164      }
 165  
 166      /**
 167       * Tries to convert $localname into utf-8
 168       * please note that it may fail really badly.
 169       * The resulting file name is cleaned.
 170       *
 171       * @param string $localname name of file in $this->encoding
 172       * @return string in utf-8
 173       */
 174      protected function unmangle_pathname($localname) {
 175          $result = str_replace('\\', '/', $localname); // no MS \ separators
 176          $result = ltrim($result, '/');                // no leading /
 177  
 178          if ($this->encoding !== 'utf-8') {
 179              $result = core_text::convert($result, $this->encoding, 'utf-8');
 180          }
 181  
 182          return clean_param($result, PARAM_PATH);
 183      }
 184  
 185      /**
 186       * Returns current file info.
 187       * @return object
 188       */
 189      //public abstract function current();
 190  
 191      /**
 192       * Returns the index of current file.
 193       * @return int current file index
 194       */
 195      //public abstract function key();
 196  
 197      /**
 198       * Moves forward to next file.
 199       * @return void
 200       */
 201      //public abstract function next();
 202  
 203      /**
 204       * Rewinds back to the first file.
 205       * @return void
 206       */
 207      //public abstract function rewind();
 208  
 209      /**
 210       * Did we reach the end?
 211       * @return boolean
 212       */
 213      //public abstract function valid();
 214  
 215  }