私のあるプロジェクトにおいて、Laravelからエクセルを生成するプログラムがあります。DBからの値を整形してエクセルに流し込み、生成されたエクセルをウェブからダウンロードできるプログラムです。記録として残すため、あるいはそれを他のプログラムにインポートするために、エクセルを生成する必要があるわけなのですが、ちょっとしたややこしい問題がありました。今回はその解決方法を共有です。
エクセルの作成
エクセルを作成するプログラムは、有名なphpspreadsheetのライブラリを使用して作成します。
まず、ライブラリ使用のために、以下を実行してプロジェクトに取り込みます。
$ composer require phpoffice/phpspreadsheet
次にエクセル作成のコマンドプログラムの作成です。
$ php artisan make:command ExcelCommand
作成されたコマンドのファイルを以下のように編集します。phpspreadsheetからの例から取ってきました。実行するとファイルは、storage/app/Hello world.xlsxとして作成されます。
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
class ExcelCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:excel';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate an Excel file';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');
$writer = new Xlsx($spreadsheet);
$writer->save(storage_path('app/Hello world.xlsx'));
}
}
セル値に長い番号があるときの表示
さて、上のプログラムを編集して、長い番号を表示してみます。
...
public function handle()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getDefaultColumnDimension()->setWidth(20); //列の幅を広げる
$sheet->setCellValue('A1', '12345678901');
$sheet->setCellValue('A2', '123456789012'); // 12桁の数
$sheet->setCellValue('A3', '123456789012345'); // 15桁の数
$writer = new Xlsx($spreadsheet);
$writer->save(storage_path('app/numbers.xlsx'));
}
...
生成されたファイルをエクセルでオープンすると、以下のように表示されます。

見ての通り、番号が12桁以上なら、指数として表示されます。
さらに、15桁以上となると、セル値そのものが変わって15桁からの数字が0に変わってしまいます。

この解決方法として一番簡単なのは、数字の前に文字、例えば半角スペースを入れることです。
...
$sheet->setCellValue('A1', '12345678901');
$sheet->setCellValue('A2', ' 123456789012'); // スペース+12桁の数
$sheet->setCellValue('A3', ' 123456789012345'); // スペース+15桁の数
...

数字すべて表示されるようになりましたね。しかし、数字の前に半角スペースがあるのが気に入らない、あるいは他のプログラムにインポートするときに、いちいちスペースをトリムする必要があり問題となるかもしれません。
最終の解決方法
数字を指数として表示せずに、また値に半角を入れずにオリジナルの数値をキープ方法というのは、数字とでなくテキストとして値を扱うことですが、以下のように違う関数、setCEllValueExplicity()の使用となります。
...
$sheet->setCellValueExplicit('A1', '123456789012345',
\PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING
);
...
結果は、以下のような表示となり、値もオリジナルと同じとなりました。

今回役だった情報は以下のphpspreadsheetのgithubから来ました:
https://github.com/PHPOffice/PHPExcel/issues/1148
https://github.com/PHPOffice/PhpSpreadsheet/issues/357
