PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.5
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.5
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Spout / Reader / XLSX / Helper / SharedStringsCaching / FileBasedStrategy.php

FileBasedStrategy.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.5, at app/Services/Spout/Reader/XLSX/Helper/SharedStringsCaching/FileBasedStrategy.php

194 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Box\Spout\Reader\XLSX\Helper\SharedStringsCaching;
4
5 use Box\Spout\Common\Helper\FileSystemHelper;
6 use Box\Spout\Common\Helper\GlobalFunctionsHelper;
7 use Box\Spout\Reader\Exception\SharedStringNotFoundException;
8
9 /**
10 * Class FileBasedStrategy
11 *
12 * This class implements the file-based caching strategy for shared strings.
13 * Shared strings are stored in small files (with a max number of strings per file).
14 * This strategy is slower than an in-memory strategy but is used to avoid out of memory crashes.
15 *
16 * @package Box\Spout\Reader\XLSX\Helper\SharedStringsCaching
17 */
18 class FileBasedStrategy implements CachingStrategyInterface
19 {
20 /** Value to use to escape the line feed character ("\n") */
21 const ESCAPED_LINE_FEED_CHARACTER = '_x000A_';
22
23 /** @var \Box\Spout\Common\Helper\GlobalFunctionsHelper Helper to work with global functions */
24 protected $globalFunctionsHelper;
25
26 /** @var \Box\Spout\Common\Helper\FileSystemHelper Helper to perform file system operations */
27 protected $fileSystemHelper;
28
29 /** @var string Temporary folder where the temporary files will be created */
30 protected $tempFolder;
31
32 /**
33 * @var int Maximum number of strings that can be stored in one temp file
34 * @see CachingStrategyFactory::MAX_NUM_STRINGS_PER_TEMP_FILE
35 */
36 protected $maxNumStringsPerTempFile;
37
38 /** @var resource Pointer to the last temp file a shared string was written to */
39 protected $tempFilePointer;
40
41 /**
42 * @var string Path of the temporary file whose contents is currently stored in memory
43 * @see CachingStrategyFactory::MAX_NUM_STRINGS_PER_TEMP_FILE
44 */
45 protected $inMemoryTempFilePath;
46
47 /**
48 * @var array Contents of the temporary file that was last read
49 * @see CachingStrategyFactory::MAX_NUM_STRINGS_PER_TEMP_FILE
50 */
51 protected $inMemoryTempFileContents;
52
53 /**
54 * @param string|null $tempFolder Temporary folder where the temporary files to store shared strings will be stored
55 * @param int $maxNumStringsPerTempFile Maximum number of strings that can be stored in one temp file
56 */
57 public function __construct($tempFolder, $maxNumStringsPerTempFile)
58 {
59 $rootTempFolder = ($tempFolder) ?: sys_get_temp_dir();
60 $this->fileSystemHelper = new FileSystemHelper($rootTempFolder);
61 $this->tempFolder = $this->fileSystemHelper->createFolder($rootTempFolder, uniqid('sharedstrings'));
62
63 $this->maxNumStringsPerTempFile = $maxNumStringsPerTempFile;
64
65 $this->globalFunctionsHelper = new GlobalFunctionsHelper();
66 $this->tempFilePointer = null;
67 }
68
69 /**
70 * Adds the given string to the cache.
71 *
72 * @param string $sharedString The string to be added to the cache
73 * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
74 * @return void
75 */
76 public function addStringForIndex($sharedString, $sharedStringIndex)
77 {
78 $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex);
79
80 if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) {
81 if ($this->tempFilePointer) {
82 $this->globalFunctionsHelper->fclose($this->tempFilePointer);
83 }
84 $this->tempFilePointer = $this->globalFunctionsHelper->fopen($tempFilePath, 'w');
85 }
86
87 // The shared string retrieval logic expects each cell data to be on one line only
88 // Encoding the line feed character allows to preserve this assumption
89 $lineFeedEncodedSharedString = $this->escapeLineFeed($sharedString);
90
91 $this->globalFunctionsHelper->fwrite($this->tempFilePointer, $lineFeedEncodedSharedString . PHP_EOL);
92 }
93
94 /**
95 * Returns the path for the temp file that should contain the string for the given index
96 *
97 * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
98 * @return string The temp file path for the given index
99 */
100 protected function getSharedStringTempFilePath($sharedStringIndex)
101 {
102 $numTempFile = intval($sharedStringIndex / $this->maxNumStringsPerTempFile);
103 return $this->tempFolder . '/sharedstrings' . $numTempFile;
104 }
105
106 /**
107 * Closes the cache after the last shared string was added.
108 * This prevents any additional string from being added to the cache.
109 *
110 * @return void
111 */
112 public function closeCache()
113 {
114 // close pointer to the last temp file that was written
115 if ($this->tempFilePointer) {
116 $this->globalFunctionsHelper->fclose($this->tempFilePointer);
117 }
118 }
119
120
121 /**
122 * Returns the string located at the given index from the cache.
123 *
124 * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
125 * @return string The shared string at the given index
126 * @throws \Box\Spout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index
127 */
128 public function getStringAtIndex($sharedStringIndex)
129 {
130 $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex);
131 $indexInFile = $sharedStringIndex % $this->maxNumStringsPerTempFile;
132
133 if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) {
134 throw new SharedStringNotFoundException("Shared string temp file not found: $tempFilePath ; for index: $sharedStringIndex");
135 }
136
137 if ($this->inMemoryTempFilePath !== $tempFilePath) {
138 // free memory
139 unset($this->inMemoryTempFileContents);
140
141 $this->inMemoryTempFileContents = explode(PHP_EOL, $this->globalFunctionsHelper->file_get_contents($tempFilePath));
142 $this->inMemoryTempFilePath = $tempFilePath;
143 }
144
145 $sharedString = null;
146
147 // Using isset here because it is way faster than array_key_exists...
148 if (isset($this->inMemoryTempFileContents[$indexInFile])) {
149 $escapedSharedString = $this->inMemoryTempFileContents[$indexInFile];
150 $sharedString = $this->unescapeLineFeed($escapedSharedString);
151 }
152
153 if ($sharedString === null) {
154 throw new SharedStringNotFoundException("Shared string not found for index: $sharedStringIndex");
155 }
156
157 return rtrim($sharedString, PHP_EOL);
158 }
159
160 /**
161 * Escapes the line feed characters (\n)
162 *
163 * @param string $unescapedString
164 * @return string
165 */
166 private function escapeLineFeed($unescapedString)
167 {
168 return str_replace("\n", self::ESCAPED_LINE_FEED_CHARACTER, $unescapedString);
169 }
170
171 /**
172 * Unescapes the line feed characters (\n)
173 *
174 * @param string $escapedString
175 * @return string
176 */
177 private function unescapeLineFeed($escapedString)
178 {
179 return str_replace(self::ESCAPED_LINE_FEED_CHARACTER, "\n", $escapedString);
180 }
181
182 /**
183 * Destroys the cache, freeing memory and removing any created artifacts
184 *
185 * @return void
186 */
187 public function clearCache()
188 {
189 if ($this->tempFolder) {
190 $this->fileSystemHelper->deleteFolderRecursively($this->tempFolder);
191 }
192 }
193 }
194