モノノフ日記

普通の日記です

第1回symfony勉強会

株式会社ディノさんで開催された第1回symfony勉強会に参加してきました。会場提供ありがとうございます!
気になるところノートにメモったので軽く感想レポ。詳細は公開されるであろう資料をw

15分くらい遅刻したのですが、何とかプレゼンには間に合ってよかった。。

symfonyの基本を理解する (発表資料)(Ustream動画)

  • 現状のフレームワークは何かしらRailsの影響受けてるので元を辿ればRailsのパクリだよね
    • helper
    • plugin
    • scaffolding
  • symfony-doc-ja
    • 僕も参加してちまちま和訳してます(主にpluginの所)
    • 参加者募集しているので興味ある人はご一報ください!
  • CheatSheet
  • Cache
    • sfFunctionCache
    • sfProcessCache
      • memcachedみたいに使うと、凄い便利そう
  • テストについても触れて欲しかった

symfonyによる自社サービスの作成事例について (発表資料)(Ustream動画)

  • 日本での導入事例
  • トレイン・トレイン
  • サーバ構成
    • Webサーバ1台 + DBサーバ2台
      • WebサーバはXenで動かしてるらしい
  • ドキュメントが日本語
    • 正直、プログラマーが英語を読むのためらってどうするの?と思う
  • DB+ORM
  • schema周りが弱い
    • これはOSSのORM使ってる宿命かと
    • 満足するにはオレオレORM作るしかない
  • FAQ
    • doctrineとPropelの速度比較は?
      • 全く同じコードなら、たぶんdoctrineの方が若干速い
      • doctrineは妙な動作が多いので、そこが少し怖い
    • 開発環境は個人のもXenで構築してる
      • これいいなー。ウチも導入するべきと思った

symfonyの展望とversion1.1の見所 (Ustream動画)

  • 今日の目標
    • 人柱を増やす
  • Form
  • Contoroller(Action)にはあんまり処理書かないってのは激しく同意
  • ORM
    • Propel1.2→1.3でどれだけ変わるか調べたい
    • CLIからサーバ固有情報(DSN)を入力
      • configファイルに書かないのでDSNを構成に入れない運用が可能
  • Cache
    • 1.0はファイルベース
    • 1.1はmemcachedやAPCでキャッシングしようとする
      • これは期待大!
  • YAML
    • 自前パーサに置き換わった
      • 詳細なエラーが出るようになりました
  • Config
    • config.phpは無くなって、configもクラス化

Lightning Talk

手ぶらLT (Ustream動画)
  • キャッシュ生成時の動作について
symfony.el (Ustream動画)
Symfonian (資料まとめ)(Ustream動画)
  • i18nサイトの作り方
  • Symfonianというsymfony使ってる人用のSNSがある
    • 3月にOSS化されたのでそれを参考に
懇親会
  • 秋元さんに「ブログ書くだけでどれだけもらってんだ」の件をいろいろ聞きましたw
  • もちろん、その他にもいろいろ参考になるお話が聞けました
  • symfonyIRCチャンネル作って集まろうよ、という話が
    • 月宮さんが「誰もいないけど、もうあるよ」発言w
    • freenodeの#symfony-ja

みなさんお疲れ様でした。大盛況でしたねー。
月イチで開催したいという事なので興味ある人は参加しましょう!

ITMediaの記事がブログに貼りやすくなったらしいので

早速試してみました。

画像にするのはメリットデメリット両方ありそうなんで、ケースバイケースで使い分けようかなと思います。
あと個人的な不満点は、

文章での引用禁止とかは明言していないですよね・・?

PECL::Imagickを試す

GDで展開できない画像*1があったのでImageMagickを試そうと思って導入してみました。

インストール

peclモジュールなのでコマンドライン1発で楽チン。

sudo pecl install imagick

php.iniにライブラリを呼び出す記述を追加

extension=imagick.so

実際に使ってみる

マニュアルはいろいろ探しましたが、PHPマニュアルが一番詳しいと思います。
PHP: Imagick 画像ライブラリ - Manual
しかしPHPマニュアルもAPI一覧のみで詳しい解説は書かれていないので実際に使って試してみました。

サンプル画像はこれです。

リサイズしてみた

APIリストを眺めてみるとリサイズに使いそうなメソッドである下記5つを試してみました。

  • Imagick::adaptiveResizeImage
  • Imagick::cropImage
  • Imagick::thumbnailImage
  • Imagick::resizeImage
  • Imagick::cropThumbnailImage
Imagick::adaptiveResizeImage
メソッドの説明

データに依存する三角測量にもとづいて画像のサイズを変更する, と記述されてますが何のことやら。。引数のcolumns, rowsはマニュアルページのサンプルコードから類推すると、それぞれ縦幅, 横幅の様です。

bool Imagick::adaptiveResizeImage ( int $columns , int $rows )

http://jp2.php.net/manual/ja/function.imagick-adaptiveresizeimage.php
サンプルコード

300x300の正方形にリサイズしています。

<?php
  $image = new Imagick('/path/to/sample.jpg');
  $image->adaptiveResizeImage(300,300);
  header('Content-type: image/jpeg');
  echo $image;
結果
Fatal error: Call to undefined method Imagick::adaptiveResizeImage()

メソッドが無いみたいです。とりあえず次へw

Imagick::cropImage
メソッドの説明

切り取りたい縦・横幅と元画像の切り取り開始位置を引数にとってます。よくあるcropメソッドですね。

bool Imagick::cropImage ( int $width , int $height , int $x , int $y )

http://jp2.php.net/manual/ja/function.imagick-cropimage.php
サンプルコード

300x300の大きさで、元画像の左隅(0,0)からcropさせてみました。

<?php
  $image = new Imagick('/path/to/sample.jpg');
  $image->cropImage(300,300, 0, 0);
  header('Content-type: image/jpeg');
  echo $image;
結果

f:id:Kiske:20080217121007j:image

元画像の左隅の壁の部分がcropできてます。

Imagick::thumbnailImage
メソッドの説明

fitをtrueにすると、columnsかrowsの小さい方の値に合わせてサムネイルが生成される模様です。

bool Imagick::thumbnailImage ( int $columns , int $rows [, bool $fit ] )

画像のサイズを指定したものに変更し、関連付けられたプロパティをすべて削除します。 ウェブ上での表示に適した小さなサムネイル画像を作成します。 3 番目のパラメータに true を指定すると、columns や rows にそれぞれの最大値を使用します。両方のパラメータが、 マッチするまであるいは指定したパラメータより小さくなるまで縮小されます。

http://jp2.php.net/manual/ja/function.imagick-thumbnailimage.php
サンプルコード

300x300の大きさで、filをtrueにしてサムネイル生成

<?php
  $image = new Imagick('/path/to/sample.jpg');
  $image->thumbnailImage(300, 300, true);
  header('Content-type: image/jpeg');
  echo $image;
結果

f:id:Kiske:20080408141932j:image
元画像の比率を維持したまま、サムネイル生成しています。大きさは画像の最大長側(この場合は横幅)を基準としているため300x225にリサイズされています。

Imagick::resizeImage
メソッドの説明

Imagick::thumbnailImage()との違いはfilter, blurを指定できる所の様です。

bool Imagick::resizeImage ( float $columns , float $rows , int $filter , float $blur )

指定した大きさとフィルタで、画像のサイズを変更します。

http://jp2.php.net/manual/ja/function.imagick-resizeimage.php
サンプルコード

マニュアルのサンプルコードをまねて、LANCZOSフィルタ*2を使ってみます。その他の各種フィルタ定数はマニュアルを参考してください

<?php
  $image = new Imagick('/path/to/sample.jpg');
  $image->resizeImage(300, 300, imagick::FILTER_LANCZOS, 0);
  header('Content-type: image/jpeg');
  echo $image;
結果

f:id:Kiske:20080217121007j:image

無理やり300x300に縮小しているので比率がおかしくなっています。

Imagick::cropThumbnailImage
メソッドの説明

縮小してからサムネイルを生成するメソッド。centerから指定した大きさで切り取ってくれてる様です。

bool Imagick::cropThumbnailImage ( int $width , int $height )

固定サイズのサムネイルを作成します。まず画像のサイズを縮小し、指定した範囲を中心から切り取ります。

http://jp2.php.net/manual/ja/function.imagick-cropthumbnailimage.php
サンプルコード

300x300のサムネイルを生成しています。

<?php
  $image = new Imagick('/path/to/sample.jpg');
  $image->cropThumbnailImage(300, 300);
  header('Content-type: image/jpeg');
  echo $image;
結果

f:id:Kiske:20080408143555j:image
元画像と比較すると、左右が切り取りとられていますが比率は維持されています。

まとめ

ざっくりと用途を考えると下みたいな感じでしょうか。

メソッド名 用途
Imagick::adaptiveResizeImage メソッドが存在しないようなので使えない
Imagick::cropImage 元画像から切り取る範囲が決まっている
Imagick::thumbnailImage 比率維持したまま、サムネイル作りたい
Imagick::resizeImage フィルタ使って、サムネイル作りたい
Imagick::cropThumbnailImage 比率維持したまま、中心から任意の範囲を切り取りたい

*1:VQ1005というトイカメラで撮影された画像

*2:aviutlのプラグインで見たことある名前

Vimperator 0.5.3を導入してみた

はてブホッテントリにVimperatorの紹介記事が上がってたのを見て今更ながら導入してみました。

ナレッジエース - Firefoxをキーボード操作できるプラグイン「Vimperator」の使い方に書かれてるリンクを参考に操作を覚えました。

以下、所感を箇条書きで挙げておきます。

  • 普段からvim使ってるので移動操作については特に違和感無し
  • f、;使ったリンク移動も案外すんなりと使える
  • dでタブ削除できるのイイ
  • uで削除したタブをUndoできるのもイイ
    • タブはvimでいうbufferと考えればよいみたい
  • ページ内の文章をコピーするやり方がわからない
  • ブックマークしてるURLをVimperatorから呼ぶ方法がわからない
  • プラグインいれると異様に便利になった
  • CodeReposに挙がってるプラグインは0.6pre用が多いので動かないモノもあった
    • リビジョン古いやつを辿って0.5.3用入れればOK
  • 操作に慣れてきてguioptionsを使わないようになるとブラウザが広く使えて良さそう
  • PC環境が若干非力なせいかちょっと重い時もある

f使ったクイックヒントは使いこなすとブラウジングが非常に高速化しそう。
ブックマークの件はmap使って、コマンドに登録すれば解決するのかな。

2008/04/09追記

id:otsuneさん、id:retletさんからコメント頂いてるように:t, :oでするとブックマーク候補を補完してくれます。実際に試してみました。

実行コマンド

HNの「Kiske」で補完してみます。ちなみに:tと押さなくても、tだけ押しても「:tabopen」とコマンドラインに補完してくれます。oも同じように「:open」に補完。

:t Kiske<tab>
結果

f:id:Kiske:20080409162337p:image
一杯でた。55件もヒット。
ザッと一覧した感じだと、ブックマークしてるURL、キーワード、あとブラウザの履歴からも補完してるみたいです。
これは便利すぐる!ますますマウス触る機会が減って幸せになれました。お二人方あざーっす!

タグクラウドのアルゴリズム

タグクラウドを生成する際のアルゴリズムをオープンソースのコードを参考にして現在考えてます。

symfony公式サイトで見つけたアルゴリズム

<?php
  while ($rs->next())
  {
    if (!$max_popularity)
    {
      $max_popularity = $rs->getInt('count');
    }
 
    $tags[$rs->getString('tag')] = floor(($rs->getInt('count') / $max_popularity * 3) + 1);
  }

すごいシンプルでびっくり。

処理の流れ

  1. タグの最大カウント数をmax_popularityとする
  2. 各タグのカウント数をmax_popularityで割り、タグクラウドの範囲から1引いた値をかける(ここでは3)
  3. 算出された値を切り上げて、0が無くなるように+1

この算出アルゴリズムだと最大の大きさを持つタグは1つだけで、それに小さいタグが群がる感じになります。
ただカウント数の差が大きいと最大の大きさのタグに最小のタグがわらわらと群がるので見た目のバランスが悪くなりました。

もっと平均的に振り分ける方法ないのかなと探してたら、タグクラウドのアルゴリズム (それなりブログ)を発見。

【最も基本的なアルゴリズム】

* 最終的に、各タグの大きさは25段階の範囲で区分される。ソース内ではこれを level と読んでおり、0-24の範囲で指定している。
* level算出方法は以下の通り
1. 最もタグ付けされている回数が多いタグの回数を取得し、それの平方根を求める。以後この値を max と呼ぶ。
2. 最もタグ付けされている回数が少ないタグの回数を取得し、それの平方根を求める。以後この値を min と呼ぶ。
3. max - min の間を均等に 25段階に分け、各タグのタグ付け回数の平方根の値が、その範囲のどこに位置するのかを求め、それが level となる。

http://kjirou.sakura.ne.jp/mt/2007/09/post_57.html

そうか、平方根使えばよかったのかと納得。

追記

PEARのHTML_Tagcloudのソースも見てみた。htmlタグを生成してるところだけ抜粋。

<?php
    private function _buidHTMLTags($param)
    {
        $this->total = count($this->_elements);
        // no tags elements
        if($this->total == 0){
            return array();
        }elseif($this->total == 1){
            $tag = $this->_elements[0];
            return $this->_createHTMLTag($tag, 'latest', $this->baseFontSize);
        }

        $limit = array_key_exists('limit', $param) ? $param['limit'] : 0;
        $this->_sortTags($limit);
        $this->_calcMumCount();
        $this->_calcMumEpoc();

        $range = $this->maxFontSize - $this->minFontSize;
        if($this->_max != $this->_min){
            $this->_factor = $range / (sqrt($this->_max) - sqrt($this->_min));
        }else{
            $this->_factor = 1;
        }

        if($this->_maxEpoc != $this->_minEpoc){
            $this->_epocFactor = count($this->epocLevel)
                                    / (sqrt($this->_maxEpoc) - sqrt($this->_minEpoc));
        }else{
        $rtn = array();
        foreach ($this->_elements as $tag) {
            $countLv = $this->_getCountLevel($tag['count']);
            if (! isset($tag['timestamp']) || empty($tag['timestamp'])) {
                $epocLv = count($this->epocLevel) - 1;
            } else {
                $epocLv  = $this->_getEpocLevel($tag['timestamp']);
            }
            $colorType = $this->epocLevel[$epocLv];
            $fontSize  = $this->minFontSize + $countLv;
            $rtn[] = $this->_createHTMLTag($tag, key($colorType), $fontSize);
        }
        return implode("", $rtn);
    }

やっぱ最大値/最小値の平方根の差を使って係数出してますね。
ただ最大値/最小値の値がタグのカウント数以外に、タイムスタンプも使ってるのが興味深い。タグの新鮮度でもレベル付けできるよってことですね。

しかし、_buidHTMLTagsってのはtypoだよね。すごい気になったw

WordPressでXSSの可能性?

社内のツールでWordPress2.5に対してセキュリティ診断かけたら、
1件Criticalが見つかるという始末。。

ちなみにWordPressはインストールしてすぐのデフォルトスキンの状態です。
コメントとトラックバックは無効にしました。

どこがXSSの原因になるのかと言うと、サイト内検索の結果画面でサイドバーに検索クエリーを表示をエスケープしてません。貼り付けた画像の赤い四角で囲ったところです。
f:id:Kiske:20080402143508j:image

修正箇所はwp-content/themes/default/sidebar.phpの33行目あたりになります。
get_search_query()をエスケープしてやればOKです。

<?php /* If this is a monthly archive */ } elseif (is_search()) { ?>
- <p><?php printf(__('You have searched the <a href="%1$s/">%2$s</a> blog archives for <strong>&#8216;%3$s&#8217;</strong>. If you are unable to find anything in these search results, you can try one of these links.', 'kubrick'), get_bloginfo('url'), get_bloginfo('name'), get_search_query() ); ?></p>
+ <p><?php printf(__('You have searched the <a href="%1$s/">%2$s</a> blog archives for <strong>&#8216;%3$s&#8217;</strong>. If you are unable to find anything in these search results, you can try one of these links.', 'kubrick'), get_bloginfo('url'), get_bloginfo('name'), htmlspecialchars(get_search_query(), ENT_QUOTES) ); ?></p>

しかしコメント不可にしてるし、XSSは出ないだろーと思ったら
思いっきり見つかったので有名なソフトでも安心はできないですね。。