Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is 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   * This class represent one XMLDB file
  19   *
  20   * @package    core_xmldb
  21   * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
  22   *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  
  29  class xmldb_file extends xmldb_object {
  30  
  31      /** @var string path to file */
  32      protected $path;
  33  
  34      /** @var string path to schema */
  35      protected $schema;
  36  
  37      /** @var  string document dtd */
  38      protected $dtd;
  39  
  40      /** @var xmldb_structure the structure stored in file */
  41      protected $xmldb_structure;
  42  
  43      /**
  44       * Constructor of the xmldb_file
  45       * @param string $path
  46       */
  47      public function __construct($path) {
  48          parent::__construct($path);
  49          $this->path = $path;
  50          $this->xmldb_structure = null;
  51      }
  52  
  53      /**
  54       * Determine if the XML file exists
  55       * @return bool
  56       */
  57      public function fileExists() {
  58          if (file_exists($this->path) && is_readable($this->path)) {
  59              return true;
  60          }
  61          return false;
  62      }
  63  
  64      /**
  65       * Determine if the XML is writeable
  66       * @return bool
  67       */
  68      public function fileWriteable() {
  69          if (is_writeable(dirname($this->path))) {
  70              return true;
  71          }
  72          return false;
  73      }
  74  
  75      public function getStructure() {
  76          return $this->xmldb_structure;
  77      }
  78  
  79      /**
  80       * This function will check/validate the XML file for correctness
  81       * Dynamically if will use the best available checker/validator
  82       * (expat syntax checker or DOM schema validator
  83       * @return true
  84       */
  85      public function validateXMLStructure() {
  86  
  87          // Create and load XML file
  88          $parser = new DOMDocument();
  89          $contents = file_get_contents($this->path);
  90          if (strpos($contents, '<STATEMENTS>')) {
  91              //delete the removed STATEMENTS section, it would not validate
  92              $contents = preg_replace('|<STATEMENTS>.*</STATEMENTS>|s', '', $contents);
  93          }
  94  
  95          // Let's capture errors
  96          $olderrormode = libxml_use_internal_errors(true);
  97  
  98          // Clear XML error flag so that we don't incorrectly report failure
  99          // when a previous xml parse failed
 100          libxml_clear_errors();
 101  
 102          $parser->loadXML($contents);
 103          // Only validate if we have a schema
 104          if (!empty($this->schema) && file_exists($this->schema)) {
 105              $parser->schemaValidate($this->schema);
 106          }
 107          // Check for errors
 108          $errors = libxml_get_errors();
 109  
 110          // Stop capturing errors
 111          libxml_use_internal_errors($olderrormode);
 112  
 113          // Prepare errors
 114          if (!empty($errors)) {
 115              // Create one structure to store errors
 116              $structure = new xmldb_structure($this->path);
 117              // Add errors to structure
 118              $structure->errormsg = 'XML Error: ';
 119              foreach ($errors as $error) {
 120                  $structure->errormsg .= sprintf("%s at line %d. ",
 121                                                   trim($error->message, "\n\r\t ."),
 122                                                   $error->line);
 123              }
 124              // Add structure to file
 125              $this->xmldb_structure = $structure;
 126              // Check has failed
 127              return false;
 128          }
 129  
 130          return true;
 131      }
 132  
 133      /**
 134       * Load and the XMLDB structure from file
 135       * @return true
 136       */
 137      public function loadXMLStructure() {
 138          if ($this->fileExists()) {
 139              // Let's validate the XML file
 140              if (!$this->validateXMLStructure()) {
 141                  return false;
 142              }
 143              $contents = file_get_contents($this->path);
 144              if (strpos($contents, '<STATEMENTS>')) {
 145                  //delete the removed STATEMENTS section, it would not validate
 146                  $contents = preg_replace('|<STATEMENTS>.*</STATEMENTS>|s', '', $contents);
 147                  debugging('STATEMENTS section is not supported any more, please use db/install.php or db/log.php');
 148              }
 149              // File exists, so let's process it
 150              // Load everything to a big array
 151              $xmlarr = xmlize($contents);
 152              // Convert array to xmldb structure
 153              $this->xmldb_structure = $this->arr2xmldb_structure($xmlarr);
 154              // Analyze results
 155              if ($this->xmldb_structure->isLoaded()) {
 156                  $this->loaded = true;
 157                  return true;
 158              } else {
 159                  return false;
 160              }
 161          }
 162          return true;
 163      }
 164  
 165      /**
 166       * This function takes an xmlized array and put it into one xmldb_structure
 167       * @param array $xmlarr
 168       * @return xmldb_structure
 169       */
 170      public function arr2xmldb_structure ($xmlarr) {
 171          $structure = new xmldb_structure($this->path);
 172          $structure->arr2xmldb_structure($xmlarr);
 173          return $structure;
 174      }
 175  
 176      /**
 177       * This function sets the DTD of the XML file
 178       * @param string
 179       */
 180      public function setDTD($path) {
 181          $this->dtd = $path;
 182      }
 183  
 184      /**
 185       * This function sets the schema of the XML file
 186       * @param string
 187       */
 188      public function setSchema($path) {
 189          $this->schema = $path;
 190      }
 191  
 192      /**
 193       * This function saves the whole xmldb_structure to its file
 194       * @return int|bool false on failure, number of written bytes on success
 195       */
 196      public function saveXMLFile() {
 197  
 198          $structure = $this->getStructure();
 199  
 200          $result = file_put_contents($this->path, $structure->xmlOutput());
 201  
 202          return $result;
 203      }
 204  }