teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追加調査

2020/07/11 00:29

投稿

makotokw
makotokw

スコア24

answer CHANGED
@@ -109,4 +109,48 @@
109
109
  }
110
110
  return $result && @rmdir($directory);
111
111
  }
112
+ ```
113
+
114
+ **【根本的な原因】**
115
+ phpspreadsheetの内部で使用している、`zipstream-php`というライブラリにバグがある。
116
+ https://github.com/maennchen/ZipStream-PHP/issues/154
117
+  
118
+ xlsxファイルを解凍後に再圧縮するのではなく、phpspreadsheetを暫定修正する方法も考えてみた。
119
+  
120
+ **【phpspreadsheetを暫定的に修正】**
121
+ 既にZipファイルに追加されているファイルは複数回追加されないようにチェック。
122
+ `vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php`
123
+ ```php
124
+
125
+ public function save($pFilename)
126
+      :
127
+      :
128
+
129
+ 《280行目付近》
130
+
131
+ // Add worksheet relationships (drawings, ...)
132
+ $added_files = array(); // ※追加
133
+ for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
134
+ // Add relationships
135
+ $zip->addFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts));
136
+
137
+ // Add unparsedLoadedData
138
+ $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName();
139
+ $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData();
140
+ if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) {
141
+ foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) {
142
+ $zip->addFile($ctrlProp['filePath'], $ctrlProp['content']);
143
+ }
144
+ }
145
+ if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) {
146
+ foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) {
147
+ if(!isset($added_files[$ctrlProp['filePath']])) { // ※追加
148
+ $zip->addFile($ctrlProp['filePath'], $ctrlProp['content']);
149
+ $added_files[$ctrlProp['filePath']] = $ctrlProp['filePath']; // ※追加
150
+ } // ※追加
151
+ }
152
+ }
153
+
154
+
155
+
112
156
  ```

1

追加調査結果繁栄

2020/07/11 00:29

投稿

makotokw
makotokw

スコア24

answer CHANGED
@@ -1,10 +1,25 @@
1
- 根本的原因はわからないのですが、なんとなく状況がわかってきました。
1
+ 詳細な状況がわかってきました。
2
+ テンプレートとなるExcelファイルのシートにプリンタ設定情報が含まている場合、
3
+ そのシートをコピーすると、コピーされた新しいシートにも同じプリンタ設定情報がコピーされます。
2
4
 
3
- Excel2019保存したExcelファイルをテンプレートとし使用するとダメ見たいです。
5
+ phpspreadsheet、コピーしたートのプリンタ設定情報の扱いがバグっている感じです。
6
+ ![イメージ説明](20e75c429737802da14f952e9f30257c.jpeg)
4
7
 
8
+ 【確認方法】
9
+ 1.生成後エラーが出るxlsxファイルの拡張子をzipに変更。
10
+ 2.エクスプローラーでzipファイルをダブルクリック。
11
+ 3.フォルダ移動。 xl\printerSettings\
12
+ ※ここのフォルダに同じ名前の printerSettings1.bin がコピーしたシート数分あります。
13
+  
14
+  
15
+ **phpspreadsheet自体を修正する技術量はないので、暫定対応で回避する。**
5
16
 
17
+ 【暫定対応】
18
+ 1.phpspreadsheetで生成されたxlsxファイルをunzipで解凍し、重複ファイルを1つにする。
19
+ 2.解凍されたファイルをzipで再圧縮する。 ※拡張子は .xlsx で圧縮
20
+
21
+
6
22
  ```php
7
- <?php
8
23
  require '../phpLibs/PhpSpreadsheet/vendor/autoload.php';
9
24
 
10
25
  use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
@@ -13,30 +28,31 @@
13
28
 
14
29
 
15
30
  // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
16
- // 【生成ファイル】 OK !!
17
31
  copyTemplateSheet('../tmp/Excel2016_Rclick_NEW.xlsx',
18
32
  '../tmp/Excel2016_Rclick_NEW_generate.xlsx');
19
33
 
20
- // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
34
+ // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存
21
- // ※新規作成後、ファイルを開いて内容を更新して保存
22
- // 【生成ファイル】 OK !!
23
35
  copyTemplateSheet('../tmp/Excel2016_Rclick_NEW_Save.xlsx',
24
36
  '../tmp/Excel2016_Rclick_NEW_Save_generate.xlsx');
25
37
 
38
+ // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存(プリンタ設定を変更)
39
+ copyTemplateSheet('../tmp/Excel2016_Rclick_NEW_Save2.xlsx',
40
+ '../tmp/Excel2016_Rclick_NEW_Save2_generate.xlsx');
41
+
26
42
  // Excel2019の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
27
- // 【生成ファイル】 OK !!
28
43
  copyTemplateSheet('../tmp/Excel2019_Rclick_NEW.xlsx',
29
44
  '../tmp/Excel2019_Rclick_NEW_generate.xlsx');
30
45
 
31
- // Excel2019の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
46
+ // Excel2019の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存
32
- // ※新規作成後、ファイルを開いて内容を更新して保存
33
- // 【生成ファイル】 NG !!!!
34
47
  copyTemplateSheet('../tmp/Excel2019_Rclick_NEW_Save.xlsx',
35
48
  '../tmp/Excel2019_Rclick_NEW_Save_generate.xlsx');
36
49
 
37
50
  exit;
38
51
 
39
52
  function copyTemplateSheet($load_filename, $save_filename) {
53
+ $save_folder = realpath(pathinfo($save_filename, PATHINFO_DIRNAME));
54
+ $save_basename = pathinfo($save_filename, PATHINFO_BASENAME );
55
+
40
56
  try {
41
57
  $reader = new XlsxReader();
42
58
  $spreadsheet = $reader->load($load_filename);
@@ -51,10 +67,46 @@
51
67
  $worksheet->setCellValue('A1','かきこみ');
52
68
  $writer = new XlsxWriter($spreadsheet);
53
69
  $writer->save($save_filename);
70
+
71
+ // 解凍先のtmpフォルダ作成
72
+ if(file_exists($save_filename.'.tmp')) {
73
+ removeDirectory($save_filename.'.tmp');
74
+ }
75
+ mkdir($save_filename.'.tmp', 0777, true);
76
+
77
+ //tmpフォルダにxlsxファイルを解凍 ※xlsxファイルはzip圧縮されている?
78
+ //この段階で、重複しているファイルが1つにまとめられる
79
+ shell_exec('unzip -o '.$save_filename.' -d '.$save_filename.'.tmp');
80
+
81
+ // 生成されたxlsxファイルを削除
82
+ unlink($save_filename);
83
+
84
+ // tmpフォルダの内容で再圧縮し、xlsxファイルを作成する
85
+ $cwd = getcwd();
86
+ chdir($save_filename.'.tmp');
87
+ shell_exec('zip -r '.$save_folder.'/'.$save_basename.' *');
88
+ chdir($cwd);
89
+
90
+ // tmpフォルダを削除
91
+ removeDirectory($save_filename.'.tmp');
92
+
54
93
  } catch(Exception $e) {
55
94
  die('Error: '.$e->getMessage());
56
95
  }
57
96
  }
58
- ```
59
97
 
98
+ function removeDirectory($directory) {
99
+ $result = true;
100
+ foreach(new \RecursiveIteratorIterator(
101
+ new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS),
102
+ \RecursiveIteratorIterator::CHILD_FIRST
103
+ ) as $file) {
60
- ご回答くださった方々、ありがとうございました♪
104
+ if ($file->isDir()) {
105
+ $result &= @rmdir($file->getPathname());
106
+ } else {
107
+ $result &= @unlink($file->getPathname());
108
+ }
109
+ }
110
+ return $result && @rmdir($directory);
111
+ }
112
+ ```