~ベタなPHP開発手法~ 2013/01/22 “よや” <[email protected]> 退職届PDFメーカーの作り方 自己紹介 昨年まで PHP + C言語、たまに JavaScript でお仕事してました。 趣味で公開してるライブラリ (Flashバイナリ操作) http://sourceforge.jp/projects/swfed http://openpear.org/package/IO_SWF ImageMagick のストーカーやってます。 http://d.hatena.ne.jp/yoya/searchdiary?word=Ima geMagick 発表内容 退職届PDFメーカーについて 普通のPHPプログラミング 普通じゃない(?)PHPプログラミング PDF 出力について iframe を使った PDF 表示 壁紙機能 (ストレージ、擬似α透過) QR コード対応 退職届PDFメーカーとは 参考) http://gigazine.net/news/20140105resignation-letter-generator/ http://app.awm.jp/resign/ 退職届PDFメーカー 利用者様の喜びの声!? 普通のPHPプログラミング SSI (server side include) 風 CGI (common gateway interface) 風 テンプレートエンジン(Smarty) フレームワーク? 普通の PHP プログラミング(1/4) SSI(server side include) 的な使い方 <html> <head><title> 1 </title> </head> <body> <?php echo date("Y/m/d H:i:s"); ?> </body> </html> http://awm.jp/~yoya/study/php/sagami/1/1.php 普通の PHP プログラミング(2/4) CGI (common gateway interface) 的な使い方 <?php echo "<html>\n"; echo "<head><title> 2 </title> </head>\n"; echo "<body>\n"; echo date("Y/m/d H:i:s"); echo "</body> </html>\n"; ?> http://awm.jp/~yoya/study/php/sagami/1/2.php 普通の PHP プログラミング(3/4) テンプレートエンジン(Smarty) で http://awm.jp/~yoya/study/php/sagami/1/3.tpl <html> <head><title> 3 </title> </head> <body> {$now} </body> </html> <?php require_once('Smarty.class.php'); $smarty = new Smarty(); $smarty->assign('now', date("Y/m/d H:i:s")); $smarty->display('3.tpl'); http://awm.jp/~yoya/study/php/sagami/1/3.php 普通の PHP プログラミング(4/4) PHPフレームワーク CakePHP ? ZendFramework ? Symphony ? CodeIgniter ? ↑省略!!! こういったページでも見て下さい > http://antenasites.com/2013/07/php-framework/ いずれにしても HTML 出力の話ばかり \今回もはそういう話はしません/ そもそも、僕は普通の発表した事ないです。 普通じゃないPHPプログラミング \HTML 以外を出力してみよう/ PHP は HTML 以外にも色々出力出来ます。 PHP で HTML じゃないモノ出力 JPEG/PNG画像出力 PDF 出力 Excel 出力 (要望があれば次回に解説) Spreadsheet/Excel/Writer はそのままだと PHP5.4 で動かないんですよね… PNG画像出力 (1/2) <?php header ('Content-type: image/png'); $im = imagecreate(240, 240); $red = imagecolorallocate($im, 255, 0, 0); $green = imagecolorallocate($im, 0, 255, 0); $blue = imagecolorallocate($im, 0, 0, 255); imageline($im, 0, 0, 200, 200, $green); imageline($im, 0, 100, 200, 100, $blue); imagepng($im); http://awm.jp/~yoya/study/php/sagami/1/line.php PNG画像出力 (2/2) <?php header ('Content-type: image/png'); $im = imagecreate(240, 240); $palette = array(); for ($i = 0 ; $i < 256 ; $i++) { $palette []= imagecolorallocate( $im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255) ); } for ($y = 0 ; $y < 240 ; $y++) { for ($x = 0 ; $x < 240 ; $x++) { imagesetpixel($im, $x, $y, $palette[mt_rand(0, 255)]); } } imagepng($im); http://awm.jp/~yoya/study/php/sagami/1/png.php JPEG画像出力 <?php header ('Content-type: image/jpeg'); $im = imagecreate(240, 240); $palette = array(); for ($i = 0 ; $i < 256 ; $i++) { $palette []= imagecolorallocate( $im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255) ); } for ($y = 0 ; $y < 240 ; $y++) { for ($x = 0 ; $x < 240 ; $x++) { imagesetpixel($im, $x, $y, $palette[mt_rand(0, 255)]); } } imagejpeg($im); http://awm.jp/~yoya/study/php/sagami/1/jpeg.php PDF 出力 FPDF と PHPlib が有名 とりあえず FPDF を試す インストール (Debian6) $ apt-cache search fpdf php-fpdf - PHP class to generate PDF files $ sudo apt-get install php-fpdf 日本語対応 http://www.fpdf.org/phorum/read.php?f=1&i=7977&t=79 77 japanese.zip と mbfpdf10b.zip があって後者の方が評 判が良いが、導入が楽なので前者を使ってみた (実際に何が困るのか知りたかったのもある) でも今の所、困る事がないので困ってる。 PDF 出力 (日本語対応) japanese.php は SJIS(cP932) 前提 今時の PHP は日本語を UTF-8 変換する function Text($x,$y,$txt) { $txt = mb_convert_encoding($txt, "CP932", "UTF-8"); // ☆ parent::Text($x,$y,$txt); } require('japanese.php'); header('Content-Type: application/pdf;'); $pdf=new PDF_Japanese(); $pdf->AddSJISFont(); $pdf->AddPage(); $pdf->SetFont('SJIS','',18); $pdf->Text(100,60,'こんにちわ!'); $pdf->Output(); http://awm.jp/~yoya/study/php/sagami/1/fpdfj.php PDF 出力 (縦書き対応) rotation.php で回転出来るけど日本語未対応 継承で合体させてみた 書き換え require('japanese.php'); // class PDF_Rotate extends PDF // オリジナル class PDF_Rotate extends PDF_Japanese // ☆ { require('japanese.php'); header('Content-Type: application/pdf;'); $pdf=new PDF_Japanese(); $pdf->AddSJISFont(); $pdf->AddPage(); $pdf->SetFont('SJIS','',18); $pdf->Rotate(45 ,100, 60); $pdf->Text(100,60,'こんにちわ!'); $pdf->Output(); http://awm.jp/~yoya/study/php/sagami/1/fpdfr.php 日本語対応 (縦書きレイアウト) 単純に1文字ずつ縦にしても駄目 90度倒さないと駄目なもの > ー (長音) 横がズレルもの > 」 (かぎ括弧) 縦書き用フォントならカーニングに情報 が入ってそうだけど、悲しいけどデバイ スフォントなのよね。。 デバイスフォントでPDF の容量を減らして、 さくさく操作感を重視している。 日本語対応 (縦書きレイアウト) 失敗例を元に、対処前と対処後 バグってました 後で治します 日本語対応 (縦書き無理やり対 応) switch ($c) { case 'ー': case '-': case '―': case '‐': case '~': $this->Rotate(90, $x+$fontSize*1.1, $y-$fontSize*1.1); $this->Text($x, $y, $c); $this->Rotate(0); break; case '、': case '。': case ',': case '.': $this->Text($x + $fontSize*1.5, $y - $fontSize*2, $c); break; case '」': case '”': $this->Text($x + $fontSize*1.5, $y, $c); break; default: $this->Text($x, $y, $c); break; 日本語対応 (漢数字) パターン 1 => 一 10 => 十 20 => 二十 21 => 二十一 日本語対応 (漢数字 \力づく/) function date2japanize($date) { // range: 0 - 99 $from = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); $to = array('〇', '一', '二', '三', '四', '五', '六', '七', '八', '九'); $dates = split('-', $date); $dates[0] -= 1988; foreach (range(0, 2) as $idx) { $d = $dates[$idx]; if ($d < 10) { $d = mb_substr($d, 1); } elseif ($d == 10) { $d = '十'; } elseif ($d < 20) { $d = '十'.mb_substr($d, 1); } elseif (($d % 10) === 0) { $d = mb_substr($d, 0, 1).'十'; } else { $d = mb_substr($d, 0, 1).'十'.mb_substr($d, 1); } $dates[$idx] = str_replace($from, $to, $d); } return '平成'.$dates[0].'年'.$dates[1].'月'.$dates[2].'日'; } iFrame を使った即時反映 http://app.awm.jp/resign/resign.php (トップ) GET パラメータを読んで入力 フォームを埋め る それと同時に iframe で pdf.php を開く resign.php 入力 フォ ーム http://app.awm.jp/resign/pdf.php GET パラメータを応じた PDF を出力 \それだけ/ pdf.php (iframe) 壁紙 普通のファイル送信フォーム <form enctype="multipart/form-data" action="?" method="POST"> <input type="hidden" name="MAX_FILE_SIZE" value="100000000" /> 壁紙用の画像ファイルをアップロード: <input name="image_file" type="file" class="btn btn-success" /> <input type="submit" value="画像ファイル送信" class="btn btn-primary" /> ファイルに一意な ID を付けて保存する 擬似αブレンディング処理をする 壁紙 (ファイルに一意なIDを) sha1 を使ってデータを数値に変換する 40文字は長いので12文字に減らす (衝突御免) function image_data2id($data, $ext) { // 16 chars digest $sha1 = sha1($data, true); $base64 = base64_encode(substr($sha1, 0, 12)); return strtr($base64, '+/', '-_').'.'.$ext; } フォルダを分割して保存 1フォルダに大量のファイル置くの怖いので [email protected]:/<秘密>/app/resign/img$ ls 0H 1j 3g 6u 9L AP Cg Eu JY PB Ur XV ZC cx iI jm nL qP sN ve 0N 2D 3w 6z 9O AW DA F_ Kg S5 VG Xq _A dK iP kL oE rl sO xa 0x 2j 6k 8M A0 CH DN GR MU SE VR YM ao g0 ip lF oQ ry sn xs 17 33 6s 8p AA Ca Ed Hh Ni Un Wb Yj bM i1 ja lX pa sM tz z9 壁紙 (αブレンディング) 元画像と白っぽく変換した画像を保存 [email protected]:/<秘密>/app/resign/img$ ls 17/ 17Pe9qdjx8OtTz4h.jpg _17Pe9qdjx8OtTz4h.jpg (PNG は大丈夫だけど) JPEG 画像に対して PDF に半透明の機能が見つからなかった ので、擬似アルファブレンディング 擬似αブレンディング あらかじめ画像を白くしておけば、その まま重ねても半透明で張ったように見え る。 function filterPixel(&$red, &$green, &$blue) { $red = (255 * 6 + $red) / 7; $green = (255 * 6 + $green) / 7; $blue = (255 * 6 + $blue) / 7; } QRコード対応 PHP QR Code encoder を使ってます http://phpqrcode.sourceforge.net/ 処理が重たいので大規模サイトではお勧 め出来ませんが、趣味では十分です。 require('phpqrcode.php'); $url = (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; $url = substr($url, 0, strlen($url) - strlen('&ext=.pdf')); $tmpfile = tempnam('tmp', 'qr'); QRcode::png($url, $tmpfile, 'L', 4, 0); $pdf->Image($tmpfile, 25, 220, 40, 40, 'png'); unlink($tmpfile); Github で公開中 https://github.com/yoya/resign 簡単な説明も http://pwiki.awm.jp/~yoya/?resign 質問コーナー Q) sha1 の第二引数 false にすれば base64_encode 要らない? 気付きませんでした!でも互換性怖いのでこのままで。 Q) jpeg も png で保存すれば半透明対応できない? Jpeg と png でリサイズのレンダリングが違う可能性があるので。 あと、容量増えるの嫌だったので。(後付け理由) Q) 反響はどうですか おかげ様で400を超えるブクマを頂いてます。 利用者の方から直接ありがとうメールを貰ったりもします。 Q) 生成された PDF を手元にこっそり保存してません? URL で完全に再現できるので access_log を保存すれば出来るけど、 誓ってみてません。 あと、万が一のサーバクラックが怖いので、日付でにファイルを 切り替えてて古いのは消してます。見てませんよ! おわり
© Copyright 2024 ExpyDoc