Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?php

namespace Box\Spout\Reader\XLSX\Manager;

use Box\Spout\Common\Exception\IOException;
use Box\Spout\Reader\Wrapper\XMLReader;
use Box\Spout\Reader\XLSX\Creator\InternalEntityFactory;

/**
 * Class WorkbookRelationshipsManager
 * This class manages the workbook relationships defined in the associated XML file
 */
class WorkbookRelationshipsManager
{
    const BASE_PATH = 'xl/';

    /** Path of workbook relationships XML file inside the XLSX file */
    const WORKBOOK_RELS_XML_FILE_PATH = 'xl/_rels/workbook.xml.rels';

< /** Relationships types */
> /** Relationships types - For Transitional and Strict OOXML */
const RELATIONSHIP_TYPE_SHARED_STRINGS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings'; const RELATIONSHIP_TYPE_STYLES = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles';
< const RELATIONSHIP_TYPE_WORKSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet';
> const RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT = 'http://purl.oclc.org/ooxml/officeDocument/relationships/sharedStrings'; > const RELATIONSHIP_TYPE_STYLES_STRICT = 'http://purl.oclc.org/ooxml/officeDocument/relationships/styles';
/** Nodes and attributes used to find relevant information in the workbook relationships XML file */ const XML_NODE_RELATIONSHIP = 'Relationship'; const XML_ATTRIBUTE_TYPE = 'Type'; const XML_ATTRIBUTE_TARGET = 'Target'; /** @var string Path of the XLSX file being read */ private $filePath; /** @var InternalEntityFactory Factory to create entities */ private $entityFactory; /** @var array Cache of the already read workbook relationships: [TYPE] => [FILE_NAME] */ private $cachedWorkbookRelationships; /** * @param string $filePath Path of the XLSX file being read * @param InternalEntityFactory $entityFactory Factory to create entities */ public function __construct($filePath, $entityFactory) { $this->filePath = $filePath; $this->entityFactory = $entityFactory; } /** * @return string The path of the shared string XML file */ public function getSharedStringsXMLFilePath() { $workbookRelationships = $this->getWorkbookRelationships();
< $sharedStringsXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS];
> $sharedStringsXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS] > ?? $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT];
// the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml")
< $doesContainBasePath = (strpos($sharedStringsXMLFilePath, self::BASE_PATH) !== false);
> $doesContainBasePath = (\strpos($sharedStringsXMLFilePath, self::BASE_PATH) !== false);
if (!$doesContainBasePath) { // make sure we return an absolute file path $sharedStringsXMLFilePath = self::BASE_PATH . $sharedStringsXMLFilePath; } return $sharedStringsXMLFilePath; } /** * @return bool Whether the XLSX file contains a shared string XML file */ public function hasSharedStringsXMLFile() { $workbookRelationships = $this->getWorkbookRelationships();
< return isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS]);
> return isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS]) > || isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT]);
} /**
< * @return string|null The path of the styles XML file
> * @return bool Whether the XLSX file contains a styles XML file > */ > public function hasStylesXMLFile() > { > $workbookRelationships = $this->getWorkbookRelationships(); > > return isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES]) > || isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT]); > } > > /** > * @return string The path of the styles XML file
*/ public function getStylesXMLFilePath() { $workbookRelationships = $this->getWorkbookRelationships();
< $stylesXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES];
> $stylesXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES] > ?? $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT];
// the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml")
< $doesContainBasePath = (strpos($stylesXMLFilePath, self::BASE_PATH) !== false);
> $doesContainBasePath = (\strpos($stylesXMLFilePath, self::BASE_PATH) !== false);
if (!$doesContainBasePath) { // make sure we return a full path $stylesXMLFilePath = self::BASE_PATH . $stylesXMLFilePath; } return $stylesXMLFilePath; } /** * Reads the workbook.xml.rels and extracts the filename associated to the different types. * It caches the result so that the file is read only once. * * @throws \Box\Spout\Common\Exception\IOException If workbook.xml.rels can't be read * @return array */ private function getWorkbookRelationships() { if (!isset($this->cachedWorkbookRelationships)) { $xmlReader = $this->entityFactory->createXMLReader(); if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_RELS_XML_FILE_PATH) === false) { throw new IOException('Could not open "' . self::WORKBOOK_RELS_XML_FILE_PATH . '".'); } $this->cachedWorkbookRelationships = []; while ($xmlReader->readUntilNodeFound(self::XML_NODE_RELATIONSHIP)) { $this->processWorkbookRelationship($xmlReader); } } return $this->cachedWorkbookRelationships; } /** * Extracts and store the data of the current workbook relationship. * * @param XMLReader $xmlReader * @return void */ private function processWorkbookRelationship($xmlReader) { $type = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TYPE); $target = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET); // @NOTE: if a type is defined more than once, we overwrite the previous value // To be changed if we want to get the file paths of sheet XML files for instance. $this->cachedWorkbookRelationships[$type] = $target; } }