1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Helper;
4
5use PhpOffice\PhpSpreadsheet\IOFactory;
6use PhpOffice\PhpSpreadsheet\Spreadsheet;
7use PhpOffice\PhpSpreadsheet\Writer\IWriter;
8use PhpOffice\PhpSpreadsheet\Writer\Pdf;
9use RecursiveDirectoryIterator;
10use RecursiveIteratorIterator;
11use RecursiveRegexIterator;
12use ReflectionClass;
13use RegexIterator;
14
15/**
16 * Helper class to be used in sample code.
17 */
18class Sample
19{
20    /**
21     * Returns whether we run on CLI or browser.
22     *
23     * @return bool
24     */
25    public function isCli()
26    {
27        return PHP_SAPI === 'cli';
28    }
29
30    /**
31     * Return the filename currently being executed.
32     *
33     * @return string
34     */
35    public function getScriptFilename()
36    {
37        return basename($_SERVER['SCRIPT_FILENAME'], '.php');
38    }
39
40    /**
41     * Whether we are executing the index page.
42     *
43     * @return bool
44     */
45    public function isIndex()
46    {
47        return $this->getScriptFilename() === 'index';
48    }
49
50    /**
51     * Return the page title.
52     *
53     * @return string
54     */
55    public function getPageTitle()
56    {
57        return $this->isIndex() ? 'PHPSpreadsheet' : $this->getScriptFilename();
58    }
59
60    /**
61     * Return the page heading.
62     *
63     * @return string
64     */
65    public function getPageHeading()
66    {
67        return $this->isIndex() ? '' : '<h1>' . str_replace('_', ' ', $this->getScriptFilename()) . '</h1>';
68    }
69
70    /**
71     * Returns an array of all known samples.
72     *
73     * @return string[] [$name => $path]
74     */
75    public function getSamples()
76    {
77        // Populate samples
78        $baseDir = realpath(__DIR__ . '/../../../samples');
79        $directory = new RecursiveDirectoryIterator($baseDir);
80        $iterator = new RecursiveIteratorIterator($directory);
81        $regex = new RegexIterator($iterator, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH);
82
83        $files = [];
84        foreach ($regex as $file) {
85            $file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
86            $info = pathinfo($file);
87            $category = str_replace('_', ' ', $info['dirname']);
88            $name = str_replace('_', ' ', preg_replace('/(|\.php)/', '', $info['filename']));
89            if (!in_array($category, ['.', 'boostrap', 'templates'])) {
90                if (!isset($files[$category])) {
91                    $files[$category] = [];
92                }
93                $files[$category][$name] = $file;
94            }
95        }
96
97        // Sort everything
98        ksort($files);
99        foreach ($files as &$f) {
100            asort($f);
101        }
102
103        return $files;
104    }
105
106    /**
107     * Write documents.
108     *
109     * @param Spreadsheet $spreadsheet
110     * @param string $filename
111     * @param string[] $writers
112     */
113    public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls'])
114    {
115        // Set active sheet index to the first sheet, so Excel opens this as the first sheet
116        $spreadsheet->setActiveSheetIndex(0);
117
118        // Write documents
119        foreach ($writers as $writerType) {
120            $path = $this->getFilename($filename, mb_strtolower($writerType));
121            $writer = IOFactory::createWriter($spreadsheet, $writerType);
122            if ($writer instanceof Pdf) {
123                // PDF writer needs temporary directory
124                $tempDir = $this->getTemporaryFolder();
125                $writer->setTempDir($tempDir);
126            }
127            $callStartTime = microtime(true);
128            $writer->save($path);
129            $this->logWrite($writer, $path, $callStartTime);
130        }
131
132        $this->logEndingNotes();
133    }
134
135    /**
136     * Returns the temporary directory and make sure it exists.
137     *
138     * @return string
139     */
140    private function getTemporaryFolder()
141    {
142        $tempFolder = sys_get_temp_dir() . '/phpspreadsheet';
143        if (!is_dir($tempFolder)) {
144            if (!mkdir($tempFolder) && !is_dir($tempFolder)) {
145                throw new \RuntimeException(sprintf('Directory "%s" was not created', $tempFolder));
146            }
147        }
148
149        return $tempFolder;
150    }
151
152    /**
153     * Returns the filename that should be used for sample output.
154     *
155     * @param string $filename
156     * @param string $extension
157     *
158     * @return string
159     */
160    public function getFilename($filename, $extension = 'xlsx')
161    {
162        $originalExtension = pathinfo($filename, PATHINFO_EXTENSION);
163
164        return $this->getTemporaryFolder() . '/' . str_replace('.' . $originalExtension, '.' . $extension, basename($filename));
165    }
166
167    /**
168     * Return a random temporary file name.
169     *
170     * @param string $extension
171     *
172     * @return string
173     */
174    public function getTemporaryFilename($extension = 'xlsx')
175    {
176        $temporaryFilename = tempnam($this->getTemporaryFolder(), 'phpspreadsheet-');
177        unlink($temporaryFilename);
178
179        return $temporaryFilename . '.' . $extension;
180    }
181
182    public function log($message)
183    {
184        $eol = $this->isCli() ? PHP_EOL : '<br />';
185        echo date('H:i:s ') . $message . $eol;
186    }
187
188    /**
189     * Log ending notes.
190     */
191    public function logEndingNotes()
192    {
193        // Do not show execution time for index
194        $this->log('Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . 'MB');
195    }
196
197    /**
198     * Log a line about the write operation.
199     *
200     * @param IWriter $writer
201     * @param string $path
202     * @param float $callStartTime
203     */
204    public function logWrite(IWriter $writer, $path, $callStartTime)
205    {
206        $callEndTime = microtime(true);
207        $callTime = $callEndTime - $callStartTime;
208        $reflection = new ReflectionClass($writer);
209        $format = $reflection->getShortName();
210        $message = "Write {$format} format to <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
211
212        $this->log($message);
213    }
214
215    /**
216     * Log a line about the read operation.
217     *
218     * @param string $format
219     * @param string $path
220     * @param float $callStartTime
221     */
222    public function logRead($format, $path, $callStartTime)
223    {
224        $callEndTime = microtime(true);
225        $callTime = $callEndTime - $callStartTime;
226        $message = "Read {$format} format from <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
227
228        $this->log($message);
229    }
230}
231