| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace Box\Spout\Reader\XLSX\Manager; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use Box\Spout\Reader\Wrapper\XMLReader; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use Box\Spout\Reader\XLSX\Creator\EntityFactory; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use Box\Spout\Reader\XLSX\Sheet; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  * Class SheetManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  * This class manages XLSX sheets | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  * @package Box\Spout\Reader\XLSX\Manager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | class SheetManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     /** Paths of XML files relative to the XLSX file root */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     const WORKBOOK_XML_RELS_FILE_PATH = 'xl/_rels/workbook.xml.rels'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     const WORKBOOK_XML_FILE_PATH = 'xl/workbook.xml'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     /** Definition of XML node names used to parse data */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     const XML_NODE_WORKBOOK_VIEW = 'workbookView'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |     const XML_NODE_SHEET = 'sheet'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |     const XML_NODE_SHEETS = 'sheets'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |     const XML_NODE_RELATIONSHIP = 'Relationship'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |     /** Definition of XML attributes used to parse data */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |     const XML_ATTRIBUTE_ACTIVE_TAB = 'activeTab'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |     const XML_ATTRIBUTE_R_ID = 'r:id'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |     const XML_ATTRIBUTE_NAME = 'name'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |     const XML_ATTRIBUTE_ID = 'Id'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |     const XML_ATTRIBUTE_TARGET = 'Target'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     /** @var string Path of the XLSX file being read */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     protected $filePath; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |     /** @var \Box\Spout\Common\Manager\OptionsManagerInterface Reader's options manager */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     protected $optionsManager; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     /** @var \Box\Spout\Reader\XLSX\Manager\SharedStringsManager Manages shared strings */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     protected $sharedStringsManager; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     /** @var \Box\Spout\Common\Helper\GlobalFunctionsHelper Helper to work with global functions */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     protected $globalFunctionsHelper; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     /** @var EntityFactory Factory to create entities */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     protected $entityFactory; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |     /** @var \Box\Spout\Common\Helper\Escaper\XLSX Used to unescape XML data */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     protected $escaper; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |      * @param string $filePath Path of the XLSX file being read | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |      * @param \Box\Spout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |      * @param \Box\Spout\Reader\XLSX\Manager\SharedStringsManager Manages shared strings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |      * @param \Box\Spout\Common\Helper\Escaper\XLSX $escaper Used to unescape XML data | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |      * @param EntityFactory $entityFactory Factory to create entities | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 34 |  |     public function __construct($filePath, $optionsManager, $sharedStringsManager, $escaper, $entityFactory) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 | 34 |  |         $this->filePath = $filePath; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 34 |  |         $this->optionsManager = $optionsManager; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 | 34 |  |         $this->sharedStringsManager = $sharedStringsManager; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 34 |  |         $this->escaper = $escaper; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 | 34 |  |         $this->entityFactory = $entityFactory; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 | 34 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |      * Returns the sheets metadata of the file located at the previously given file path. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |      * The paths to the sheets' data are read from the [Content_Types].xml file. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |      * @return Sheet[] Sheets within the XLSX file | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 | 34 |  |     public function getSheets() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 | 34 |  |         $sheets = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 34 |  |         $sheetIndex = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 | 34 |  |         $activeSheetIndex = 0; // By default, the first sheet is active | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 | 34 |  |         $xmlReader = $this->entityFactory->createXMLReader(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 | 34 |  |         if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_FILE_PATH)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 | 34 |  |             while ($xmlReader->read()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 34 |  |                 if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_WORKBOOK_VIEW)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                     // The "workbookView" node is located before "sheet" nodes, ensuring that | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |                     // the active sheet is known before parsing sheets data. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 12 |  |                     $activeSheetIndex = (int) $xmlReader->getAttribute(self::XML_ATTRIBUTE_ACTIVE_TAB); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 34 |  |                 } else if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_SHEET)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 | 33 |  |                     $isSheetActive = ($sheetIndex === $activeSheetIndex); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 33 |  |                     $sheets[] = $this->getSheetFromSheetXMLNode($xmlReader, $sheetIndex, $isSheetActive); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 33 |  |                     $sheetIndex++; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 34 |  |                 } else if ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_SHEETS)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |                     // stop reading once all sheets have been read | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 | 34 |  |                     break; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |                 } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 | 34 |  |             $xmlReader->close(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 | 34 |  |         return $sheets; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |      * Returns an instance of a sheet, given the XML node describing the sheet - from "workbook.xml". | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |      * We can find the XML file path describing the sheet inside "workbook.xml.res", by mapping with the sheet ID | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |      * ("r:id" in "workbook.xml", "Id" in "workbook.xml.res"). | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |      * @param \Box\Spout\Reader\Wrapper\XMLReader $xmlReaderOnSheetNode XML Reader instance, pointing on the node describing the sheet, as defined in "workbook.xml" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |      * @param int $sheetIndexZeroBased Index of the sheet, based on order of appearance in the workbook (zero-based) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |      * @param bool $isSheetActive Whether this sheet was defined as active | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |      * @return \Box\Spout\Reader\XLSX\Sheet Sheet instance | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 | 33 |  |     protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 | 33 |  |         $sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 | 33 |  |         $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 | 33 |  |         $sheetName = $this->escaper->unescape($escapedSheetName); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 | 33 |  |         $sheetDataXMLFilePath = $this->getSheetDataXMLFilePathForSheetId($sheetId); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 | 33 |  |         return $this->entityFactory->createSheet( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 | 33 |  |             $this->filePath, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 33 |  |             $sheetDataXMLFilePath, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 33 |  |             $sheetIndexZeroBased, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 33 |  |             $sheetName, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 33 |  |             $isSheetActive, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 33 |  |             $this->optionsManager, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 | 33 |  |             $this->sharedStringsManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |         ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |      * @param string $sheetId The sheet ID, as defined in "workbook.xml" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |      * @return string The XML file path describing the sheet inside "workbook.xml.res", for the given sheet ID | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 136 |  |  |      */ | 
            
                                                        
            
                                    
            
            
                | 137 | 33 |  |     protected function getSheetDataXMLFilePathForSheetId($sheetId) | 
            
                                                        
            
                                    
            
            
                | 138 |  |  |     { | 
            
                                                        
            
                                    
            
            
                | 139 | 33 |  |         $sheetDataXMLFilePath = ''; | 
            
                                                        
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 141 |  |  |         // find the file path of the sheet, by looking at the "workbook.xml.res" file | 
            
                                                        
            
                                    
            
            
                | 142 | 33 |  |         $xmlReader = $this->entityFactory->createXMLReader(); | 
            
                                                        
            
                                    
            
            
                | 143 | 33 |  |         if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_RELS_FILE_PATH)) { | 
            
                                                        
            
                                    
            
            
                | 144 | 33 |  |             while ($xmlReader->read()) { | 
            
                                                        
            
                                    
            
            
                | 145 | 33 |  |                 if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_RELATIONSHIP)) { | 
            
                                                        
            
                                    
            
            
                | 146 | 33 |  |                     $relationshipSheetId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_ID); | 
            
                                                        
            
                                    
            
            
                | 147 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 148 | 33 |  |                     if ($relationshipSheetId === $sheetId) { | 
            
                                                        
            
                                    
            
            
                | 149 |  |  |                         // In workbook.xml.rels, it is only "worksheets/sheet1.xml" | 
            
                                                        
            
                                    
            
            
                | 150 |  |  |                         // In [Content_Types].xml, the path is "/xl/worksheets/sheet1.xml" | 
            
                                                        
            
                                    
            
            
                | 151 | 33 |  |                         $sheetDataXMLFilePath = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET); | 
            
                                                        
            
                                    
            
            
                | 152 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 153 |  |  |                         // sometimes, the sheet data file path already contains "/xl/"... | 
            
                                                        
            
                                    
            
            
                | 154 | 33 |  |                         if (strpos($sheetDataXMLFilePath, '/xl/') !== 0) { | 
            
                                                        
            
                                    
            
            
                | 155 | 32 |  |                             $sheetDataXMLFilePath = '/xl/' . $sheetDataXMLFilePath; | 
            
                                                        
            
                                    
            
            
                | 156 | 32 |  |                             break; | 
            
                                                        
            
                                    
            
            
                | 157 |  |  |                         } | 
            
                                                        
            
                                    
            
            
                | 158 |  |  |                     } | 
            
                                                        
            
                                    
            
            
                | 159 |  |  |                 } | 
            
                                                        
            
                                    
            
            
                | 160 |  |  |             } | 
            
                                                        
            
                                    
            
            
                | 161 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 162 | 33 |  |             $xmlReader->close(); | 
            
                                                        
            
                                    
            
            
                | 163 |  |  |         } | 
            
                                                        
            
                                    
            
            
                | 164 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 165 | 33 |  |         return $sheetDataXMLFilePath; | 
            
                                                        
            
                                    
            
            
                | 166 |  |  |     } | 
            
                                                        
            
                                    
            
            
                | 167 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 168 |  |  |  |