ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ.outputFilePath = $outputFilePath; $errorMessage = null; set_error_handler(static function ($nr, $message) use (&$errorMessage): bool { $errorMessage = $message; return true; }); $resource = fopen($this->outputFilePath, 'w'); restore_error_handler(); if (null !== $errorMessage) { throw new IOException("Unable to open file {$this->outputFilePath}: {$errorMessage}"); } \assert(false !== $resource); $this->filePointer = $resource; $this->openWriter(); $this->isWriterOpened = true; } /** * @codeCoverageIgnore * * @param mixed $outputFileName */ final public function openToBrowser($outputFileName): void { $this->outputFilePath = basename($outputFileName); $resource = fopen('php://output', 'w'); \assert(false !== $resource); $this->filePointer = $resource; // Clear any previous output (otherwise the generated file will be corrupted) // @see https://github.com/box/spout/issues/241 if (ob_get_length() > 0) { ob_end_clean(); } /* * Set headers * * For newer browsers such as Firefox, Chrome, Opera, Safari, etc., they all support and use `filename*` * specified by the new standard, even if they do not automatically decode filename; it does not matter; * and for older versions of Internet Explorer, they are not recognized `filename*`, will automatically * ignore it and use the old `filename` (the only minor flaw is that there must be an English suffix name). * In this way, the multi-browser multi-language compatibility problem is perfectly solved, which does not * require UA judgment and is more in line with the standard. * * @see https://github.com/box/spout/issues/745 * @see https://tools.ietf.org/html/rfc6266 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition */ header('Content-Type: '.static::$headerContentType); header( 'Content-Disposition: attachment; '. 'filename="'.rawurlencode($this->outputFilePath).'"; '. 'filename*=UTF-8\'\''.rawurlencode($this->outputFilePath) ); /* * When forcing the download of a file over SSL,IE8 and lower browsers fail * if the Cache-Control and Pragma headers are not set. * * @see http://support.microsoft.com/KB/323308 * @see https://github.com/liuggio/ExcelBundle/issues/45 */ header('Cache-Control: max-age=0'); header('Pragma: public'); $this->openWriter(); $this->isWriterOpened = true; } final public function addRow(Row $row): void { if (!$this->isWriterOpened) { throw new WriterNotOpenedException('The writer needs to be opened before adding row.'); } $this->addRowToWriter($row); ++$this->writtenRowCount; } final public function addRows(array $rows): void { foreach ($rows as $row) { $this->addRow($row); } } final public function setCreator(string $creator): void { $this->creator = $creator; } final public function getWrittenRowCount(): int { return $this->writtenRowCount; } final public function close(): void { if (!$this->isWriterOpened) { return; } $this->closeWriter(); fclose($this->filePointer); $this->isWriterOpened = false; } /** * Opens the streamer and makes it ready to accept data. * * @throws IOException If the writer cannot be opened */ abstract protected function openWriter(): void; /** * Adds a row to the currently opened writer. * * @param Row $row The row containing cells and styles * * @throws WriterNotOpenedException If the workbook is not created yet * @throws IOException If unable to write data */ abstract protected function addRowToWriter(Row $row): void; /** * Closes the streamer, preventing any additional writing. */ abstract protected function closeWriter(): void; }