Croppyの作り方

Web サイト構築のためのトータルデザイン誌 Web Designing 2011年 12月号 に、jQuery × WordPress 活用事例ということで Croppy の作り方を掲載させて頂きました。

記事は2ページしかない関係でほんの一部の情報とソースしか掲載出来なかったため、こちらの記事で色々と補足させて頂きたいと思います。

ちなみに、この記事は WordPress Advent Calendar 2011 という「12月1日から12月25日のクリスマスまで一人一つずつ自分のブログにWordPressについて何かしら書いてくイベント」で昨日の @horike37 さんに続き、6番バッターとして執筆しています。

How to make

目次

  • なぜ WordPress で作ったのか
  • 記事の追加はどうやっているのか
  • 記事の削除はどうやっているのか
  • Web Designing記事の補足
  • 色彩分析などの情報はどうやって保管しているか
  • サーバ周りと負荷対策

なぜ WordPress で作ったのか

Croppy を WordPress で制作した理由は、主に

ということです。
次に制作するWebサービスは CakePHP 2.0 を使おうと思っていて今勉強中ですが、現時点では Croppy を CakePHP などのフレームワークで作ったほうが良かったのか、それとも WordPress で作って正解だったのかはちょっと分かりません。

ただ、WordPress は非常にカスタマイズしやすく、私のようなプログラミングが苦手なデザイナーでもなんとかサービスをリリースすることができました。
WordPress はやりたいことを Google で検索すれば大抵のことは分かりましたし、速度やサーバの負荷も全く問題ありませんでした。

記事の追加はどうやっているのか

「WordPress を使えば本格的な Webサービスが作れるのでは?」と感じたのは、以下の記事を読んだことがきっかけでした。

WordPress でゲストに記事投稿させるフォームが作れる wp_insert_post() 関数が便利すぎてぎっくり腰になる件 | ウェブル

この関数を使えば WordPress の管理画面からでなくても記事を投稿することができます。
おそらくこの関数を使って、ウェブルの @soraiy さんは以下のようなサービスを作っていました。

従って、Croppy のアイディアを思いついたときに「WordPress を使えば簡単に作れるのではないか」と思い、WordPress をベースに制作することにしました。

記事の投稿は、WordPress フォルダの中に /add/post.php という PHP スクリプトを作り、そちらで行なっています。
テーマフォルダ以外の場所にある PHP は、そのままでは WordPress の関数が使用できないので、以下の関数を使用します。

require_once('../wp-load.php');

require_once 関数を使って WordPressディレクトリ内にある wp-load.php を読み込むと、WordPress 独自の関数が使えますし、ユーザーが WordPress にログインしていればそのユーザーの情報を表示したり、そのユーザーとして記事を投稿することができます。

次に、ログインしていないユーザーは投稿できないようにします。
is_user_logged_in() は WordPress にログインしている場合に true になる WordPress の関数です。

// ログインしていなければ終了
if ( !is_user_logged_in() ) {
	
	// トップページURL
	$url = get_bloginfo('url');
	
	// エラーメッセージ
	echo <<< EOF




画像を切り抜き


ログインした状態でないとページを追加できません。お手数ですがトップページよりログインしてください。

EOF; exit(); }

この下に、POSTで値を取得し、取得した値に問題がなければ先ほどの wp_insert_post() 関数を使って記事を投稿させれば、WordPress で構築した Webサービス上から記事を投稿できるようになります。

crop.php

ちなみに、記事のキャプチャは wkhtmltoimage という WebKit モジュールをさくらのクラウドにインストールし、それを使ってキャプチャした画像を PNG で保存、JCrop という jQuery プラグインを使ってドラッグで選択できるようにし、選択範囲(左上と右下)の座標を form に入れ、PHP の GD ライブラリを使って切り抜いています。

記事の削除はどうやっているのか

Croppy を作るにあたり、真っ先に決めたことは「ユーザーには WordPress の管理画面を見せない」ということでした。
WordPress では、記事の修正や削除は WordPress の管理画面を使ったほうが楽ですが、一般のユーザーの方からは WordPress を意識せず、一般の Webサービスと同じように使って欲しかったのです。

そこで問題になるのが「記事を削除させるにはどうするか」ということですが、自分が投稿した記事の場合、投稿記事(テーマの single.php)ページの右下に「この投稿を削除」リンクを付けることにしました。

以下の記事に具体的なやり方が書いてありました。

お手軽WordPress Tips:閲覧している記事をその場で削除するボタンを設置する – かちびと. net

Web Designing記事の補足

Web Designing の 2011年12月号の72〜73ページに「jQuery と WordPress で構築したソーシャル Web サービス」というタイトルで、Croppy のソースコードの一部を公開しています。

具体的には、「フォロー機能をどうやって実装しているか」や「キャプチャした画像の切り抜き」の部分です。

残念ながら、紙面の関係上各ソースコードの関連図を掲載することができなかったため、ここに掲載しておきます。

ソースの関連図

B、C、D はそれぞれ記事内のソースコード B、C、D に対応しています。

色彩分析などの情報はどうやって保管しているか

色彩分析

投稿された記事の中には「色彩分析」というコーナーがあり、切り抜かれたパーツに含まれる最大25色のカラーコードが表示されています。

これは、切り抜かれた画像を PHP の GDライブラリ で解析してカラーコードを取得し、RGB それぞれの1の位が0になるよう丸めた上で、最大25色までをカスタムタクソノミーに保存しています。

色をまとめる処理に関しては、 yuki さんのブログに書かれている方法と同じようなことをやっています。

PHOTO STOCKERに似た色が使われている画像が簡単に検索できる機能を実装してみました!

最初、カラーコードは カスタムフィールド に保存しようかと思っていたのですが、 @miya0001 さんより検索の際の負荷を考えると「カスタムタクソノミー」の方が良いとアドバイスを頂いたのでリリース直前にカスタムタクソノミーに変更しました。

カスタムタクソノミーを使用するためには、テーマの functions.php に以下のようなコードを入れておきます。

// カスタムタクソノミー 'color(labelはカラーコード)' の追加
function create_my_taxonomies() {
	register_taxonomy(
		'color',
		'post',
		array(
			'hierarchical' => false,
			'label' => 'カラーコード',
			'query_var' => true,
			'rewrite' => true
		)
	);
}

あとは、記事を追加するスクリプト(/add/post.php)で記事を投稿した後、記事の ID を指定し、カスタムタクソノミーをセットすることができます。

// カスタムタクソノミー 'color' をセット
// $postid==記事ID, $colors_key==セットしたい内容の配列, 'color'==カスタムタクソノミー名
wp_set_object_terms( $postid, $colors_key, 'color' );

サーバ周りと負荷対策

仮想サーバ

Croppy は、オープン直後はこのブログと同じサーバ(さくらのVPS 512M)で動かしていたのですが、キャプチャに使っている wkhtmltoimage がキャプチャした瞬間にメモリを食い過ぎたり、たまに暴走して CPU を 100% 専有し続けるためか時々 Croppy のページが表示されなくなることがありました。

そこで、現在は さくらのクラウド のプラン1(CPU 1コア、メモリ2GB、ディスク20GB)で動かしています。結論から言うと、swap が発生することもなくかなり快適に動作しています。

サーバは、このブログと同じく Apache は使用せず、Nginx で Proxy Cache を使用しています。
Nginx の設定は Krayさんのブログの設定↓に近いです。

WordPressを100倍速くする! MySQLの調整やnginx proxy cache | KRAY Inc

この設定の場合、ログインしていないユーザーにはキャッシュしたページを見せるためほとんどサーバに負荷がかかりません。

Croppy の場合、ログインしている方も多いはずなので、WordPress によるサーバの負荷が心配でしたが、ログインしている方がそこそこいた場合でもサーバの負荷はほとんどありませんでした。

キャプチャソフトの多重起動対策

問題は wkhtmltoimage の多重起動によるスラッシングで、VPS の頃にサーバの挙動を見ていると、どうやらキャプチャを開始するためのブックマークレットが連続でクリックされたために wkhtmltoimage が多重起動され、VPS のメモリが不足してスラッシングが発生しているケースがあるようでした。

そこで、WordPress の update_option() 関数を使い、キャプチャを開始する PHP (/add/index.php)が実行された日時を update_option() で記録しておき、次回からは、まず get_option() 関数で保存されている時間と現在の時間を比較し、前回キャプチャした時間から+15秒以上経過していなければキャプチャさせないようにしました。
これで、wkhtmltoimage の多重起動によるスラッシングは多少抑えられたようです。

// 最後に投稿した時刻を取得
$lasttime = get_option('cp_lasttime');

// 現在時刻を取得
$nowtime = time();

// 現在時刻+15秒を取得
$nowtimeminus = time(strtotime('now'))-15;

// もし15秒以内であれば
if ( $lasttime > $nowtimeminus ) {
	
	// エラーメッセージ
	echo <<< EOF




画像を切り抜き


連続して切り抜こうとしたためプログラムの実行を停止しました。

以下の可能性が考えられます。

  • 誰かが同時に切り抜こうとした
  • ブックマークレットを連続してクリックした(ブックマークレットは1度だけクリックして、しばらくお待ちください)

お手数をおかけして申し訳ありませんが、ブラウザの[戻る]ボタンで前のページに戻り、15秒以上経過してからブックマークレットをクリックして下さい。

EOF; exit(); } // 現在時刻を「最後に投稿した時刻」とする update_option( 'cp_lasttime', $nowtime );

現在使用している さくらのクラウド では、wkhtmltoimage が暴走しても top コマンドで CPU 使用率を確認するまではほとんど気づかない程度です。
ただ、キャプチャ終了後に wkhtmltoimage プロセスが残っていた場合や数分間起動し続けていた時は強制終了する方法がないか、これから調べようと思っています。

CDN

Nginx Proxy Cache を使っていれば負荷に関してはまず大丈夫だろうと思ったのですが、画像が多いサイトなので念のため CDN を導入しておくことにしました。

コンテンツデリバリネットワーク(CDN)- Wikipedia

CDN は Akamai などが有名で料金は非常に高いらしいですが、最近は無料で使用できる CDN もあります。

Croppy では、無料でも利用できる CloudFlare という CDN を使用しています。

追記

CloudFlare を入れるとページの表示レスポンスが下がるのと、2回ほど CloudFlare 側がダウンしたため結局外しました。

CloudFlareはHTMLはキャッシュしませんが、画像やCSS、JSなどをキャッシュしてくれます。
管理画面を見るかぎり、トラフィックの8割ほどは CDN 側でさばいてくれているようです。

【画像付き導入記】 CloudFlareが便利そうなんでWordpressブログに導入してみた | IDEA*IDEA

Nginx も CloudFlare も、お金をかけずに負荷対策できるのでとても素晴らしいですね。

これだけ負荷対策していれば、GIGAZINE で紹介されようが Yahoo! ニュースに掲載されようがサーバは大丈夫ですね(^o^) → 掲載されませんでした orz

明日の WordPress Advent Calendar 2011 は…なんと、皆さんご存知の @naokomc さんことマクラケン直子さんです!

If you like this article click the Facebook “Like” button to share it with your friends!