<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>有限会社アテージ &#187; コラム</title>
	<atom:link href="https://www.atage.jp/archives/category/column/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.atage.jp</link>
	<description>使えるシステムから使いたいシステムへ、有限会社アテージ</description>
	<lastBuildDate>Wed, 10 Jan 2018 06:32:41 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>NightmareJSでファイルのダウンロード、アップロード</title>
		<link>https://www.atage.jp/archives/3276/</link>
		<comments>https://www.atage.jp/archives/3276/#comments</comments>
		<pubDate>Wed, 28 Sep 2016 22:44:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3276</guid>
		<description><![CDATA[NightmareJSを使ってファイルをダウンロード、アップロードする方法を紹介します。]]></description>
			<content:encoded><![CDATA[<p>WebシステムでCSVによるデータのインポートやエクスポートの機能をよく見かけます。<br />
求人サイトや不動産サイトなどを複数利用していて、あるサイトからデータをエクスポート、加工・編集して別のサイトへインポートしている方もいらっしゃるのではないでしょうか。</p>
<p>面倒な作業ですし、ついつい忘れてしまうこともあります。このような作業を自動化したいと思われた方も多いと思います。</p>
<p>今回は、NightmareJSというブラウザを使った自動処理を行えるツール(ホームページにはhigh-level browser automation libraryと書かれています)を使ってファイルのダウンロード、アップロードを自動化する方法を紹介します。</p>
<p>■ダウンロード</p>
<p>nightmare-download-managerというプラグインを利用します。</p>
<p></p><pre class="crayon-plain-tag">var Nightmare = require('nightmare');
require('nightmare-download-manager')(Nightmare);
var vo = require('vo');

vo(function* () {
  var nightmare = Nightmare({ show: true });
  nightmare.on('download', function(state, downloadItem){
    if(state == 'started'){
      nightmare.emit('download', './data.csv', downloadItem);
    }
  });

  var ret = yield nightmare
    .goto('http://localhost/admin/index.php')
    .insert('input[name="id"]', 'username')
    .insert('input[name="pass"]', 'password')
    .click('input[type="submit"]')
    .wait('input[value="ダウンロード"]')
    .downloadManager()
    .click('input[value="ダウンロード"]')
    .waitDownloadsComplete()
    .then(function () {
      console.log('done');
    });

  yield nightmare.end();

})(function (err, result) {
  if (err) return console.log(err);
});</pre><p> </p>
<p>■アップロード</p>
<p>nightmare-uploadというプラグインを利用します。</p>
<p></p><pre class="crayon-plain-tag">var Nightmare = require('nightmare');
require('nightmare-upload')(Nightmare);
var vo = require('vo');
const path = require('path');

vo(function* () {
  var nightmare = Nightmare({ show: true });

  yield nightmare
    .goto('http://localhost/admin/index.php')
    .insert('input[name="id"]', 'username')
    .insert('input[name="pass"]', 'password')
    .click('input[type="submit"]')
    .wait('input[value="アップロード"]')
    .upload('input[name="file"]', path.join(__dirname, 'data.csv'))
    .click('input[value="アップロード"]')
    .then(function () {
      console.log('done');
    });

  yield nightmare.end();

})(function (err, result) {
  if (err) return console.log(err);
});</pre><p> </p>
<p>NightmareJSに限らずスクレイピングツールはブラウザを使った操作をそのまま書き下すようにコードを書けばよいので何をやっているか一目瞭然だと思います。</p>
<p><strong style="color:blue;">ブラウザで行っている作業を自動化したいという方は是非一度弊社に<a href="https://www.atage.jp/contact/"><span style="text-decoration:underline;">ご相談</span></a>ください。スクレイピング、クローラーのご相談も承っております。</strong></p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3276/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Node.jsでメール送信</title>
		<link>https://www.atage.jp/archives/3233/</link>
		<comments>https://www.atage.jp/archives/3233/#comments</comments>
		<pubDate>Wed, 24 Aug 2016 11:41:26 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3233</guid>
		<description><![CDATA[Node.jsでメール送信を簡単に行えるNodemailerを使ってみました。]]></description>
			<content:encoded><![CDATA[<p>このところスクレイピングのご相談が多く、HTMLのみであればPHP+Goutte、<br />
JSでページを書き換えているものならNode.js+NightmareJS+Electronを利用しています。</p>
<p>先日もNightmareJSでスクレイピングツールを作ったのですが、<br />
結果をメールに添付して飛ばしてほしいというご要望がございました。</p>
<p>そのときに使ったメール送信モジュール Nodemailer を紹介します。</p>
<p>SMTPでの送信がデフォルトで組み込まれていて、<br />
sendmailコマンドでの送信はモジュールを組み込むことで可能になっています。（PHPとは逆）<br />
その他の送信モジュールは<a href="http://nodemailer.com/2-0-0-beta/setup-transporter/">こちら</a>。</p>
<p>以下は、画像を入れたHTMLメールにPDFを添付して送信したサンプルです。<br />
説明の必要はないと思いますが、cid（Content-ID）は見慣れない方もいるかもしれません。<br />
HTMLから添付した画像を参照する場合は、添付ファイルのファイル名ではなく、<br />
このIDを使う決まりになっています。<a href="https://tools.ietf.org/html/rfc2392">https://tools.ietf.org/html/rfc2392</a><br />
（これはNodemailerに限った話でありません）</p>
<p><strong>日本語はUTF-8を使用します。（これはNodemailerの決まり）</strong></p>
<p></p><pre class="crayon-plain-tag">var  nodemailer = require('nodemailer');

var transporter = nodemailer.createTransport({
  host : 'XXXX.XXXX.ne.jp',
  port : 25,
  auth : {
    user : 'XXXX@XXXX.XXXX.ne.jp',
    pass : 'XXXX'
  }
});

transporter.sendMail({
  from : 'info@atage.jp',
  to : 'XXXX@XXXX.com',
  subject : 'お問い合わせありがとうございます。',
  html : {
    path : './message.html'
  },
  attachments : [
    {
      filename : '会社案内.pdf',
      path : './profile.pdf'
    },
    {
      cid : 'logo',
      path : './logo.png'
    }
  ]
}, function (error, info) {
  console.log(info);
});</pre><p> </p>
<p class="fname">message.html</p>
<p></p><pre class="crayon-plain-tag">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" Content="text/html;charset=UTF-8"&gt;
&lt;/head&gt;
&lt;body&gt;
この度はお問い合わせいただきありがとうございます。&lt;br&gt;
&lt;br&gt;
弊社は、ウェブとデータベースの開発を承っておりまして、&lt;br&gt;
ユーザー目線で使いやすいシステムを心がけております。&lt;br&gt;
&lt;br&gt;
３営業日以内に担当者より連絡をさせていただきます。&lt;br&gt;
よろしくお願い申し上げます。&lt;br&gt;
&lt;br&gt;
&lt;img src="cid:logo"&gt;&lt;br&gt;
東京都練馬区南大泉5-38-7　プレイン昭代103&lt;br&gt;
TEL：03-5308-5198&lt;br&gt;
URL: https://www.atage.jp/&lt;br&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p> </p>
<p class="fname">Gmail宛に送信されたメール</p>
<p><a href="https://www.atage.jp/wp-content/uploads/2016/08/Screenshot-from-2016-08-24-21-18-521.png"><img src="https://www.atage.jp/wp-content/uploads/2016/08/Screenshot-from-2016-08-24-21-18-521.png" alt="" title="Screenshot from 2016-08-24 21-18-52" width="541" height="511" class="alignnone size-full wp-image-3257" /></a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3233/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>libHaruを使ってPHPでPDFを生成(3)</title>
		<link>https://www.atage.jp/archives/3158/</link>
		<comments>https://www.atage.jp/archives/3158/#comments</comments>
		<pubDate>Tue, 20 May 2014 11:06:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3158</guid>
		<description><![CDATA[前回から少し間が開きましたが、libHaruを使ったPDF生成の最終回。パスワードと使用権限を設定する方法について紹介します。]]></description>
			<content:encoded><![CDATA[<p>少し間が開きましたがlibHaruを使ったPDFの生成でパスワードと使用権限の設定について紹介します。</p>
<h6 class="sub-title">パスワードの設定</h6>
<p><a href="http://www.php.net/manual/ja/harudoc.setpassword.php" target="_blank">HaruDoc::setPassword</a>でパスワードを指定するだけです。</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPassword('foo', 'bar');

  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $doc-&gt;useJPFonts();
  $doc-&gt;useJPEncodings();

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf', true);
  $ipam = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 0);

  $page-&gt;beginText();

  $page-&gt;setTextRenderingMode(HaruPage::FILL);

  $text = mb_convert_encoding('パスワード', 'SJIS-win', 'UTF-8');

  $page-&gt;setFontAndSize($ipam, 36);
  $page-&gt;textOut(350, $page_h - 200, $text);

  $page-&gt;endText();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p>生成されたPDFのプロパティをAcrobat Readerで見ると40bitのRC4で暗号化されていることが確認できます。</p>
<p><img src="https://www.atage.jp/wp-content/uploads/2014/05/haru0.png" alt="" title="haru0" width="431" height="323" class="alignnone size-full wp-image-3161" /></p>
<p>現状ではlibHaruはRC4のみの対応となっていますが、鍵の長さを128bitにすることができます。</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPassword('foo', 'bar');
  $doc-&gt;setEncryptionMode(HaruDoc::ENCRYPT_R3, 16);</pre><p> </p>
<p><img src="https://www.atage.jp/wp-content/uploads/2014/05/haru128.png" alt="" title="haru128" width="431" height="323" class="alignnone size-full wp-image-3163" /></p>
<h6 class="sub-title">使用権限の設定</h6>
<p>使用権限の設定も簡単で、<a href="http://www.php.net/manual/ja/harudoc.setpermission.php" target="_blank">HaruDoc::setPermission</a>で権限を指定するだけです。</p>
<p>たとえば印刷とドキュメント内のテキストや画像をコピーする権限を有効にする場合は以下のようにします。</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPassword('foo', 'bar');
  $doc-&gt;setEncryptionMode(HaruDoc::ENCRYPT_R3, 16);
  $doc-&gt;setPermission(HaruDoc::ENABLE_PRINT | HaruDoc::ENABLE_COPY);</pre><p> </p>
<p><img src="https://www.atage.jp/wp-content/uploads/2014/05/haruprintcopy.png" alt="" title="haruprintcopy" width="433" height="323" class="alignnone size-full wp-image-3167" /></p>
<p>マニュアルには記述はありませんが、すべての権限を無効にするには0を指定すればよさそうです。</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPassword('foo', 'bar');
  $doc-&gt;setEncryptionMode(HaruDoc::ENCRYPT_R3, 16);
  $doc-&gt;setPermission(0);</pre><p> </p>
<p><img src="https://www.atage.jp/wp-content/uploads/2014/05/haruperm0.png" alt="" title="haruperm0" width="433" height="323" class="alignnone size-full wp-image-3165" /></p>
<p>3回に渡ってlibHaruによるPDF生成を紹介しましたが、PHPで動的にPDFを生成する必要に迫られたときの選択肢としては上位に入るという印象を持ちました。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3158/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>emacs24</title>
		<link>https://www.atage.jp/archives/3110/</link>
		<comments>https://www.atage.jp/archives/3110/#comments</comments>
		<pubDate>Mon, 28 Apr 2014 12:23:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3110</guid>
		<description><![CDATA[開発で使っているUbuntu12.04のパッケージのemacsのバージョンが23ということもあり、23を使っていたのですが、先日遅ればせながら24にアップデートしてパッケージ周りを見直しました。便利なパッケージや設定を紹介します。]]></description>
			<content:encoded><![CDATA[<p>開発で使っているUbuntu12.04のパッケージのemacsのバージョンが23ということもあり、23を使っていたのですが、先日遅ればせながら24にアップデートしてパッケージ周りを見直しました。便利なパッケージや設定を紹介します。</p>
<h6 class="sub-title">パッケージ管理</h6>
<p>24からpackage.elが標準でバンドルされていて、melpla、marmaladeという非公式なリポジトリも利用可能です。</p>
<p></p><pre class="crayon-plain-tag">(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/"))
(package-initialize)</pre><p> </p>
<h6 class="sub-title">フォント設定</h6>
<p>いままでVLゴシックを使っていましたが、<a href="http://save.sys.t.u-tokyo.ac.jp/~yusa/fonts/rictydiminished.html" target="_blank">Ricty Diminished</a>に移行しました。</p>
<p>ttfファイルを~/.fontsにコピーしてフォントキャッシュを再作成して~/.emacs.d/init.elに以下を追加すればOKです。</p>
<p class="fname">フォントキャッシュの再作成</p>
<p></p><pre class="crayon-plain-tag">$ fc-cache -vf</pre><p></p><pre class="crayon-plain-tag">(set-face-attribute 'default nil
                    :family "Ricty Diminished Discord"
                    :height 110)
(set-fontset-font (frame-parameter nil 'font)
                  'japanese-jisx0208
                  (cons "Ricty Diminished Discord" "iso10646-1"))
(set-fontset-font (frame-parameter nil 'font)
                  'japanese-jisx0212
                  (cons "Ricty Diminished Discord" "iso10646-1"))
(set-fontset-font (frame-parameter nil 'font)
                  'katakana-jisx0201
                  (cons "Ricty Diminished Discord" "iso10646-1"))</pre><p> </p>
<h6 class="sub-title">helm</h6>
<p>anythingの後継で、関連パッケージの開発も活発に行われています。キーバインドに違和感があるのでキーバインドを変更しています。</p>
<p></p><pre class="crayon-plain-tag">(require 'helm-config)
(global-set-key (kbd "C-c h") 'helm-mini)
(helm-mode 1)
(custom-set-variables '(helm-ff-auto-update-initial-value nil))
(define-key helm-c-read-file-map (kbd "TAB") 'helm-execute-persistent-action)
(define-key helm-c-read-file-map (kbd "&lt;C-backspace&gt;") 'backward-kill-word)
(require 'helm-descbinds)
(helm-descbinds-mode)
(require 'helm-ls-git)
(require 'helm-ag)</pre><p> </p>
<h6 class="sub-title">icicles</h6>
<p></p><pre class="crayon-plain-tag">(require 'icicles)
(icy-mode)
(setq icicle-sort-function nil)
(setq icicle-sort-functions-alist nil)</pre><p> </p>
<h6 class="sub-title">multi-term</h6>
<p>複数のターミナルを開くことができます。24.3からは文字色の<a href="http://stackoverflow.com/questions/15661372/adjusting-term-faces-in-the-new-emacs-24-3" target="_blank">指定方法が変更</a>されています。</p>
<p></p><pre class="crayon-plain-tag">(require 'multi-term)
(add-hook 'term-mode-hook '(lambda ()
                           (setq show-trailing-whitespace nil)))
(global-set-key (kbd "C-c t")
               '(lambda () (interactive) (multi-term)))
(global-set-key (kbd "C-c n") 'multi-term-next)
(global-set-key (kbd "C-c p") 'multi-term-prev)
(setq multi-term-program shell-file-name
     ansi-term-color-vector [term
                             term-color-black
                             term-color-green
                             term-color-yellow
                             term-color-blue
                             term-color-magenta
                             term-color-cyan
                             term-color-white])</pre><p> </p>
<h6 class="sub-title">migemo</h6>
<p>ローマ字入力で日本語検索ができます。ruby版を使っていましたが、<a href="https://github.com/koron/cmigemo" target="_blank">C版</a>に移行しました。Ubuntu12.04にはcmigemoのパッケージも用意されていますが、辞書ファイルの文字コードがUTF-8ではないので、ソースから入れました。</p>
<p></p><pre class="crayon-plain-tag">(setq migemo-dictionary "/usr/local/share/migemo/utf-8/migemo-dict")
(setq migemo-command "cmigemo")
(setq migemo-options '("-q" "-e"))
(setq migemo-user-dictionary nil)
(setq migemo-regex-dictionary nil)
(setq migemo-coding-system 'utf-8)
(load-library "migemo")
(migemo-init)</pre><p> </p>
<h6 class="sub-title">magit, git-gutter</h6>
<p>バージョン管理システムgit関連。magitは従来から使っていたのですが、<a href="https://github.com/syohex/emacs-git-gutter" target="_blank">git-gutter</a>を新たに追加しました。コミットからの変更箇所が一目で分かります。</p>
<p></p><pre class="crayon-plain-tag">(require 'magit)
(require 'git-gutter)
(global-git-gutter-mode +1)</pre><p> </p>
<h6 class="sub-title">flycheck</h6>
<p>構文チェックにはflymakeを使っていましたが、flycheckに移行しました。flymakeは言語ごとにパッケージをインストールする必要がありましたが、flycheckではそれ自身で多くの言語に対応していて簡単に導入できます。</p>
<p></p><pre class="crayon-plain-tag">(require 'flycheck)
(add-hook 'after-init-hook #'global-flycheck-mode)</pre><p> </p>
<h6 class="sub-title">web-mode</h6>
<p>htmlの編集にはhtml-helper-modeを使っていましたが、インデントに不満がありました。web-modeでインデントの問題が解消されました。</p>
<p></p><pre class="crayon-plain-tag">(require 'web-mode)
(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.php\\'" . web-mode))</pre><p> </p>
<h6 class="sub-title">elscreen</h6>
<p>emacs上でscreenライクなインターフェイスを実現できます。パッケージからインストールした新しいバージョンでは、以下の1行を書くだけで利用できます。最近はtabbarというパッケージもあるようです。</p>
<p></p><pre class="crayon-plain-tag">(elscreen-start)</pre><p> </p>
<h6 class="sub-title">sdic</h6>
<p>英辞郎の検索に使っています。</p>
<p></p><pre class="crayon-plain-tag">(autoload 'sdic-describe-word "sdic" "英単語の意味を調べるW" t nil)
(autoload 'sdic-describe-word-at-point "sdic" "カーソルの位置の英単語の意味を調べる" t nil)
(global-set-key "\C-cw" 'sdic-describe-word)
(global-set-key "\C-cW" 'sdic-describe-word-at-point)
(setq sdic-eiwa-dictionary-list
      '((sdicf-client "/usr/share/dict/eijiro112.sdic")))
(setq sdic-waei-dictionary-list
      '((sdicf-client "/usr/share/dict/waeiji112.sdic"
                      (add-keys-to-headword t))))
(setq sdic-default-coding-system 'utf-8-unix)</pre><p> </p>
<h6 class="sub-title">mozc</h6>
<p>emacsで日本語入力にmozcが使えます。</p>
<p></p><pre class="crayon-plain-tag">(require 'mozc)
(setq default-input-method "japanese-mozc")
(define-key global-map "\C-o" 'toggle-input-method)</pre><p> </p>
<h6 class="sub-title">w3m<br />
<h6>
<p>emacsでw3mが使えます。</p>
<p></p><pre class="crayon-plain-tag">(setq w3m-profile-directory "`/.w3m")
(setq w3m-language "Japanese")
(setq w3m-use-japanese-menu t)
(require 'w3m)
(require 'w3m-session)
(add-hook 'w3m-mode-hook '(lambda ()
                            (define-key w3m-mode-map "W" 'w3m-session-save)
                            (define-key w3m-mode-map "L" 'w3m-session-load)
                            (define-key w3m-mode-map "\C-c\C-k" 'copy-region-as-kill)
                            (define-key w3m-mode-map "\C-t" 'other-window-or-split)
                            (setq show-trailing-whitespace nil)))
(setq newsticker-html-renderer 'w3m-region
      browse-url-browser-function 'w3m-browse-url)</pre><p> </p>
<h6 class="sub-title">sequential-command</h6>
<p>コマンドを連続入力した場合に動作を変えることができます。ちょっとしたツールですが便利です。</p>
<p></p><pre class="crayon-plain-tag">(require 'sequential-command-config)
(global-set-key "\C-a" 'seq-home)
(global-set-key "\C-e" 'seq-end)</pre><p> </p>
<h6 class="sub-title">各種言語モード</h6>
<p>php-mode, js2-mode, less-css-mode, ruby-mode, lua-modeなどの言語モードを使っています。</p>
<p>他にもいくつか使ってるモードもありますが、主なものをざっと並べてみました。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3110/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>libHaruを使ってPHPでPDFを生成(2)</title>
		<link>https://www.atage.jp/archives/3067/</link>
		<comments>https://www.atage.jp/archives/3067/#comments</comments>
		<pubDate>Wed, 26 Mar 2014 08:48:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3067</guid>
		<description><![CDATA[libHaruを使ってPHPからPDFを生成する方法の2回目。今回は文字列の扱いについてです。]]></description>
			<content:encoded><![CDATA[<p>前回からの続きでlibHaruを使って文字列を扱ってみます。</p>
<h6 class="sub-title">文字の表示</h6>
<p>IPAゴシック、IPA明朝の等幅フォントを使って文字を表示してみます。主なポイントは次の通りです。</p>
<ul>
<li>日本語を使う場合は、useJPEncodings()で日本語エンコーディングを有効にする必要があります。今回はIPAフォントを使いますが、組み込みの日本語フォントを使う場合は、useJPFonts()で有効にします。</li>
<li>getFont()の第2引数でエンコーディングを指定します。エンコーディングの一覧はこちら。日本語でつかえるのは、RKSJの付く3つとEUCで始まる2つです。名前の通り、前3つはSJIS、後の2つはEUCです。Hは横書き、Vは縦書きです。</li>
<li>文字をレンダリングするときのモードが塗りつぶしや外形のみなど8種類あり、setTextRenderingMode()で指定できます。</li>
<li>beginText()でテキストの挿入開始、endText()終了。</li>
<li>textOut()で挿入位置を指定しますが、文字のベースラインの開始点(横書きなら左端)が基準になります。文字の左下、左上ではないことに注意が必要です。</li>
<li>ベースラインからの上下の幅はgetAscent(), getDescent()で得られます。フォントサイズに対するパーミル値を返しますので、1000で除したものをフォントサイズに乗ずれば幅が得られます。</li>
</ul>
<p class="fname">コード例：日本語の表示</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $doc-&gt;useJPFonts();
  $doc-&gt;useJPEncodings();

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf', true);
  $ipag = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf', true);
  $ipam = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 0);

  $modes = array(
    HaruPage::FILL,
    HaruPage::STROKE,
    HaruPage::FILL_THEN_STROKE,
    HaruPage::INVISIBLE,
    HaruPage::FILL_CLIPPING,
    HaruPage::STROKE_CLIPPING,
    HaruPage::FILL_STROKE_CLIPPING,
    HaruPage::CLIPPING
  );

  $page-&gt;beginText();

  $i = 0;
  foreach($modes as $mode) {
    $page-&gt;setTextRenderingMode($mode);

    $page-&gt;setFontAndSize($ipag, 40);
    $ascent = ($ipag-&gt;getAscent() / 1000) * 40;
    $page-&gt;textOut(0, $page_h - $ascent - 40 * $i, mb_convert_encoding("薔薇、憂鬱、麒麟", 'SJIS-win', 'UTF-8'));

    $page-&gt;setFontAndSize($ipam, 40);
    $ascent = ($ipam-&gt;getAscent() / 1000) * 40;
    $page-&gt;textOut(400, $page_h - $ascent - 40 * $i, mb_convert_encoding("薔薇、憂鬱、麒麟", 'SJIS-win', 'UTF-8'));

    $i++;
  }

  $page-&gt;endText();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test3.pdf'>出力されたPDFはこちら</a></p>
<h6 class="sub-title">文字列の幅</h6>
<p>描画した文字列の幅を求めるには、HaruPage::getTextWidth()を使います。HaruFontにも同じ名前のメソッドがあるので要注意です。</p>
<p class="fname">コード例：アンダーライン</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $doc-&gt;useJPFonts();
  $doc-&gt;useJPEncodings();

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf', true);
  $ipam = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf', true);
  $ipamp = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 0);

  $page-&gt;beginText();

  $page-&gt;setTextRenderingMode(HaruPage::FILL);

  $text = mb_convert_encoding('等幅フォントとプロポーショナルフォント', 'SJIS-win', 'UTF-8');

  $page-&gt;setFontAndSize($ipam, 36);
  $page-&gt;textOut(50, $page_h - 50, $text);
  $ipam_width = $page-&gt;getTextWidth($text);
  $ipam_descent = $ipam-&gt;getDescent();

  $page-&gt;setFontAndSize($ipamp, 36);
  $page-&gt;textOut(50, $page_h - 100, $text);
  $ipamp_width = $page-&gt;getTextWidth($text);
  $ipamp_descent = $ipamp-&gt;getDescent();

  $page-&gt;endText();

  $page-&gt;moveTo(50, $page_h - 50);
  $page-&gt;lineTo(50 + $ipam_width, $page_h - 50);
  $page-&gt;stroke();

  $page-&gt;moveTo(50, $page_h - 100);
  $page-&gt;lineTo(50 + $ipamp_width, $page_h - 100);
  $page-&gt;stroke();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test31.pdf'>出力されたPDFはこちら</a></p>
<h6 class="sub-title">moveToTextPos()による位置決め</h6>
<p><P>長い文章を表示する場合、textOut()での位置決めは大変ですので、moveTextPos()を使います。行の送り幅を定義(setTextLeading())して改行(showTextNextLine())で改行することもできます。</p>
<p class="fname">コード例：改行</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $doc-&gt;useJPFonts();
  $doc-&gt;useJPEncodings();

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf', true);
  $ipam = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf', true);
  $ipamp = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 0);

  $page-&gt;beginText();

  $page-&gt;setTextRenderingMode(HaruPage::FILL);

  $text = mb_convert_encoding('moveToText()とshowText()で文字列を表示', 'SJIS-win', 'UTF-8');

  $page-&gt;setFontAndSize($ipam, 18);
  $page-&gt;setTextLeading(18);
  $page-&gt;moveTextPos(0, $page_h - 18);
  $page-&gt;showText($text);
  $page-&gt;showText($text);
  $page-&gt;showTextNextLine($text);

  $page-&gt;endText();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test4.pdf'>出力されたPDFはこちら</a></p>
<h6 class="sub-title">文字列の変形</h6>
<p>setTextMatrix()で文字列を変形させることができます。</p>
<p class="fname">コード例：文字列の変形</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {

  $doc = new HaruDoc;

  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $doc-&gt;useJPFonts();
  $doc-&gt;useJPEncodings();

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf', true);
  $ipam = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $font_name = $doc-&gt;loadTTF('/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf', true);
  $ipamp = $doc-&gt;getFont($font_name,'90msp-RKSJ-H');

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 0);

  $page-&gt;beginText();

  $page-&gt;setTextRenderingMode(HaruPage::FILL);

  $text = mb_convert_encoding('変形', 'SJIS-win', 'UTF-8');

  $page-&gt;setTextMatrix(2, pi()/8, pi()/4, 1, 0, 0);

  $page-&gt;setFontAndSize($ipam, 36);
  $page-&gt;textOut(50, $page_h - 200, $text);

  $page-&gt;setTextMatrix(1, pi()/4, pi()/4, 2, 0, 0);

  $page-&gt;setFontAndSize($ipam, 36);
  $page-&gt;textOut(250, $page_h - 200, $text);

  $page-&gt;setTextMatrix(1, pi(), pi(), 1, 0, 0);

  $page-&gt;setFontAndSize($ipam, 36);
  $page-&gt;textOut(350, $page_h - 200, $text);

  $page-&gt;endText();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test5.pdf'>出力されたPDFはこちら</a></p>
<p>次回はパスワードの設定などについてみていきます。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3067/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>libHaruを使ってPHPでPDFを生成(1)</title>
		<link>https://www.atage.jp/archives/3021/</link>
		<comments>https://www.atage.jp/archives/3021/#comments</comments>
		<pubDate>Sun, 23 Mar 2014 02:44:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=3021</guid>
		<description><![CDATA[PHPからPDFを生成する方法はいろいろありますが、libHaruを利用した方法を試してみました。初回は図形の描画についてです。]]></description>
			<content:encoded><![CDATA[<p>PHPでPDFを生成する方法はいろいろありますが、実験的なモジュールではありますが、PHPのマニュアルにも掲載のある<a href="http://libharu.org/" target="_blank">libHaru</a>を使ったものを使ってみました。</p>
<p>環境は、Ubuntu12.04、PHP5.3です。</p>
<h6 class="sub-title">インストール</h6>
<p>libharuを入れて、peclでインストールできます。</p>
<p></p><pre class="crayon-plain-tag">$ sudo apt-get install libhpdf-dev
$ sudo pecl install haru</pre><p> </p>
<p>PHPにharu.soを読み込む設定を追加してapacheを再起動します。</p>
<p class="fname">/etc/php5/apache2/conf.d/haru.ini</p>
<p></p><pre class="crayon-plain-tag">extension=haru.so</pre><p> </p>
<p>phpinfo()の出力にharuが追加されていればOKです。</p>
<p><img src="https://www.atage.jp/wp-content/uploads/2014/03/haru.png" alt="" title="haru" width="611" height="120" class="alignnone size-full wp-image-3022" /></p>
<p>日本語文字出力にIPAフォントを使いますので、インストールしていない場合は、インストールします。</p>
<p></p><pre class="crayon-plain-tag">$ sudo apt-get install fonts-ipafont-gothic fonts-ipafont-mincho</pre><p> </p>
<h6 class="sub-title">図形の描画</h6>
<p>ドキュメントの左下が座標の原点となり、長さの単位は<a href="http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88" target="_blank">DTPポイント</a>を使います。A4横の場合、幅は841.89001464844、高さは595.27600097656です。</p>
<p class="fname">コード例：ページの背景色をグレーに</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {
  $doc = new HaruDoc;
  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $page-&gt;setRGBStroke(0.7, 0.7, 0.7);
  $page-&gt;setRGBFill(0.7, 0.7, 0.7);

  $page-&gt;rectangle(0, 0, $page_w, $page_h);
  $page-&gt;fillStroke();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p class="fname">コード例：基本的な図形の描画</p>
<p>図形の描画はペン(setRBGStroke, setDash, setLineWidth etc)と刷毛(setRGBFill etc)を選んで、描画(stroke, fillStroke)を行います。</p>
<p>直線はペンを始点に移動して終点を指定して描画します。少し違和感があるのが、円弧の開始角、終了角で、時計の12時の位置を0度として時計回りに角度を測ります。</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {
  $doc = new HaruDoc;
  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $page-&gt;setRGBStroke(0.7, 0.7, 0.7);
  $page-&gt;setRGBFill(0.7, 0.7, 0.7);

  $page-&gt;rectangle(0, 0, $page_w, $page_h);
  $page-&gt;fillStroke();

  $page-&gt;setRGBStroke(1, 0, 0);
  $page-&gt;setRGBFill(0, 0, 1);

  // 直線
  $page-&gt;moveTo(0, $page_h);
  $page-&gt;lineTo(100, $page_h - 100);
  $page-&gt;stroke();

  // 円弧
  $page-&gt;arc(100, $page_h - 100, 100, 0, 225);
  $page-&gt;stroke();

  // 円
  $page-&gt;setLineWidth(5);
  $page-&gt;circle(310, $page_h - 100, 100);
  $page-&gt;fillStroke();

  // 楕円
  $page-&gt;setDash(array(15, 3), 0);
  $page-&gt;ellipse(420, $page_h - 100, 120, 80);
  $page-&gt;stroke();

  // 傾いた矩形
  $page-&gt;setLineWidth(1);
  $page-&gt;setDash(array(), 0);
  $page-&gt;moveTo(200, $page_h - 350);
  $page-&gt;lineTo(200 + 80, $page_h - 350 + 60);
  $page-&gt;lineTo(200 + 80 - 30, $page_h - 350 + 60 + 40);
  $page-&gt;lineTo(200 + 80 - 30 - 80, $page_h - 350 + 60 + 40 - 60);
  $page-&gt;closePath();
  $page-&gt;fillStroke();

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test.pdf'>出力されたPDFはこちら</a></p>
<p>ベジェ曲線も描画できますが今回は割愛します。</p>
<h6 class="sub-title">画像の挿入</h6>
<p>画像を挿入するときに指定する座標は、画像の左上の位置になります。</p>
<p class="fname">コード例：PNG画像の挿入</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
try {
  $doc = new HaruDoc;
  $doc-&gt;setPageMode(HaruDoc::PAGE_MODE_USE_THUMBS);

  $page = $doc-&gt;addPage();
  $page-&gt;setSize(HaruPage::SIZE_A4, HaruPage::LANDSCAPE);

  $page_w = $page-&gt;getWidth();
  $page_h = $page-&gt;getHeight();

  $page-&gt;setRGBStroke(0.7, 0.7, 0.7);
  $page-&gt;setRGBFill(0.7, 0.7, 0.7);

  $page-&gt;rectangle(0, 0, $page_w, $page_h);
  $page-&gt;fillStroke();

  $img = $doc-&gt;loadPNG(__DIR__ . '/Emacs23.png');

  $page-&gt;drawImage($img, 0, $page_h - $img-&gt;getHeight(), $img-&gt;getWidth(), $img-&gt;getHeight());

  header('Content-Type: application/pdf');
  header('Content-Disposition: attachment; filename=test.pdf');
  $doc-&gt;output();

} catch(Exception $e) {
  echo $e-&gt;getFile().'('.$e-&gt;getLine().'):'.$e-&gt;getMessage();
}
?&gt;</pre><p> </p>
<p><a href='https://www.atage.jp/wp-content/uploads/2014/03/test21.pdf'>出力されたPDFはこちら</a></p>
<p>次回は文字についてみていきます。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/3021/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CasperJSでWebスクレイピング</title>
		<link>https://www.atage.jp/archives/2940/</link>
		<comments>https://www.atage.jp/archives/2940/#comments</comments>
		<pubDate>Wed, 26 Feb 2014 09:34:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=2940</guid>
		<description><![CDATA[昨今JavaScriptを使っていないページを見ることが少なくなりました。今回は、JavaScriptでレンダリングしたページのスクレイピングにCasperJSを使う方法を紹介します。]]></description>
			<content:encoded><![CDATA[<p>JavaScriptを使用したページが多くなり、一昔前のツールではスクレイピングできないページに行き当たることが多くなりました。そこでSeleniumのようなブラウザを操ることができるツールが出てきて、JavaScriptを使用したページのスクレイピングやテストができるようになりました。</p>
<p>しかし、GUIブラウザを起動してコントロールさせてとなると、とても時間がかかる。そこでGUIのないブラウザ、ヘッドレスブラウザの登場となりました。</p>
<p><a href="http://casperjs.org/" target="_blank">CasperJS</a>は、ヘッドレスブラウザを使ったクライアントサイドテストやスクレイピングをより簡単に記述できるツールです。</p>
<p>対応しているヘッドレスブラウザは、<a href="http://phantomjs.org/" target="_blank">PhantomJS</a>(WebKitベース)と<a href="http://slimerjs.org/" target="_blank">SlimerJS</a>(Gekoベース)です。ただし、SlimerJSは厳密にはヘッドレスではなく、GUIブラウザを起動しています。</p>
<h6 class="sub-title">実例</h6>
<p>以下のようなページを用意します。一昔前のスクレイピングツールではtitleを取り出した場合、&#8221;書き換え前&#8221;となってJavaScriptによる処理を拾えませんでした。</p>
<p class="fname">html</p>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;link rel="stylesheet" href="" type="text/css" media="all" /&gt;
    &lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" charset="UTF-8"&gt;
      $(function(){
        $("title").text("書き換え後");
      });
    &lt;/script&gt;
    &lt;title&gt;書き換え前&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p> </p>
<p class="fname">CasperJSスクリプト</p>
<p></p><pre class="crayon-plain-tag">"use strict";

var casper = require('casper').create({
  verbose: true,
  logLevel: 'debug'
});

casper.start('http://test/index.html', function() {
  this.echo(this.getTitle());
});

casper.run(function() {
  this.exit();
});</pre><p> </p>
<p>CasperJSをPhantomJS、SlimerJSで実行すると以下の通り、いずれも&#8221;書き換え後&#8221;が取り出せていて、JavaScriptによる処理が拾えています。</p>
<p>処理時間は、SlimerJSはPhantomJSの3倍近くかかっていて、GUIブラウザを使う分かなり遅いです。</p>
</p>
<p></p><pre class="crayon-plain-tag">$ casperjs --engine=phantomjs scraper.js 
[info] [phantom] Starting...
[info] [phantom] Running suite: 2 steps
[debug] [phantom] opening url: http://test/index.html, HTTP GET
[debug] [phantom] Navigation requested: url=http://test/index.html, type=Other, willNavigate=true, isMainFrame=true
[debug] [phantom] url changed to "http://test/index.html"
[debug] [phantom] Successfully injected Casper client-side utilities
[info] [phantom] Step anonymous 2/2 http://test/index.html (HTTP 200)
書き換え後
[info] [phantom] Step anonymous 2/2: done in 227ms.
[info] [phantom] Done 2 steps in 244ms</pre><p> </p>
<p></p><pre class="crayon-plain-tag">$ casperjs --engine=slimerjs scraper.js
[info] [phantom] Starting...
[info] [phantom] Running suite: 2 steps
[debug] [phantom] opening url: http://test/index.html, HTTP GET
[debug] [phantom] Navigation requested: url=http://test/index.html, type=Undefined, willNavigate=true, isMainFrame=true
[debug] [phantom] url changed to "http://test/index.html"
[debug] [phantom] Successfully injected Casper client-side utilities
[info] [phantom] Step anonymous 2/2 http://test/index.html (HTTP 200)
書き換え後
[info] [phantom] Step anonymous 2/2: done in 683ms.
[info] [phantom] Done 2 steps in 696ms</pre><p> </p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/2940/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mustacheのphp実装でフィルター</title>
		<link>https://www.atage.jp/archives/2943/</link>
		<comments>https://www.atage.jp/archives/2943/#comments</comments>
		<pubDate>Thu, 20 Feb 2014 09:24:41 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=2943</guid>
		<description><![CDATA[<p>以前紹介した<a href="https://github.com/bobthecow/mustache.php" target="_blank">こちら</a>のmustacheのphp実装ではsmartyやtwigで使えるパイプ記法のフィルターが使えます。</p>]]></description>
			<content:encoded><![CDATA[<p>以前紹介した<a href="https://github.com/bobthecow/mustache.php" target="_blank">こちら</a>のmustacheのphp実装ではsmartyやtwigで使えるパイプ記法のフィルターが使えます。今回はこのパイプ記法について紹介します。</p>
<p>※mustacheには本来ない機能ですので、テンプレートを他の言語でも使いたいという場合には注意が必要です。</p>
<h6 class="sub-title">実例</h6>
<p>例えば、フィルターを使ってゼロパッディングとゼロサプレスを行うには以下のようにします。テンプレートに{{%FILTERS}}pragmaを入れることでフィルタ記法を解釈するようになります。</p>
<p class="fname">php</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
require_once(dirname(__FILE__).'/../vendor/autoload.php');

$m = new Mustache_Engine(array(
  'loader' =&gt; new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/../views'),
  'partials_loader' =&gt; new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/../views/partials'),
  'escape' =&gt; function($v) {
    return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
  },
));

$m-&gt;addHelper('zero', array(
  'padding' =&gt; function($v) { return sprintf('%04d', $v); },
  'suppress' =&gt; function($v) { return preg_replace('/^0+/', '', $v); }));

$v = array(
  'code1' =&gt; '1',
  'code2' =&gt; '0001',
);

$tpl = $m-&gt;loadTemplate('index');
echo $tpl-&gt;render($v);
?&gt;</pre><p> </p>
<p class="fname">mustache template</p>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;title&gt;mustache&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    {{%FILTERS}}
    &lt;p&gt;{{code1|zero.padding}}&lt;/p&gt;
    &lt;p&gt;{{code1|zero.suppress}}&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p> </p>
<h6 class="sub-title">注意！</h6>
<p>mustache準拠のlambdaを使えば同じことができるように思えますが、lambdaでは変数の展開が行われる前に関数に&#8221;{{変数}}&#8221;が文字列として渡ってしまうためエラーや想定外の結果となることがあります。いつ展開が行われるか、注意が必要です。</p>
<p class="fname">php</p>
<p></p><pre class="crayon-plain-tag">&lt;?php
require_once(dirname(__FILE__).'/../vendor/autoload.php');

$m = new Mustache_Engine(array(
  'loader' =&gt; new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/../views'),
  'partials_loader' =&gt; new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/../views/partials'),
  'escape' =&gt; function($v) {
    return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
  },
));

$v = array(
  'code' =&gt; '1',
  'zeropadding' =&gt; function($v) { return sprintf('%04d', $v); },
);

$tpl = $m-&gt;loadTemplate('index');
echo $tpl-&gt;render($v);
?&gt;</pre><p> </p>
<p class="fname">mustache template</p>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;title&gt;mustache&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;{{#zeropadding}}{{code}}{{/zeropadding}}&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p> </p>
<p class="fname">展開結果</p>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;title&gt;mustache&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;0000&lt;/p&gt; <!--// 0001ではない! -->
  &lt;/body&gt;
&lt;/html&gt;</pre><p> </p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/2943/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NginxのSPDY3.1パッチがリリース</title>
		<link>https://www.atage.jp/archives/2908/</link>
		<comments>https://www.atage.jp/archives/2908/#comments</comments>
		<pubDate>Tue, 28 Jan 2014 12:08:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">https://www.atage.jp/?p=2908</guid>
		<description><![CDATA[<p>当ホームページはSPDY2に対応しておりましたが、NginxのSPDY3.1パッチがリリース</a>されましたので、バージョンアップしました。</p>]]></description>
			<content:encoded><![CDATA[<p>当ホームページは現在SPDY2に対応しておりましたが、<a href="http://mailman.nginx.org/pipermail/nginx-devel/2014-January/004890.html" target="_blank">NginxのSPDY3.1パッチがリリース</a>されましたので、バージョンアップしてみました。</p>
<p>バージョンアップの前後でchrome://net-internals/#spdyの出力とコマンドラインで使えるSPDYのクライアント<a href="https://github.com/tatsuhiro-t/spdylay" target="_blank">spdycat</a>の出力は以下の通り。</p>
<h6 class="sub-title">バージョンアップ前</h6>
<p><a href="https://www.atage.jp/wp-content/uploads/2014/01/spdy21.png" target="_blank"><img src="https://www.atage.jp/wp-content/uploads/2014/01/spdy21.png" alt="" title="spdy2" width="800" class="alignnone size-full wp-image-2926" /></a></p><pre class="crayon-plain-tag">$ spdycat -nv https://www.atage.jp/
[  0.080] NPN select next protocol: the remote server offers:
          * spdy/2
          * http/1.1
          NPN selected the protocol: spdy/2
[  0.100] Handshake complete
[  0.100] send SYN_STREAM frame &lt;version=2, flags=1, length=179&gt;
          (stream_id=1, assoc_stream_id=0, pri=3)
          :host: www.atage.jp
          :method: GET
          :path: /
          :scheme: https
          :version: HTTP/1.1
          accept: */*
          accept-encoding: gzip, deflate
          user-agent: spdylay/1.2.3-DEV
[  0.890] recv SYN_REPLY frame &lt;version=2, flags=0, length=430&gt;
          (stream_id=1)
          content-encoding: gzip
          content-type: text/html; charset=UTF-8
          date: Tue, 28 Jan 2014 12:03:53 GMT
          server: nginx/1.5.8
          set-cookie: wassup=ODQ4Njk4NmNlZWZlMTMxZmMwZTA5MmIwYWU2NWMyMTI6OjEzOTA5MTMzMzI6Ojo6MjE4LjIxOS4yNDcuMTAwOjpsMjQ3MTAwLnBwcC5hc2FoaS1uZXQub3IuanA6Og%253D%253D; expires=Tue, 28-Jan-2014 12:53:52 GMT; path=/
          :status: 200 OK
          :version: HTTP/1.1
          x-pingback: https://www.atage.jp/xmlrpc.php
[  0.891] recv SETTINGS frame &lt;version=2, flags=1, length=12&gt;
          (niv=1)
          [4(1):100]
[  0.934] recv DATA frame (stream_id=1, flags=1, length=6911)
[  0.934] send GOAWAY frame &lt;version=2, flags=0, length=4&gt;
          (last_good_stream_id=0)</pre><p> </p>
<h6 class="sub-title">バージョンアップ後</h6>
<p><a href="https://www.atage.jp/wp-content/uploads/2014/01/spdy31.png" target="_blank"><img src="https://www.atage.jp/wp-content/uploads/2014/01/spdy31.png" alt="" title="spdy3" width="800" class="alignnone size-full wp-image-2927" /></a></p><pre class="crayon-plain-tag">$ spdycat -nv https://www.atage.jp/
[  0.074] NPN select next protocol: the remote server offers:
          * spdy/3.1
          * http/1.1
          NPN selected the protocol: spdy/3.1
[  0.096] Handshake complete
[  0.097] send SYN_STREAM frame &lt;version=3, flags=1, length=219&gt;
          (stream_id=1, assoc_stream_id=0, pri=3)
          :host: www.atage.jp
          :method: GET
          :path: /
          :scheme: https
          :version: HTTP/1.1
          accept: */*
          accept-encoding: gzip, deflate
          user-agent: spdylay/1.2.3-DEV
[  0.116] recv SETTINGS frame &lt;version=3, flags=1, length=20&gt;
          (niv=2)
          [4(0):100]
          [7(0):2147483647]
[  0.116] recv WINDOW_UPDATE frame &lt;version=3, flags=0, length=8&gt;
          (stream_id=0, delta_window_size=2147418111)
[  0.956] recv SYN_REPLY frame &lt;version=3, flags=0, length=464&gt;
          (stream_id=1)
          :status: 200 OK
          :version: HTTP/1.1
          content-encoding: gzip
          content-type: text/html; charset=UTF-8
          date: Tue, 28 Jan 2014 12:58:47 GMT
          server: nginx/1.5.9
          set-cookie: wassup=OTUxMWI1OTA3OWU2YjEyNjdhM2YwZjgwMWRmMzZiYmM6OjEzOTA5MTY2MjY6Ojo6MjE4LjIxOS4yNDcuMTAwOjpsMjQ3MTAwLnBwcC5hc2FoaS1uZXQub3IuanA6Og%253D%253D; expires=Tue, 28-Jan-2014 13:48:46 GMT; path=/
          x-pingback: https://www.atage.jp/xmlrpc.php
[  0.956] recv DATA frame (stream_id=1, flags=1, length=6911)
[  0.956] send GOAWAY frame &lt;version=3, flags=0, length=8&gt;
          (last_good_stream_id=0)</pre><p> </p>
<p>バージョンが3.1に上がっていて、send windowやreceive windowの項目が追加されていることが確認できます。バージョンアップの効果は機会があれば検証したいと思います。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/2908/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>grunt-useminでJS、CSSを結合</title>
		<link>https://www.atage.jp/archives/2828/</link>
		<comments>https://www.atage.jp/archives/2828/#comments</comments>
		<pubDate>Fri, 17 Jan 2014 01:02:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コラム]]></category>

		<guid isPermaLink="false">http://www.atage.jp/?p=2828</guid>
		<description><![CDATA[読み込むJavaScriptファイルを1ファイルに結合してロード時間を短縮する際に便利な、Gruntのタスク grunt-usemin を紹介します。]]></description>
			<content:encoded><![CDATA[<p>昨今のWebアプリでは複数のJavaScriptライブラリを当たり前のように使うようになりましたが、パッケージマネージャとしてbowerを使っている方も多いと思います。</p>
<p>読み込むJavaScriptファイルが多くなるに連れて、読み込みの時間に悩まされることが多くなります。そこで個別に読み込むのではなく、1ファイルに結合してロード時間を短縮するということが行われます。</p>
<p>タスク自動化ツールの<a href="http://gruntjs.com/" target="_blank">Grunt</a>には、パッケージマネージャbowerで落としたJSファイルを1つにまとめるためのタスクがいくつかあります。ただ、bowerパッケージのディレクトリ構成の規約が甘く、パッケージによっては依存関係をいちいち書き下す必要があるものがほとんどです。</p>
<p>今回紹介する<a href="https://github.com/yeoman/grunt-usemin" target="_blank">grunt-usemin</a>は依存関係はhtmlを参照すればよいということに目を付けたのがポイント。使い勝手のよいタスクになっています。JSだけでなく、CSSの結合もできます。</p>
<h6 class="sub-title">ディレクトリ構成</h6>
<p>以下のようなディレクトリ構成でappが開発用、distが本番デプロイ用のディレクトリです。テンプレートエンジンを使っていて、テンプレート(拡張子は.html)がapp/views以下にあるものとします。</p>
<p>やりたいことは、以下の2つ。</p>
<ul>
<li>app/views以下にあるテンプレートを読み込んでそこに書かれているJS、CSSをそれぞれ結合、圧縮してdistのpublic/scripts、public/stylesにファイルを作る。</li>
<li>app/views以下にあるテンプレートをdist/viewsにコピーして、読み込むJS、CSSを上で作ったファイルに置き換える。</li>
</ul>
<p></p><pre class="crayon-plain-tag">.
├── .bowerrc
├── .git
├── .gitignore
├── Gruntfile.js
├── app // 開発用
│   ├── cache
│   ├── database
│   ├── include
│   ├── public // DocumentRoot
│   │   ├── bower_components
│   │   ├── images
│   │   ├── index.php
│   │   ├── scripts
│   │   └── styles
│   ├── test
│   ├── upload
│   ├── vendor
│   └── views // テンプレート
├── bower.json
├── composer.json
├── dist // 本番デプロイ用
├── node_modules
└── package.json</pre><p> </p>
<h6 class="sub-title">htmlに結合ルールを記述</h6>
<p>app/views以下のhtmlの結合したいJS、CSSの前後に以下のようなコメントを入れます。</p>
<p class="fname">CSS</p>
<p></p><pre class="crayon-plain-tag">&lt;!-- build:css styles/common.css --&gt;
&lt;link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.css"&gt;
&lt;link rel="stylesheet" type="text/css" href="bower_components/jquery.ui/dist/jquery-ui.min.css"&gt;
&lt;!-- endbuild --&gt;</pre><p> </p>
<p class="fname">JS</p>
<p></p><pre class="crayon-plain-tag">&lt;!-- build:js scripts/common.js --&gt;
&lt;script src="bower_components/less.js/dist/less-1.5.1.min.js"&gt;&lt;/script&gt;
&lt;script language="javascript" type="text/javascript" src="bower_components/jquery/jquery.min.js"&gt;&lt;/script&gt;
&lt;script src="bower_components/bootstrap/dist/js/bootstrap.js"&gt;&lt;/script&gt;
&lt;script language="javascript" type="text/javascript" src="bower_components//jquery.ui/dist/jquery-ui.min.js"&gt;&lt;/script&gt;
&lt;!-- endbuild --&gt;</pre><p> </p>
<p>コメントのルールは以下の通りで、typeの部分にjs or cssを指定します。(alternate search path)の部分は今回は使わず、Gruntfileで指定します。</p>
<blockquote style="border:2px solid gray; margin:1em; padding:1em; background-color:#eee;"><p>
&lt;!&#8211; build:&lt;type&gt;(alternate search path) &lt;path&gt; &#8211;&gt;<br />
&#8230; HTML Markup, list of script / link tags.<br />
&lt;!&#8211; endbuild &#8211;&gt;
</p></blockquote>
<h6 class="sub-title">Gruntfile</h6>
<p>Gruntfile.jsは以下の通り。useminPrepareはGruntのタスクを生成、useminはhtmlのJS、CSSの読み込み部分の書き換えを行います。</p>
<p class="fname">Gruntfile.js</p>
<p></p><pre class="crayon-plain-tag">copy: {
      main: {
        files: [{
          expand: true,
          cwd: 'app/',
          src: ['views/**/*.html'],
          dest: 'dist/'
        }]
      }
    },

    useminPrepare: {
      html: ['app/views/**/*.html'],
      options: {
        root: 'app/public',
        dest: 'dist'
      }
    },
    usemin: {
      html: ['dist/views/**/*.html'],
      options: {
        root: 'app/public',
        dirs: ['dist']
      }
    }</pre><p> </p>
<p>useminPrepareを実行するとconcatやuglifyの処理を事前に確認できます。</p>
<p></p><pre class="crayon-plain-tag">$ grunt useminPrepare
(...)
Configuration is now:

  concat:
  { generated: 
   { files: 
      [ { dest: '.tmp/concat/styles/common.css',
          src: 
           [ 'app/public/bower_components/bootstrap/dist/css/bootstrap.css',
             'app/public/bower_components/jquery.ui/dist/jquery-ui.min.css' ] },
        { dest: '.tmp/concat/scripts/common.js',
          src: 
           [ 'app/public/bower_components/less.js/dist/less-1.5.1.min.js',
             'app/public/bower_components/jquery/jquery.min.js',
             'app/public/bower_components/bootstrap/dist/js/bootstrap.js',
             'app/public/bower_components/jquery.ui/dist/jquery-ui.min.js' ] } ] } }

  uglify:
  { generated: 
   { files: 
      [ { dest: 'dist/scripts/common.js',
          src: [ '.tmp/concat/scripts/common.js' ] } ] } }

  cssmin:
  { generated: 
   { files: 
      [ { dest: 'dist/styles/common.css',
          src: [ '.tmp/concat/styles/common.css' ] } ] } }

Done, without errors.</pre><p> </p>
<p>タスクを実行するとdist以下に結合、圧縮後のJS、CSSファイルとそのファイルを使うように書き換えられたhtmlが生成されます。</p>
<p></p><pre class="crayon-plain-tag">$ grunt useminPrepare concat uglify cssmin copy usemin</pre><p> </p>
<p>上のコマンドを打つのは面倒なので、Gruntfileにタスクを登録しておきましょう。</p>
<p></p><pre class="crayon-plain-tag">grunt.registerTask('myusemin', ['useminPrepare', 'concat', 'uglify', 'cssmin', 'copy', 'usemin']);</pre><p> </p>
<h6 class="sub-title">感想</h6>
<p>grunt-useminはhtmlに簡単なコメントを入れるだけで、結合、圧縮ファイルが生成され、それにあわせてhtmlも書き換えてくれるという優れもので、重宝しそうです。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.atage.jp/archives/2828/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
