Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Reader\Xml;
   4  
   5  use PhpOffice\PhpSpreadsheet\Document\Properties as DocumentProperties;
   6  use PhpOffice\PhpSpreadsheet\Spreadsheet;
   7  use SimpleXMLElement;
   8  
   9  class Properties
  10  {
  11      /**
  12       * @var Spreadsheet
  13       */
  14      protected $spreadsheet;
  15  
  16      public function __construct(Spreadsheet $spreadsheet)
  17      {
  18          $this->spreadsheet = $spreadsheet;
  19      }
  20  
  21      public function readProperties(SimpleXMLElement $xml, array $namespaces): void
  22      {
  23          $this->readStandardProperties($xml);
  24          $this->readCustomProperties($xml, $namespaces);
  25      }
  26  
  27      protected function readStandardProperties(SimpleXMLElement $xml): void
  28      {
  29          if (isset($xml->DocumentProperties[0])) {
  30              $docProps = $this->spreadsheet->getProperties();
  31  
  32              foreach ($xml->DocumentProperties[0] as $propertyName => $propertyValue) {
  33                  $propertyValue = (string) $propertyValue;
  34  
  35                  $this->processStandardProperty($docProps, $propertyName, $propertyValue);
  36              }
  37          }
  38      }
  39  
  40      protected function readCustomProperties(SimpleXMLElement $xml, array $namespaces): void
  41      {
  42          if (isset($xml->CustomDocumentProperties) && is_iterable($xml->CustomDocumentProperties[0])) {
  43              $docProps = $this->spreadsheet->getProperties();
  44  
  45              foreach ($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) {
  46                  $propertyAttributes = self::getAttributes($propertyValue, $namespaces['dt']);
  47                  $propertyName = (string) preg_replace_callback('/_x([0-9a-f]{4})_/i', [$this, 'hex2str'], $propertyName);
  48  
  49                  $this->processCustomProperty($docProps, $propertyName, $propertyValue, $propertyAttributes);
  50              }
  51          }
  52      }
  53  
  54      protected function processStandardProperty(
  55          DocumentProperties $docProps,
  56          string $propertyName,
  57          string $stringValue
  58      ): void {
  59          switch ($propertyName) {
  60              case 'Title':
  61                  $docProps->setTitle($stringValue);
  62  
  63                  break;
  64              case 'Subject':
  65                  $docProps->setSubject($stringValue);
  66  
  67                  break;
  68              case 'Author':
  69                  $docProps->setCreator($stringValue);
  70  
  71                  break;
  72              case 'Created':
  73                  $docProps->setCreated($stringValue);
  74  
  75                  break;
  76              case 'LastAuthor':
  77                  $docProps->setLastModifiedBy($stringValue);
  78  
  79                  break;
  80              case 'LastSaved':
  81                  $docProps->setModified($stringValue);
  82  
  83                  break;
  84              case 'Company':
  85                  $docProps->setCompany($stringValue);
  86  
  87                  break;
  88              case 'Category':
  89                  $docProps->setCategory($stringValue);
  90  
  91                  break;
  92              case 'Manager':
  93                  $docProps->setManager($stringValue);
  94  
  95                  break;
  96              case 'HyperlinkBase':
  97                  $docProps->setHyperlinkBase($stringValue);
  98  
  99                  break;
 100              case 'Keywords':
 101                  $docProps->setKeywords($stringValue);
 102  
 103                  break;
 104              case 'Description':
 105                  $docProps->setDescription($stringValue);
 106  
 107                  break;
 108          }
 109      }
 110  
 111      protected function processCustomProperty(
 112          DocumentProperties $docProps,
 113          string $propertyName,
 114          ?SimpleXMLElement $propertyValue,
 115          SimpleXMLElement $propertyAttributes
 116      ): void {
 117          switch ((string) $propertyAttributes) {
 118              case 'boolean':
 119                  $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN;
 120                  $propertyValue = (bool) (string) $propertyValue;
 121  
 122                  break;
 123              case 'integer':
 124                  $propertyType = DocumentProperties::PROPERTY_TYPE_INTEGER;
 125                  $propertyValue = (int) $propertyValue;
 126  
 127                  break;
 128              case 'float':
 129                  $propertyType = DocumentProperties::PROPERTY_TYPE_FLOAT;
 130                  $propertyValue = (float) $propertyValue;
 131  
 132                  break;
 133              case 'dateTime.tz':
 134              case 'dateTime.iso8601tz':
 135                  $propertyType = DocumentProperties::PROPERTY_TYPE_DATE;
 136                  $propertyValue = trim((string) $propertyValue);
 137  
 138                  break;
 139              default:
 140                  $propertyType = DocumentProperties::PROPERTY_TYPE_STRING;
 141                  $propertyValue = trim((string) $propertyValue);
 142  
 143                  break;
 144          }
 145  
 146          $docProps->setCustomProperty($propertyName, $propertyValue, $propertyType);
 147      }
 148  
 149      protected function hex2str(array $hex): string
 150      {
 151          return mb_chr((int) hexdec($hex[1]), 'UTF-8');
 152      }
 153  
 154      private static function getAttributes(?SimpleXMLElement $simple, string $node): SimpleXMLElement
 155      {
 156          return ($simple === null) ? new SimpleXMLElement('<xml></xml>') : ($simple->attributes($node) ?? new SimpleXMLElement('<xml></xml>'));
 157      }
 158  }