PluginProbe ʕ •ᴥ•ʔ
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets / 3.0
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets v3.0
4.1.1 3.9.5 3.9.6 4.0.0 4.0.1 4.1.0 trunk 2.12 2.13 2.14 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9 3.7.0 3.7.1 3.7.2 3.7.3 3.7.3-beta-1.0 3.7.4 3.7.4-beta-1.0 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4
wp-all-import / classes / chunk.php
wp-all-import / classes Last commit date
chunk.php 13 years ago config.php 13 years ago download.php 13 years ago helper.php 13 years ago input.php 13 years ago
chunk.php
359 lines
1 <?php
2 /**
3 * Chunk
4 *
5 * Reads a large file in as chunks for easier parsing.
6 *
7 * The chunks returned are whole <$this->options['element']/>s found within file.
8 *
9 * Each call to read() returns the whole element including start and end tags.
10 *
11 * Tested with a 1.8MB file, extracted 500 elements in 0.11s
12 * (with no work done, just extracting the elements)
13 *
14 * Usage:
15 * <code>
16 * // initialize the object
17 * $file = new Chunk('chunk-test.xml', array('element' => 'Chunk'));
18 *
19 * // loop through the file until all lines are read
20 * while ($xml = $file->read()) {
21 * // do whatever you want with the string
22 * $o = simplexml_load_string($xml);
23 * }
24 * </code>
25 *
26 * @package default
27 * @author Dom Hastings
28 */
29 class PMXI_Chunk {
30 /**
31 * options
32 *
33 * @var array Contains all major options
34 * @access public
35 */
36 public $options = array(
37 'path' => './', // string The path to check for $file in
38 'element' => '', // string The XML element to return
39 'chunkSize' => 4096, // integer The amount of bytes to retrieve in each chunk
40 'type' => 'upload'
41 );
42
43 /**
44 * file
45 *
46 * @var string The filename being read
47 * @access public
48 */
49 public $file = '';
50 /**
51 * pointer
52 *
53 * @var integer The current position the file is being read from
54 * @access public
55 */
56 public $pointer = 0;
57
58 public $cloud = array();
59
60 /**
61 * handle
62 *
63 * @var resource The fopen() resource
64 * @access private
65 */
66 private $handle = null;
67 /**
68 * reading
69 *
70 * @var boolean Whether the script is currently reading the file
71 * @access private
72 */
73 private $reading = false;
74 /**
75 * readBuffer
76 *
77 * @var string Used to make sure start tags aren't missed
78 * @access private
79 */
80 private $readBuffer = '';
81
82 /**
83 * __construct
84 *
85 * Builds the Chunk object
86 *
87 * @param string $file The filename to work with
88 * @param array $options The options with which to parse the file
89 * @author Dom Hastings
90 * @access public
91 */
92 public function __construct($file, $options = array(), $pointer = 0) {
93 // merge the options together
94 $this->options = array_merge($this->options, (is_array($options) ? $options : array()));
95
96 // check that the path ends with a /
97 if (substr($this->options['path'], -1) != '/') {
98 $this->options['path'] .= '/';
99 }
100
101 // normalize the filename
102 $file_base = basename($file);
103
104 // make sure chunkSize is an int
105 $this->options['chunkSize'] = intval($this->options['chunkSize']);
106
107 // check it's valid
108 if ($this->options['chunkSize'] < 64) {
109 $this->options['chunkSize'] = 1024;
110 }
111
112 $this->pointer = $pointer;
113
114 // set the filename
115 $this->file = ($this->options['path'] != './') ? realpath($this->options['path'].$file_base) : $file;
116
117 // check the file exists
118 if (!file_exists($this->file)){
119 throw new Exception('File doesn\'t exist');
120 }
121
122 // open the file
123 $this->handle = fopen($this->file, 'rb');
124
125 // check the file opened successfully
126 if (!$this->handle) {
127 throw new Exception('Error opening file for reading');
128 }
129
130 }
131
132 /**
133 * __destruct
134 *
135 * Cleans up
136 *
137 * @return void
138 * @author Dom Hastings
139 * @access public
140 */
141 public function __destruct() {
142 // close the file resource
143 fclose($this->handle);
144 }
145
146 /**
147 * read
148 *
149 * Reads the first available occurence of the XML element $this->options['element']
150 *
151 * @return string The XML string from $this->file
152 * @author Dom Hastings
153 * @access public
154 */
155 public function read() {
156 // check we have an element specified
157 if (!empty($this->options['element'])) {
158 // trim it
159 $element = trim($this->options['element']);
160
161 } else {
162 $element = '';
163 }
164
165 // initialize the buffer
166 $buffer = false;
167
168 // if the element is empty, then start auto detect root element tag name
169 if (empty($element)) {
170 // let the script know we're reading
171 $this->reading = true;
172 $founded_tags = array();
173 // read in the whole doc, cos we don't know what's wanted
174 while ($this->reading) {
175 $c = fread($this->handle, $this->options['chunkSize']);
176 if ( preg_match_all("/<\\w+\\s*[^<]*\\s*\/?>/i", $c, $matches, PREG_PATTERN_ORDER) ){
177 foreach ($matches[0] as $tag) {
178 $tag = explode(" ",trim(str_replace(array('<','>','/'), '', $tag)));
179 array_push($founded_tags, $tag[0]);
180 }
181 }
182 $this->reading = (!feof($this->handle));
183 }
184
185 // we must be looking for a specific element
186 }
187
188 if (empty($element) and !empty($founded_tags)) {
189
190 $element_counts = array_count_values($founded_tags);
191
192 if (!empty($element_counts)){
193
194 $this->cloud = array_slice($element_counts, 0, 2);
195
196 foreach ($element_counts as $tag => $count) {
197 if ($count > 1 and empty($this->options['element'])) {
198 $this->options['element'] = $element = $tag;
199 }
200 elseif ($count > 1){
201 $this->cloud[$tag] = $count;
202 }
203 }
204 }
205
206 }
207
208 // return it all if element doesn't founded
209 if (empty($element))
210 return false;
211
212 // we must be looking for a specific element
213 //}
214
215 // initialize the buffer
216 $buffer = false;
217
218 // set up the strings to find
219 $open = '<'.$element;
220 $close = '</'.$element.'>';
221
222 // let the script know we're reading
223 $this->reading = true;
224
225 // reset the global buffer
226 $this->readBuffer = '';
227
228 // this is used to ensure all data is read, and to make sure we don't send the start data again by mistake
229 $store = false;
230
231 // seek to the position we need in the file
232 fseek($this->handle, $this->pointer);
233
234 // start reading
235 while ($this->reading && !feof($this->handle)) {
236
237 // store the chunk in a temporary variable
238 $tmp = fread($this->handle, $this->options['chunkSize']);
239
240 // update the global buffer
241 $this->readBuffer .= $tmp;
242
243 // check for the open string
244 $checkOpen = strpos($tmp, $open." ");
245 if (!$checkOpen) $checkOpen = strpos($tmp, $open.">");
246
247 // if it wasn't in the new buffer
248 if (!$checkOpen && !($store)) {
249 // check the full buffer (in case it was only half in this buffer)
250 $checkOpen = strpos($this->readBuffer, $open." ");
251 if (!$checkOpen) $checkOpen = strpos($this->readBuffer, $open.">");
252
253 // if it was in there
254 if ($checkOpen) {
255 // set it to the remainder
256 $checkOpen = $checkOpen % $this->options['chunkSize'];
257 }
258 }
259
260 // check for the close string
261 $checkClose = strpos($tmp, $close);
262 $withoutcloseelement = false;
263 if (!$checkClose){
264 $checkClose = (preg_match_all("/\/>\s*".$open."\s*/", $this->readBuffer, $matches)) ? strpos($this->readBuffer, $matches[0][0]) : false;
265 if ($checkClose)
266 $withoutcloseelement = true;
267 else{
268 /*$checkClose = (preg_match_all("/\s*\/>\s*<\/", $this->readBuffer, $matches)) ? strpos($this->readBuffer, $matches[0][0]) : false;
269 if ($checkClose)
270 $withoutcloseelement = true;*/
271 }
272 }
273
274 // if it wasn't in the new buffer
275 if (!$checkClose && ($store)) {
276 // check the full buffer (in case it was only half in this buffer)
277 $checkClose = strpos($this->readBuffer, $close);
278
279 $withoutcloseelement = false;
280 if (!$checkClose){
281 $checkClose = (preg_match_all("/\/>\s*".$open."\s*/", $this->readBuffer, $matches)) ? strpos($this->readBuffer, $matches[0][0]) : false;
282 if ($checkClose)
283 $withoutcloseelement = true;
284 else{
285 /*$checkClose = (preg_match_all("//>\\s*<\//", $this->readBuffer, $matches)) ? strpos($this->readBuffer, $matches[0][0]) : false;
286 if ($checkClose)
287 $withoutcloseelement = true;*/
288 }
289 }
290 // if it was in there
291 if ($checkClose) {
292 // set it to the remainder plus the length of the close string itself
293 if (!$withoutcloseelement){
294 $checkClose = ($checkClose + strlen($close)) % $this->options['chunkSize'];
295 }else{
296 $checkClose = ($checkClose + strlen("/>")) % $this->options['chunkSize'];
297 }
298 }
299
300 // if it was
301 } elseif ($checkClose) {
302 // add the length of the close string itself
303 if ( ! $withoutcloseelement)
304 $checkClose += strlen($close);
305 else
306 $checkClose += strlen("/>"); // "/>" symbols
307 }
308
309 // if we've found the opening string and we're not already reading another element
310 if ($checkOpen !== false && !($store)) {
311 // if we're found the end element too
312 if ($checkClose !== false) {
313 // append the string only between the start and end element
314 $buffer .= substr($tmp, $checkOpen, ($checkClose - $checkOpen));
315
316 // update the pointer
317 $this->pointer += $checkClose;
318
319 // let the script know we're done
320 $this->reading = false;
321
322 } else {
323 // append the data we know to be part of this element
324 $buffer .= substr($tmp, $checkOpen);
325
326 // update the pointer
327 $this->pointer += $this->options['chunkSize'];
328
329 // let the script know we're gonna be storing all the data until we find the close element
330 $store = true;
331 }
332
333 // if we've found the closing element
334 } elseif ($checkClose !== false) {
335 // update the buffer with the data upto and including the close tag
336 $buffer .= substr($tmp, 0, $checkClose);
337
338 // update the pointer
339 $this->pointer += $checkClose;
340
341 // let the script know we're done
342 $this->reading = false;
343
344 // if we've found the closing element, but half in the previous chunk
345 } elseif ($store) {
346 // update the buffer
347 $buffer .= $tmp;
348
349 // and the pointer
350 $this->pointer += $this->options['chunkSize'];
351 }
352
353 }
354
355 // return the element (or the whole file if we're not looking for elements)
356 return $buffer;
357 }
358 }
359