Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
   4  
   5  use PhpOffice\PhpSpreadsheet\Document\Properties as DocumentProperties;
   6  use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
   7  use PhpOffice\PhpSpreadsheet\Settings;
   8  use SimpleXMLElement;
   9  
  10  class Properties
  11  {
  12      /** @var XmlScanner */
  13      private $securityScanner;
  14  
  15      /** @var DocumentProperties */
  16      private $docProps;
  17  
  18      public function __construct(XmlScanner $securityScanner, DocumentProperties $docProps)
  19      {
  20          $this->securityScanner = $securityScanner;
  21          $this->docProps = $docProps;
  22      }
  23  
  24      /**
  25       * @param mixed $obj
  26       */
  27      private static function nullOrSimple($obj): ?SimpleXMLElement
  28      {
  29          return ($obj instanceof SimpleXMLElement) ? $obj : null;
  30      }
  31  
  32      private function extractPropertyData(string $propertyData): ?SimpleXMLElement
  33      {
  34          // okay to omit namespace because everything will be processed by xpath
  35          $obj = simplexml_load_string(
  36              $this->securityScanner->scan($propertyData),
  37              'SimpleXMLElement',
  38              Settings::getLibXmlLoaderOptions()
  39          );
  40  
  41          return self::nullOrSimple($obj);
  42      }
  43  
  44      public function readCoreProperties(string $propertyData): void
  45      {
  46          $xmlCore = $this->extractPropertyData($propertyData);
  47  
  48          if (is_object($xmlCore)) {
  49              $xmlCore->registerXPathNamespace('dc', Namespaces::DC_ELEMENTS);
  50              $xmlCore->registerXPathNamespace('dcterms', Namespaces::DC_TERMS);
  51              $xmlCore->registerXPathNamespace('cp', Namespaces::CORE_PROPERTIES2);
  52  
  53              $this->docProps->setCreator((string) self::getArrayItem($xmlCore->xpath('dc:creator')));
  54              $this->docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath('cp:lastModifiedBy')));
  55              $this->docProps->setCreated((string) self::getArrayItem($xmlCore->xpath('dcterms:created'))); //! respect xsi:type
  56              $this->docProps->setModified((string) self::getArrayItem($xmlCore->xpath('dcterms:modified'))); //! respect xsi:type
  57              $this->docProps->setTitle((string) self::getArrayItem($xmlCore->xpath('dc:title')));
  58              $this->docProps->setDescription((string) self::getArrayItem($xmlCore->xpath('dc:description')));
  59              $this->docProps->setSubject((string) self::getArrayItem($xmlCore->xpath('dc:subject')));
  60              $this->docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath('cp:keywords')));
  61              $this->docProps->setCategory((string) self::getArrayItem($xmlCore->xpath('cp:category')));
  62          }
  63      }
  64  
  65      public function readExtendedProperties(string $propertyData): void
  66      {
  67          $xmlCore = $this->extractPropertyData($propertyData);
  68  
  69          if (is_object($xmlCore)) {
  70              if (isset($xmlCore->Company)) {
  71                  $this->docProps->setCompany((string) $xmlCore->Company);
  72              }
  73              if (isset($xmlCore->Manager)) {
  74                  $this->docProps->setManager((string) $xmlCore->Manager);
  75              }
  76          }
  77      }
  78  
  79      public function readCustomProperties(string $propertyData): void
  80      {
  81          $xmlCore = $this->extractPropertyData($propertyData);
  82  
  83          if (is_object($xmlCore)) {
  84              foreach ($xmlCore as $xmlProperty) {
  85                  /** @var SimpleXMLElement $xmlProperty */
  86                  $cellDataOfficeAttributes = $xmlProperty->attributes();
  87                  if (isset($cellDataOfficeAttributes['name'])) {
  88                      $propertyName = (string) $cellDataOfficeAttributes['name'];
  89                      $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
  90  
  91                      $attributeType = $cellDataOfficeChildren->getName();
  92                      $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
  93                      $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType);
  94                      $attributeType = DocumentProperties::convertPropertyType($attributeType);
  95                      $this->docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
  96                  }
  97              }
  98          }
  99      }
 100  
 101      /**
 102       * @param array|false $array
 103       * @param mixed $key
 104       */
 105      private static function getArrayItem($array, $key = 0): ?SimpleXMLElement
 106      {
 107          return is_array($array) ? ($array[$key] ?? null) : null;
 108      }
 109  }