Manul Tech

前回、WordPress上でPDFにパスワードを設定するやつを作ったんだけど、ちょっとした問題があったのでアップデートすることに。


前回のものでも問題なく動作していたんだけど、あるPDFをアップロードした際にエラーが発生


Fatal error: Uncaught setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException: This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details)

フリーのパーサーではサポートしていないPDFですよ、と。
エラーにあるURLを見てみると、どうやらフリーのパーサーではPDF ver1.4までしかサポートしていないから、ver1.5以上のパースをしたい場合は対応したパーサー買ってね、ってことらしい。そういえばPDFにもバージョンなんてものがあったな。。

料金プランはいくつかあって、100 EUR / Licenseからとのこと。
うーん、一万円ちょいかー。別にそれぐらい払えばいいんだけど、別の方法がないか一応調べることにした。

PDF ver1.5以上に対応しているフリーパーサー

以下のカタコト翻訳されているポストを発見。

なんでも同じ問題に直面して自作されたのだとか。すげーなー。
ということで有難く使わせていただくことに。

READMEにある通りにpauln/tcpdi_parserFPDF_TPLもダウンロードして、path/to/TCPDFに突っ込んどく。
前回はFPDIを利用したけど、今回はいらないみたい。

require_once('lib/tcpdf/tcpdf.php');
require_once('lib/tcpdf/tcpdi.php');

$pdf = new TCPDI();
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$page_count = $pdf->setSourceFile('path/to/sourcefile');
$pdf->SetProtection(['print', 'copy', 'modify'], 'password');

for($i = 1; $i <= $page_count; $i++){
	$page = $pdf->importPage($i);
	$pdf->AddPage();
	$pdf->useTemplate($page, 0, 0);
}
$pdf->Output('savepath/to/PDF', 'F');

前回と違うのはライブラリの読み込み部分と、new TcpdfFpdi が new TCPDIになっただけ。

しかし、またしてもエラーが


Warning: Declaration of …….

調べてみるとPHPのバージョンが7以上の場合に出るエラーのようで、

継承によりメソッドをオーバーライドする場合は、継承元と同じメソッド定義にする。

・親クラスと引数の数が異なるとNG
・デフォルト値のあり・なしが異なるとNG(値は変わってもOK)
・Typehintも同じでないとNG

とのこと。

エラーが出ていたのはfpdf_tpl.php(Version 1.2.3)の275行目。

public function SetFont($family, $style = '', $size = 0) {...}
↓
//引数をTCPDFに揃える
public function SetFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) {...}

これでOKと思ったらまた別のエラーが。


ERROR: count(): Parameter must be an array or an object that implements Countable …

countメソッドのパラメーターがおかしいらしい。今度はtcpdi_parser.php(Version 1.1)で。
該当箇所の486行目を見てみるとこんなコードだった。

} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND count($v[1] >= 2))) {

..countメソッドの中に比較演算子。。こんな書き方ってあったんだろうか。一応調べてみたけど見当たらず。でも、$v[1] >= 2が返す値はboolean型のはずだからcountする意味はあるんだろうか。。
よくわかんないけど、$v[1]が2以上ならいいのだろうということで(適当)、以下のように変更。

} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND ($v[1] >= 2))) {

countとっただけ。
これでエラーも出ずに、無事にPDF ver1.5でもパースすることができました!
結果的にFPDIを使わなくなったことでファイル容量も少なくなってよかったかな。