Merge branch 'fix/MDL-52666' of https://github.com/mikr0/moodle
[moodle.git] / lib / spout / README.md
blob6bb73aab19ce8b446ec052e1a393b9a610976d12
1 # Spout
3 [![Latest Stable Version](https://poser.pugx.org/box/spout/v/stable)](https://packagist.org/packages/box/spout)
4 [![Project Status](http://opensource.box.com/badges/active.svg)](http://opensource.box.com/badges)
5 [![Build Status](https://travis-ci.org/box/spout.svg?branch=master)](https://travis-ci.org/box/spout)
6 [![Code Coverage](https://scrutinizer-ci.com/g/box/spout/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/box/spout/?branch=master)
7 [![Total Downloads](https://poser.pugx.org/box/spout/downloads)](https://packagist.org/packages/box/spout)
8 [![License](https://poser.pugx.org/box/spout/license)](https://packagist.org/packages/box/spout)
10 Spout is a PHP library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way.
11 Contrary to other file readers or writers, it is capable of processing very large files while keeping the memory usage really low (less than 10MB).
13 Join the community and come discuss about Spout: [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/box/spout?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
15 ## Installation
17 ### Composer (recommended)
19 Spout can be installed directly from [Composer](https://getcomposer.org/).
21 Run the following command:
22 ```
23 $ composer require box/spout
24 ```
26 ### Manual installation
28 If you can't use Composer, no worries! You can still install Spout manually.
30 > Before starting, make sure your system meets the [requirements](#requirements).
32 1. Download the source code from the [Releases page](https://github.com/box/spout/releases)
33 2. Extract the downloaded content into your project.
34 3. Add this code to the top controller (index.php) or wherever it may be more appropriate:
35 ```php
36 require_once '[PATH/TO]/src/Spout/Autoloader/autoload.php'; // don't forget to change the path!
37 ```
40 ## Requirements
42 * PHP version 5.4.0 or higher
43 * PHP extension `php_zip` enabled
44 * PHP extension `php_xmlreader` enabled
45 * PHP extension `php_simplexml` enabled
48 ## Basic usage
50 ### Reader
52 Regardless of the file type, the interface to read a file is always the same:
54 ```php
55 use Box\Spout\Reader\ReaderFactory;
56 use Box\Spout\Common\Type;
58 $reader = ReaderFactory::create(Type::XLSX); // for XLSX files
59 //$reader = ReaderFactory::create(Type::CSV); // for CSV files
60 //$reader = ReaderFactory::create(Type::ODS); // for ODS files
62 $reader->open($filePath);
64 foreach ($reader->getSheetIterator() as $sheet) {
65     foreach ($sheet->getRowIterator() as $row) {
66         // do stuff with the row
67     }
70 $reader->close();
71 ```
73 If there are multiple sheets in the file, the reader will read all of them sequentially.
75 ### Writer
77 As with the reader, there is one common interface to write data to a file:
79 ```php
80 use Box\Spout\Writer\WriterFactory;
81 use Box\Spout\Common\Type;
83 $writer = WriterFactory::create(Type::XLSX); // for XLSX files
84 //$writer = WriterFactory::create(Type::CSV); // for CSV files
85 //$writer = WriterFactory::create(Type::ODS); // for ODS files
87 $writer->openToFile($filePath); // write data to a file or to a PHP stream
88 //$writer->openToBrowser($fileName); // stream data directly to the browser
90 $writer->addRow($singleRow); // add a row at a time
91 $writer->addRows($multipleRows); // add multiple rows at a time
93 $writer->close();
94 ```
96 For XLSX and ODS files, the number of rows per sheet is limited to 1,048,576. By default, once this limit is reached, the writer will automatically create a new sheet and continue writing data into it.
99 ## Advanced usage
101 If you are looking for  how to perform some common, more advanced tasks with Spout, please take a look at the [Wiki](https://github.com/box/spout/wiki). It contains code snippets, ready to be used.
103 ### Configuring the CSV reader and writer
105 It is possible to configure both the CSV reader and writer to specify the field separator as well as the field enclosure:
106 ```php
107 use Box\Spout\Reader\ReaderFactory;
108 use Box\Spout\Common\Type;
110 $reader = ReaderFactory::create(Type::CSV);
111 $reader->setFieldDelimiter('|');
112 $reader->setFieldEnclosure('@');
113 $reader->setEndOfLineCharacter("\r");
116 Additionally, if you need to read non UTF-8 files, you can specify the encoding of your file this way:
117 ```php
118 $reader->setEncoding('UTF-16LE');
121 The writer always generate CSV files encoded in UTF-8, with a BOM.
124 ### Configuring the XLSX and ODS writers
126 #### Row styling
128 It is possible to apply some formatting options to a row. Spout supports fonts as well as alignment styles.
130 ```php
131 use Box\Spout\Common\Type;
132 use Box\Spout\Writer\WriterFactory;
133 use Box\Spout\Writer\Style\StyleBuilder;
134 use Box\Spout\Writer\Style\Color;
136 $style = (new StyleBuilder())
137            ->setFontBold()
138            ->setFontSize(15)
139            ->setFontColor(Color::BLUE)
140            ->setShouldWrapText()
141            ->build();
143 $writer = WriterFactory::create(Type::XLSX);
144 $writer->openToFile($filePath);
146 $writer->addRowWithStyle($singleRow, $style); // style will only be applied to this row
147 $writer->addRow($otherSingleRow); // no style will be applied
148 $writer->addRowsWithStyle($multipleRows, $style); // style will be applied to all given rows
150 $writer->close();
153 Unfortunately, Spout does not support all the possible formatting options yet. But you can find the most important ones:
155 Category  | Property      | API
156 ----------|---------------|---------------------------------------
157 Font      | Bold          | `StyleBuilder::setFontBold()`
158           | Italic        | `StyleBuilder::setFontItalic()`
159           | Underline     | `StyleBuilder::setFontUnderline()`
160           | Strikethrough | `StyleBuilder::setFontStrikethrough()`
161           | Font name     | `StyleBuilder::setFontName('Arial')`
162           | Font size     | `StyleBuilder::setFontSize(14)`
163           | Font color    | `StyleBuilder::setFontColor(Color::BLUE)`<br>`StyleBuilder::setFontColor(Color::rgb(0, 128, 255))`
164 Alignment | Wrap text     | `StyleBuilder::setShouldWrapText()`
167 #### New sheet creation
169 It is also possible to change the behavior of the writer when the maximum number of rows (1,048,576) have been written in the current sheet:
170 ```php
171 use Box\Spout\Writer\WriterFactory;
172 use Box\Spout\Common\Type;
174 $writer = WriterFactory::create(Type::ODS);
175 $writer->setShouldCreateNewSheetsAutomatically(true); // default value
176 $writer->setShouldCreateNewSheetsAutomatically(false); // will stop writing new data when limit is reached
179 #### Using custom temporary folder
181 Processing XLSX and ODS files require temporary files to be created. By default, Spout will use the system default temporary folder (as returned by `sys_get_temp_dir()`). It is possible to override this by explicitly setting it on the reader or writer:
182 ```php
183 use Box\Spout\Writer\WriterFactory;
184 use Box\Spout\Common\Type;
186 $writer = WriterFactory::create(Type::XLSX);
187 $writer->setTempFolder($customTempFolderPath);
190 #### Strings storage (XLSX writer)
192 XLSX files support different ways to store the string values:
193 * Shared strings are meant to optimize file size by separating strings from the sheet representation and ignoring strings duplicates (if a string is used three times, only one string will be stored)
194 * Inline strings are less optimized (as duplicate strings are all stored) but is faster to process
196 In order to keep the memory usage really low, Spout does not optimize strings when using shared strings. It is nevertheless possible to use this mode.
197 ```php
198 use Box\Spout\Writer\WriterFactory;
199 use Box\Spout\Common\Type;
201 $writer = WriterFactory::create(Type::XLSX);
202 $writer->setShouldUseInlineStrings(true); // default (and recommended) value
203 $writer->setShouldUseInlineStrings(false); // will use shared strings
206 > ##### Note on Apple Numbers and iOS support
208 > Apple's products (Numbers and the iOS previewer) don't support inline strings and display empty cells instead. Therefore, if these platforms need to be supported, make sure to use shared strings!
211 ### Playing with sheets
213 When creating a XLSX or ODS file, it is possible to control which sheet the data will be written into. At any time, you can retrieve or set the current sheet:
214 ```php
215 $firstSheet = $writer->getCurrentSheet();
216 $writer->addRow($rowForSheet1); // writes the row to the first sheet
218 $newSheet = $writer->addNewSheetAndMakeItCurrent();
219 $writer->addRow($rowForSheet2); // writes the row to the new sheet
221 $writer->setCurrentSheet($firstSheet);
222 $writer->addRow($anotherRowForSheet1); // append the row to the first sheet
225 It is also possible to retrieve all the sheets currently created:
226 ```php
227 $sheets = $writer->getSheets();
230 If you rely on the sheet's name in your application, you can access it and customize it this way:
231 ```php
232 // Accessing the sheet name when reading
233 foreach ($reader->getSheetIterator() as $sheet) {
234     $sheetName = $sheet->getName();
237 // Accessing the sheet name when writing
238 $sheet = $writer->getCurrentSheet();
239 $sheetName = $sheet->getName();
241 // Customizing the sheet name when writing
242 $sheet = $writer->getCurrentSheet();
243 $sheet->setName('My custom name');
244 ``` 
246 > Please note that Excel has some restrictions on the sheet's name:
247 > * it must not be blank
248 > * it must not exceed 31 characters
249 > * it must not contain these characters: \ / ? * : [ or ]
250 > * it must not start or end with a single quote
251 > * it must be unique
253 > Handling these restrictions is the developer's responsibility. Spout does not try to automatically change the sheet's name, as one may rely on this name to be exactly what was passed in.
256 ### Fluent interface
258 Because fluent interfaces are great, you can use them with Spout:
259 ```php
260 use Box\Spout\Writer\WriterFactory;
261 use Box\Spout\Common\Type;
263 $writer = WriterFactory::create(Type::XLSX);
264 $writer->setTempFolder($customTempFolderPath)
265        ->setShouldUseInlineStrings(true)
266        ->openToFile($filePath)
267        ->addRow($headerRow)
268        ->addRows($dataRows)
269        ->close();
273 ## Running tests
275 On the `master` branch, only unit and functional tests are included. The performance tests require very large files and have been excluded.
276 If you just want to check that everything is working as expected, executing the tests of the `master` branch is enough.
278 If you want to run performance tests, you will need to checkout the `perf-tests` branch. Multiple test suites can then be run, depending on the expected output:
280 * `phpunit` - runs the whole test suite (unit + functional + performance tests)
281 * `phpunit --exclude-group perf-tests` - only runs the unit and functional tests
282 * `phpunit --group perf-tests` - only runs the performance tests
284 For information, the performance tests take about 30 minutes to run (processing 1 million rows files is not a quick thing).
286 > Performance tests status: [![Build Status](https://travis-ci.org/box/spout.svg?branch=perf-tests)](https://travis-ci.org/box/spout)
289 ## Frequently Asked Questions
291 #### How can Spout handle such large data sets and still use less than 10MB of memory?
293 When writing data, Spout is streaming the data to files, one or few lines at a time. That means that it only keeps in memory the few rows that it needs to write. Once written, the memory is freed.
295 Same goes with reading. Only one row at a time is stored in memory. A special technique is used to handle shared strings in XLSX, storing them - if needed - into several small temporary files that allows fast access.
297 #### How long does it take to generate a file with X rows?
299 Here are a few numbers regarding the performance of Spout:
301 | Type | Action                        | 2,000 rows (6,000 cells) | 200,000 rows (600,000 cells) | 2,000,000 rows (6,000,000 cells) |
302 |------|-------------------------------|--------------------------|------------------------------|----------------------------------|
303 | CSV  | Read                          | < 1 second               | 4 seconds                    | 2-3 minutes                      |
304 |      | Write                         | < 1 second               | 2 seconds                    | 2-3 minutes                      |
305 | XLSX | Read<br>*inline&nbsp;strings* | < 1 second               | 35-40 seconds                | 18-20 minutes                    |
306 |      | Read<br>*shared&nbsp;strings* | 1 second                 | 1-2 minutes                  | 35-40 minutes                    |
307 |      | Write                         | 1 second                 | 20-25 seconds                | 8-10 minutes                     |
308 | ODS  | Read                          | 1 second                 | 1-2 minutes                  | 5-6 minutes                      |
309 |      | Write                         | < 1 second               | 35-40 seconds                | 5-6 minutes                      |
311 #### Does Spout support charts or formulas?
313 No. This is a compromise to keep memory usage low. Charts and formulas requires data to be kept in memory in order to be used.
314 So the larger the file would be, the more memory would be consumed, preventing your code to scale well.
317 ## Support
319 Need to contact us directly? Email oss@box.com and be sure to include the name of this project in the subject.
321 You can also ask questions, submit new features ideas or discuss about Spout in the chat room:<br>
322 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/box/spout?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
324 ## Copyright and License
326 Copyright 2015 Box, Inc. All rights reserved.
328 Licensed under the Apache License, Version 2.0 (the "License");
329 you may not use this file except in compliance with the License.
330 You may obtain a copy of the License at
332    http://www.apache.org/licenses/LICENSE-2.0
334 Unless required by applicable law or agreed to in writing, software
335 distributed under the License is distributed on an "AS IS" BASIS,
336 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
337 See the License for the specific language governing permissions and
338 limitations under the License.