Blame view

lib/XlsxParser.php 8.93 KB
8e128526   Mihail   add xlsx parser
1
2
3
4
5
6
7
8
  <?php
  /**
   * Created by PhpStorm.
   * User: Tsurkanov
   * Date: 21.10.2015
   * Time: 15:44
   */
  
d0261fd1   Mihail   fixed namespace i...
9
  namespace yii\multiparser;
f6e54131   Mihail   fixed keys and he...
10
  
735c416d   Mihail   add compatibility...
11
  use common\components\CustomVarDamp;
8e128526   Mihail   add xlsx parser
12
  
8e128526   Mihail   add xlsx parser
13
  
8e128526   Mihail   add xlsx parser
14
15
  /**
   * Class XlsxParser
d0261fd1   Mihail   fixed namespace i...
16
   * @package yii\multiparser
8e128526   Mihail   add xlsx parser
17
   */
f6e54131   Mihail   fixed keys and he...
18
19
  class XlsxParser extends TableParser
  {
8e128526   Mihail   add xlsx parser
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  
      /**
       * @var string - путь куда будут распаковываться файлы, если не указанно - во временный каталог сервера
       */
      public $path_for_extract_files = '';
  
  
      /**
       * @var int - если указано то считывание будет производиться с этого листа, иначе со всех листов
       * при чтении со всех листов - выходной массив будет иметь номера листов первыми элементами
       */
      public $active_sheet = 0;
  
      protected $strings_arr = [];
      protected $sheets_arr = [];
  
      protected $current_node;
      protected $current_sheet;
  
2395ca4f   Mihail   add round func fo...
39
40
41
42
      // глубина округления для флоата
      // @todo - перенести вродительский класс и применить в дочерних классах
      protected $float_precision = 6;
  
8e128526   Mihail   add xlsx parser
43
44
45
46
47
      public function setup()
      {
  
          parent::setup();
  
f6e54131   Mihail   fixed keys and he...
48
          if ($this->path_for_extract_files == '') {
8e128526   Mihail   add xlsx parser
49
50
51
52
53
54
55
              $this->path_for_extract_files = sys_get_temp_dir();
          }
      }
  
  
      public function read()
      {
f6e54131   Mihail   fixed keys and he...
56
          $this->extractFiles();
8e128526   Mihail   add xlsx parser
57
58
          $this->readSheets();
          $this->readStrings();
f6e54131   Mihail   fixed keys and he...
59
          foreach ($this->sheets_arr as $sheet) {
8e128526   Mihail   add xlsx parser
60
              //проходим по всем файлам из директории /xl/worksheets/
0c6fd004   Mihail   fixed issue with ...
61
              $this->current_sheet = $sheet;
8e128526   Mihail   add xlsx parser
62
              $sheet_path = $this->path_for_extract_files . '/xl/worksheets/' . $sheet . '.xml';
f6e54131   Mihail   fixed keys and he...
63
64
              if (file_exists($sheet_path) && is_readable($sheet_path)) {
                  $xml = simplexml_load_file($sheet_path, "SimpleXMLIterator");
8e128526   Mihail   add xlsx parser
65
66
                  $this->current_node = $xml->sheetData->row;
                  $this->current_node->rewind();
f6e54131   Mihail   fixed keys and he...
67
                  if ($this->current_node->valid()) {
0c6fd004   Mihail   fixed issue with ...
68
                      parent::read();
0c6fd004   Mihail   fixed issue with ...
69
                  }
8e128526   Mihail   add xlsx parser
70
              }
8e128526   Mihail   add xlsx parser
71
          }
0c6fd004   Mihail   fixed issue with ...
72
  
cd8b9f70   Mihail   add cleanUp metho...
73
          $this->cleanUp();
735c416d   Mihail   add compatibility...
74
  
f6e54131   Mihail   fixed keys and he...
75
          if ($this->active_sheet) {
735c416d   Mihail   add compatibility...
76
              // в настройках указан конкретный лист с которого будем производить чтение, поэтому и возвращаем подмассив
f6e54131   Mihail   fixed keys and he...
77
78
              return $this->result[$this->current_sheet];
          } else {
0c6fd004   Mihail   fixed issue with ...
79
80
81
              return $this->result;
          }
  
8e128526   Mihail   add xlsx parser
82
83
      }
  
f6e54131   Mihail   fixed keys and he...
84
      protected function extractFiles()
8e128526   Mihail   add xlsx parser
85
      {
0c6fd004   Mihail   fixed issue with ...
86
          $this->path_for_extract_files = $this->path_for_extract_files . session_id();
f6e54131   Mihail   fixed keys and he...
87
88
89
          if (!file_exists($this->path_for_extract_files)) {
              if (!mkdir($this->path_for_extract_files)) {
                  throw new \Exception('Ошибка создания временного каталога - ' . $this->path_for_extract_files);
0c6fd004   Mihail   fixed issue with ...
90
              }
735c416d   Mihail   add compatibility...
91
          }
0c6fd004   Mihail   fixed issue with ...
92
  
8e128526   Mihail   add xlsx parser
93
          $zip = new \ZipArchive;
f6e54131   Mihail   fixed keys and he...
94
95
          if ($zip->open($this->file_path) === TRUE) {
              $zip->extractTo($this->path_for_extract_files . '/');
8e128526   Mihail   add xlsx parser
96
97
              $zip->close();
          } else {
735c416d   Mihail   add compatibility...
98
  
f6e54131   Mihail   fixed keys and he...
99
              throw new \Exception('Ошибка чтения xlsx файла');
8e128526   Mihail   add xlsx parser
100
          }
221da14e   Mihail   change SplFileObj...
101
          unset($zip);
8e128526   Mihail   add xlsx parser
102
103
      }
  
f6e54131   Mihail   fixed keys and he...
104
      protected function readSheets()
8e128526   Mihail   add xlsx parser
105
      {
f6e54131   Mihail   fixed keys and he...
106
107
          if ($this->active_sheet) {
              $this->sheets_arr[] = 'sheet' . $this->active_sheet;
8e128526   Mihail   add xlsx parser
108
109
110
              return;
          }
  
f6e54131   Mihail   fixed keys and he...
111
112
          $xml = simplexml_load_file($this->path_for_extract_files . '/xl/workbook.xml');
          foreach ($xml->sheets->children() as $sheet) {
8e128526   Mihail   add xlsx parser
113
114
115
              $sheet_name = '';
              $sheet_id = 0;
              $attr = $sheet->attributes();
f6e54131   Mihail   fixed keys and he...
116
              foreach ($attr as $name => $value) {
8e128526   Mihail   add xlsx parser
117
118
119
120
121
122
123
                  if ($name == 'name')
                      $sheet_name = (string)$value;
  
                  if ($name == 'sheetId')
                      $sheet_id = $value;
  
              }
f6e54131   Mihail   fixed keys and he...
124
              if ($sheet_name && $sheet_id) {
8e128526   Mihail   add xlsx parser
125
126
127
128
129
130
                  $this->sheets_arr[$sheet_name] = 'Sheet' . $sheet_id;
              }
  //
          }
      }
  
f6e54131   Mihail   fixed keys and he...
131
      protected function readStrings()
8e128526   Mihail   add xlsx parser
132
      {
f6e54131   Mihail   fixed keys and he...
133
134
          $xml = simplexml_load_file($this->path_for_extract_files . '/xl/sharedStrings.xml');
          foreach ($xml->children() as $item) {
8e128526   Mihail   add xlsx parser
135
136
137
138
139
              $this->strings_arr[] = (string)$item->t;
          }
      }
  
  
f6e54131   Mihail   fixed keys and he...
140
      protected function readRow()
8e128526   Mihail   add xlsx parser
141
      {
0c6fd004   Mihail   fixed issue with ...
142
          $this->row = [];
8e128526   Mihail   add xlsx parser
143
          $node = $this->current_node->getChildren();
0c6fd004   Mihail   fixed issue with ...
144
145
146
          if ($node === NULL) {
              return;
          }
f6e54131   Mihail   fixed keys and he...
147
148
  
          for ($node->rewind(), $i = 0; $node->valid(); $node->next(), $i++) {
0c6fd004   Mihail   fixed issue with ...
149
              $child = $node->current();
8e128526   Mihail   add xlsx parser
150
151
              $attr = $child->attributes();
  
f6e54131   Mihail   fixed keys and he...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
              // define the index of result array
              // $attr['r'] - contain the address of cells - A1, B1 ...
              if (isset($attr['r'])) {
                  // override index
                  $i = $this->convertCellToIndex( $attr['r'] );
  
                  if ( $this->keys !== Null ){
                      if( isset( $this->keys[$i] ) ){
                          //$i = $this->keys[$i];
                      } else {
                          // we have a keys, but this one we didn't find, so skip it
                          continue;
                      }
                  }
              }
              // define the value of result array
              if (isset($child->v)) {
8e128526   Mihail   add xlsx parser
169
                  $value = (string)$child->v;
f6e54131   Mihail   fixed keys and he...
170
  
2395ca4f   Mihail   add round func fo...
171
172
                  if ( isset($attr['t']) ){
                      // it's not a value it's a string, so fetch it from string array
f6e54131   Mihail   fixed keys and he...
173
                      $value = $this->strings_arr[$value];
2395ca4f   Mihail   add round func fo...
174
175
176
177
                  } else {
                      $value = (string)round( $value, $this->float_precision );
                  }
  
f6e54131   Mihail   fixed keys and he...
178
179
  
              } else {
8e128526   Mihail   add xlsx parser
180
181
                  $value = '';
              }
f6e54131   Mihail   fixed keys and he...
182
183
184
  
              // set
              $this->row[$i] = $value;
8e128526   Mihail   add xlsx parser
185
186
  
          }
f6e54131   Mihail   fixed keys and he...
187
188
189
190
191
192
193
194
195
196
197
198
  //        // fill the row by empty values for keys that we are missed in previous step
          // only for 'has_header_row = true' mode
          if ( $this->has_header_row && $this->keys !== Null  ) {
              $extra_column = count( $this->keys ) - count( $this->row );
              if ( $extra_column ) {
                  foreach ( $this->keys as $key => $key ) {
  
                      if ( isset( $this->row[$key] ) ) {
                          continue;
                      }
                      $this->row[$key] = '';
                  }
0c6fd004   Mihail   fixed issue with ...
199
              }
f6e54131   Mihail   fixed keys and he...
200
  
0c6fd004   Mihail   fixed issue with ...
201
          }
f6e54131   Mihail   fixed keys and he...
202
          ksort( $this->row );
8e128526   Mihail   add xlsx parser
203
          $this->current_node->next();
8e128526   Mihail   add xlsx parser
204
205
      }
  
f6e54131   Mihail   fixed keys and he...
206
207
      protected function isEmptyRow()
      {
8e128526   Mihail   add xlsx parser
208
209
  
          $is_empty = false;
8e128526   Mihail   add xlsx parser
210
  
f6e54131   Mihail   fixed keys and he...
211
          if (!count($this->row) || !$this->current_node->valid()) {
8e128526   Mihail   add xlsx parser
212
213
214
215
              return true;
          }
  
          $j = 0;
f6e54131   Mihail   fixed keys and he...
216
          for ($i = 1; $i <= count($this->row); $i++) {
8e128526   Mihail   add xlsx parser
217
  
f6e54131   Mihail   fixed keys and he...
218
              if (isset($this->row[$i - 1]) && $this->isEmptyColumn($this->row[$i - 1])) {
8e128526   Mihail   add xlsx parser
219
220
221
                  $j++;
              }
  
f6e54131   Mihail   fixed keys and he...
222
              if ($j >= $this->min_column_quantity) {
8e128526   Mihail   add xlsx parser
223
224
225
226
227
228
229
230
                  $is_empty = true;
                  break;
              }
          }
  
          return $is_empty;
      }
  
f6e54131   Mihail   fixed keys and he...
231
232
      protected function isEmptyColumn($val)
      {
8e128526   Mihail   add xlsx parser
233
234
          return $val == '';
      }
0c6fd004   Mihail   fixed issue with ...
235
  
f6e54131   Mihail   fixed keys and he...
236
237
238
      protected function setResult()
      {
          $this->result[$this->current_sheet][] = $this->row;
0c6fd004   Mihail   fixed issue with ...
239
240
      }
  
f6e54131   Mihail   fixed keys and he...
241
      protected function deleteExtractFiles()
0c6fd004   Mihail   fixed issue with ...
242
      {
f6e54131   Mihail   fixed keys and he...
243
          $this->removeDir($this->path_for_extract_files);
0c6fd004   Mihail   fixed issue with ...
244
245
246
  
      }
  
f6e54131   Mihail   fixed keys and he...
247
248
      protected function removeDir($dir)
      {
0c6fd004   Mihail   fixed issue with ...
249
250
251
252
          if (is_dir($dir)) {
              $objects = scandir($dir);
              foreach ($objects as $object) {
                  if ($object != "." && $object != "..") {
f6e54131   Mihail   fixed keys and he...
253
254
                      if (filetype($dir . "/" . $object) == "dir")
                          $this->removeDir($dir . "/" . $object);
0c6fd004   Mihail   fixed issue with ...
255
                      else
f6e54131   Mihail   fixed keys and he...
256
                          unlink($dir . "/" . $object);
0c6fd004   Mihail   fixed issue with ...
257
258
259
260
261
262
263
                  }
              }
              reset($objects);
              rmdir($dir);
          }
      }
  
cd8b9f70   Mihail   add cleanUp metho...
264
  
f6e54131   Mihail   fixed keys and he...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
      /**
       * @param $cell_address - string with address like A1, B1 ...
       * @return int - integer index
       * this method has a constraint - 'Z' - it's a last column to convert,
       * column with 'AA..' address and bigger - return index = 0
       */
      protected function convertCellToIndex($cell_address)
      {
          $index = 0;
  
          $address_letter = substr($cell_address, 0, 1);
          $address_arr = range('A', 'Z');
  
          if ( $search_value =  array_search( $address_letter, $address_arr ) )
              $index = $search_value;
  
          return $index;
  
      }
  // @todo - переписать родительский метод в универсальной манере а не переопределять его
      protected  function setKeysFromHeader(){
          if ( $this->has_header_row ) {
  
              if ($this->keys === NULL) {
                  $this->keys =  $this->row;
                  return true;
              }
          }
          return false;
      }
cd8b9f70   Mihail   add cleanUp metho...
295
      protected function cleanUp()
0c6fd004   Mihail   fixed issue with ...
296
      {
cd8b9f70   Mihail   add cleanUp metho...
297
298
299
300
301
          parent::cleanUp();
          unset($this->strings_arr);
          unset($this->sheets_arr);
          unset($this->current_node);
  
cd8b9f70   Mihail   add cleanUp metho...
302
  
0c6fd004   Mihail   fixed issue with ...
303
304
      }
  
f6e54131   Mihail   fixed keys and he...
305
306
307
308
309
      function __destruct()
      {
          $this->deleteExtractFiles();
      }
  
0c6fd004   Mihail   fixed issue with ...
310
  
8e128526   Mihail   add xlsx parser
311
  }