PHPExcelとExcel2007

2010.06.10 Author: ぴ

業務効率化を図ろうと、Excel2007で作った書類のデータをうまく取り出し、加工して使うことを模索しております。
弊社でWebシステム開発をするときのメイン言語であるPHPには、Excelファイルの読み込み・書き込みを行うことができるPHPExcelというものが存在します。
今回は、PHPExcelにまつわるお話です。

PHPExcelでは、Excel2007形式のファイルの読み書きができる優れものです。
大昔、Excel2007が出たときには、xlsxファイルをzip展開してファイルの構造をひもとき、Web側で書き込んだデータをExcel2007形式のファイルで出力するようなシステムを作った物です。
それが、近々リリースする

の原型だったりするのですが。

今回は、CentOS 5にRPMで導入したPHPを使った場合の想定で、遭遇する問題を書き留めておきます。
なお、最新のPHP5.3系を使えばこの情報は不要です。だって、普通に動くから…。
サーバ保守を考えたりすると、RPM版のパッケージを使う方がいろいろとよいと考えていますので(賛否両論でしょうが、私はそう考えます)。

まず、PHPExcelは、PHP5.2以上の環境で動作するとあります。
しかし、PECLでいくつかのパッケージを導入すれば、PHP5.1.6の環境(RPM版PHPはこのバージョン)でも動作します。

Office 2007からは、XML形式のファイルをzip圧縮したものを使っています。
PHPExcelでは、Excel2007形式のファイルを処理するためにzipアーカイバを必要とします。
それが、php_zipと呼ばれるパッケージで、PECLにあります。
インストールは単純に

# pecl install zip
とするだけです。
当然、gccやらphp-develやらが入っている前提です。

しかし、現在公開されているphp_zipは、バージョンが1.10.xのものです。
このバージョンでは、PHP5.2に依存する定義を使っている箇所があり、コンパイル中に落ちます。
そのため、古いバージョンをインストールして回避します。

# pecl install zip-1.8.10
このように、バージョンを指定したpear/peclのパッケージ導入が可能です。
一気に最新バージョンにあげることができない場合、一時的に中間バージョンまで上げてから、最新バージョンまであげるということもできます。試してみてください(PEARとか、PEARとか、PEARとか)。

後は、PHPExcelのファイル群を適当において使えるようにしてください。
さ、これでPHPExcelが使えるようになりました。

今回、読み込ませるファイルにはセル中に「○」という文字が一文字だけ入っているものが多々あります。
しかし、PHPExcelでファイルを読み込ませると、そのセルには文字が入っていないと言われます。
しょうがないので、PHPExcelのソースファイルをひもときながら、どこで文字が失われているか探してみました。

まず、Excel2007.phpを確認しましたが、文字列は失われていません。
次に、Cell.phpを確認したところ、215行目~

            case PHPExcel_Cell_DataType::TYPE_STRING:
            case PHPExcel_Cell_DataType::TYPE_NULL:
            case PHPExcel_Cell_DataType::TYPE_INLINE:
                $this->_value = PHPExcel_Cell_DataType::checkString($pValue);
                break;
を通過した時点で、文字が失われていることが分かりました。
ということで、Cell/DataType.phpを確認すると、88行目~
        $pValue = PHPExcel_Shared_String::Substring($pValue, 0, 32767);
なんていう記述が…。
文字列長を制限しているようですが、何も自前で作らなくとも…と思ったりもしますが、2バイト圏の我々のことを考えてくれているんだと前向きに捉え、次に進みます。
最後に、Shared/String.php::Substringを見ると、iconv_substrを優先的に使いsubstrを行っているようです。
iconv_substrは、PHP5.1系にはバグがあり、1文字の入力を入れると0文字になるという、嬉しい特典があります。
そのため、560行目~の
        if (self::getIsIconvEnabled()) {
            $string = iconv_substr($pValue, $pStart, $pLength, 'UTF-8');
            return $string;
        }
をコメントアウト。大好きなmbstringに処理を任せることにしました。

ようやく、まともに動作しました。
これで、とっておきの業務改善ツールが作れます。
ということで、近々弊社の開発が急に早くなっているかもしれません!

名古屋のWebシステム開発・ネットワーク構築会社 コネクティボへ