詳細な状況がわかってきました。
テンプレートとなるExcelファイルのシートにプリンタ設定情報が含まている場合、
そのシートをコピーすると、コピーされた新しいシートにも同じプリンタ設定情報がコピーされます。
phpspreadsheetで、コピーしたシートのプリンタ設定情報の扱いがバグっている感じです。
【確認方法】
1.生成後エラーが出るxlsxファイルの拡張子をzipに変更。
2.エクスプローラーでzipファイルをダブルクリック。
3.フォルダ移動。 xl\printerSettings
※ここのフォルダに同じ名前の printerSettings1.bin がコピーしたシート数分あります。
phpspreadsheet自体を修正する技術量はないので、暫定対応で回避する。
【暫定対応】
1.phpspreadsheetで生成されたxlsxファイルをunzipで解凍し、重複ファイルを1つにする。
2.解凍されたファイルをzipで再圧縮する。 ※拡張子は .xlsx で圧縮
php
1 require '../phpLibs/PhpSpreadsheet/vendor/autoload.php' ;
2
3 use PhpOffice \ PhpSpreadsheet \ Reader \ Xlsx as XlsxReader ;
4 use PhpOffice \ PhpSpreadsheet \ Writer \ Xlsx as XlsxWriter ;
5 use PhpOffice \ PhpSpreadsheet \ IOFactory ;
6
7
8 // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
9 copyTemplateSheet ( '../tmp/Excel2016_Rclick_NEW.xlsx' ,
10 '../tmp/Excel2016_Rclick_NEW_generate.xlsx' ) ;
11
12 // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存
13 copyTemplateSheet ( '../tmp/Excel2016_Rclick_NEW_Save.xlsx' ,
14 '../tmp/Excel2016_Rclick_NEW_Save_generate.xlsx' ) ;
15
16 // Excel2016の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存(プリンタ設定を変更)
17 copyTemplateSheet ( '../tmp/Excel2016_Rclick_NEW_Save2.xlsx' ,
18 '../tmp/Excel2016_Rclick_NEW_Save2_generate.xlsx' ) ;
19
20 // Excel2019の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート
21 copyTemplateSheet ( '../tmp/Excel2019_Rclick_NEW.xlsx' ,
22 '../tmp/Excel2019_Rclick_NEW_generate.xlsx' ) ;
23
24 // Excel2019の環境で、右クリック⇒新規作成⇒Microsoft Excel ワークシート ※新規作成後、ファイルを開いて内容を更新して保存
25 copyTemplateSheet ( '../tmp/Excel2019_Rclick_NEW_Save.xlsx' ,
26 '../tmp/Excel2019_Rclick_NEW_Save_generate.xlsx' ) ;
27
28 exit ;
29
30 function copyTemplateSheet ( $load_filename , $save_filename ) {
31 $save_folder = realpath ( pathinfo ( $save_filename , PATHINFO_DIRNAME ) ) ;
32 $save_basename = pathinfo ( $save_filename , PATHINFO_BASENAME ) ;
33
34 try {
35 $reader = new XlsxReader ( ) ;
36 $spreadsheet = $reader -> load ( $load_filename ) ;
37 $spreadsheet -> setActiveSheetIndex ( 0 ) ;
38
39 $mastersheet = $spreadsheet -> getSheetByName ( 'Sheet1' ) ;
40
41 $worksheet = clone $mastersheet ;
42 $worksheet -> setTitle ( 'シート1' ) ;
43 $spreadsheet -> addSheet ( $worksheet ) ;
44
45 $worksheet -> setCellValue ( 'A1' , 'かきこみ' ) ;
46 $writer = new XlsxWriter ( $spreadsheet ) ;
47 $writer -> save ( $save_filename ) ;
48
49 // 解凍先のtmpフォルダ作成
50 if ( file_exists ( $save_filename . '.tmp' ) ) {
51 removeDirectory ( $save_filename . '.tmp' ) ;
52 }
53 mkdir ( $save_filename . '.tmp' , 0777 , true ) ;
54
55 //tmpフォルダにxlsxファイルを解凍 ※xlsxファイルはzip圧縮されている?
56 //この段階で、重複しているファイルが1つにまとめられる
57 shell_exec ( 'unzip -o ' . $save_filename . ' -d ' . $save_filename . '.tmp' ) ;
58
59 // 生成されたxlsxファイルを削除
60 unlink ( $save_filename ) ;
61
62 // tmpフォルダの内容で再圧縮し、xlsxファイルを作成する
63 $cwd = getcwd ( ) ;
64 chdir ( $save_filename . '.tmp' ) ;
65 shell_exec ( 'zip -r ' . $save_folder . '/' . $save_basename . ' *' ) ;
66 chdir ( $cwd ) ;
67
68 // tmpフォルダを削除
69 removeDirectory ( $save_filename . '.tmp' ) ;
70
71 } catch ( Exception $e ) {
72 die ( 'Error: ' . $e -> getMessage ( ) ) ;
73 }
74 }
75
76 function removeDirectory ( $directory ) {
77 $result = true ;
78 foreach ( new \ RecursiveIteratorIterator (
79 new \ RecursiveDirectoryIterator ( $directory , \ RecursiveDirectoryIterator :: SKIP_DOTS ) ,
80 \ RecursiveIteratorIterator :: CHILD_FIRST
81 ) as $file ) {
82 if ( $file -> isDir ( ) ) {
83 $result &= @ rmdir ( $file -> getPathname ( ) ) ;
84 } else {
85 $result &= @ unlink ( $file -> getPathname ( ) ) ;
86 }
87 }
88 return $result && @ rmdir ( $directory ) ;
89 }
【根本的な原因】
phpspreadsheetの内部で使用している、zipstream-php
というライブラリにバグがある。
https://github.com/maennchen/ZipStream-PHP/issues/154
xlsxファイルを解凍後に再圧縮するのではなく、phpspreadsheetを暫定修正する方法も考えてみた。
【phpspreadsheetを暫定的に修正】
既にZipファイルに追加されているファイルは複数回追加されないようにチェック。
vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php
php
1
2 public function save ( $pFilename )
3 :
4 :
5
6 《 280 行目付近》
7
8 // Add worksheet relationships (drawings, ...)
9 $added_files = array ( ) ; // ※追加
10 for ( $i = 0 ; $i < $this -> spreadSheet -> getSheetCount ( ) ; ++ $i ) {
11 // Add relationships
12 $zip -> addFile ( 'xl/worksheets/_rels/sheet' . ( $i + 1 ) . '.xml.rels' , $this -> getWriterPart ( 'Rels' ) -> writeWorksheetRelationships ( $this -> spreadSheet -> getSheet ( $i ) , ( $i + 1 ) , $this -> includeCharts ) ) ;
13
14 // Add unparsedLoadedData
15 $sheetCodeName = $this -> spreadSheet -> getSheet ( $i ) -> getCodeName ( ) ;
16 $unparsedLoadedData = $this -> spreadSheet -> getUnparsedLoadedData ( ) ;
17 if ( isset ( $unparsedLoadedData [ 'sheets' ] [ $sheetCodeName ] [ 'ctrlProps' ] ) ) {
18 foreach ( $unparsedLoadedData [ 'sheets' ] [ $sheetCodeName ] [ 'ctrlProps' ] as $ctrlProp ) {
19 $zip -> addFile ( $ctrlProp [ 'filePath' ] , $ctrlProp [ 'content' ] ) ;
20 }
21 }
22 if ( isset ( $unparsedLoadedData [ 'sheets' ] [ $sheetCodeName ] [ 'printerSettings' ] ) ) {
23 foreach ( $unparsedLoadedData [ 'sheets' ] [ $sheetCodeName ] [ 'printerSettings' ] as $ctrlProp ) {
24 if ( ! isset ( $added_files [ $ctrlProp [ 'filePath' ] ] ) ) { // ※追加
25 $zip -> addFile ( $ctrlProp [ 'filePath' ] , $ctrlProp [ 'content' ] ) ;
26 $added_files [ $ctrlProp [ 'filePath' ] ] = $ctrlProp [ 'filePath' ] ; // ※追加
27 } // ※追加
28 }
29 }
30
31
32