Hatena::ブログ(Diary)

130単位

2009-05-29

エンジニア・サバイバルする姿勢

先週末のはなしですが、「エンジニアの未来サミット0905」の中継を視聴していました。

レポート:速報レポート:エンジニアの未来サミット0905|gihyo.jp … 技術評論社
http://gihyo.jp/news/report/2009/05/2501

志向性が近くてロールモデルとなりうるような優秀なエンジニアの方々の熱い議論は、非常に刺激的なものでした。

  • 責任感を持って、逃げない
  • 追い込まれても、とにかく必死にやってみる
  • 「できない」をすぐ理由にしない

このあたりの言葉はモロに刺さりました。自分の至らない点をあらためて認識でき、仕事に対する姿勢を考え直す良い機会となりました。

そして、ところどころで繰り返し出てきた

  • 自分のやりたいことをやる
  • とにかくやってみる

といった言葉。

今週、個人的なターニングポイントが偶然にもやってきたりしたのですが、これらを聞いていたおかげで前向きな決断と行動ができました。

「やらずに後悔よりも、やって後悔のほうが良い」

自重しないメンタルと、口だけにならない常に学び続ける姿勢でもって、これから先も臨んでいきたいと思います。

2009-05-27

画像による検索フォームのCSS (※IE6対応)

SafariGUIを適当に加工して作った検索バー。

f:id:deeeki:20090527203811j:image

こんな感じのものを、

  • 入力エリア(の背景)もボタンも画像
  • Webサイトのヘッダー上に配置

こんな仕様で実現するときのコード。

<div id="search_block">
  <form id="search_form" class="png_bg" method="post" action="search">
    <input id="search_text" type="text" name="search_text"/>
    <a id="search_button" class="png_bg" href="#">検索</a>
  </form>
</div>
div#search_block {
    position: absolute;                         /* 絶対配置 */
    top: 100px;
    left: 775px;
}
    div#search_block form#search_form {
        float: left;
        width: 240px;                           /* 検索フォーム画像幅 */
        height: 25px;                           /* 検索フォーム画像高さ */
        background: url(../images/search_form.png) no-repeat;
                                                /* 検索フォーム背景画像 */
    }
        div#search_block input#search_text {
            display: block;                     /* ブロック要素化 */
            float: left;                        /* 左寄せ */
            width: 150px;                       /* 入力欄の幅 */
            margin: 5px 5px 0 25px;             /* 入力欄の外側余白調整 */
            border-width: 0;                    /* 入力欄の枠線消去 */
            background: none;                   /* 入力欄の背景消去 */
        }

        div#search_block a#search_button {
            display: block;                     /* ブロック要素化 */
            float: left;                        /* 左寄せ */
            width: 55px;                        /* 検索ボタンの画像幅 */
            margin: 3px 0 0 0;                  /* 検索ボタンの外側余白調整 */
            background: url(../images/search_button.png) no-repeat;
                                                /* 検索ボタン通常画像 */
            text-indent: -9999px;               /* テキストを画面外に */
        }

        div#search_block a#search_button:hover {
            background: url(../images/search_button_hover.png) no-repeat;
                                                /* 検索ボタンマウスオーバー画像 */
        }

(※JavaScriptは省いてます)

  • ボタンにロールオーバー効果
    • input/button要素ではなく、a要素で
      • IE6:hover擬似クラスはa要素にしか対応していないため
  • 入力欄テキストボックスの左右余白はmarginで指定する
    • 入力が幅を超えたときに背景画像と重なってしまうため
  • input要素の既存スタイルを無効にする
    • 「border-width: 0;」と「background: none;」を指定

セレクタの指定が中途半端だったり、JSでできることをCSSで書いてたりしてて微妙かもしれませんが…。何か間違い等あればご指摘ください。

2009-05-25

FreeMindを使い始めてみた

A6ノートで読書を超速化しなさい―たった一週間でプロフェッショナル! ビジネス書をお金に変える魔法のノート術「シン

『A6ノートで読書を超速化しなさい』

koba氏に勧められて読みました。リターンを得るための読書記録の手段として、シンプルマッピング(マインドマップの簡易版)というものが紹介されています。

でもって、そのマインドマップを書くのにFreeMindを使い始めてみました。

FreeMind活用クラブ - マインドマップフリーソフトhttp://www.freemind-club.com/

これがなかなか使いやすいです。Enter、Insert、カーソルキーくらいで簡単に書けてしまいます。書いた後でブランチ(枝)の移動も自由に行えます。

本来のマインドマップは、多彩な色を用いたりイメージを描いたりするものかと思います。が、読書記録というものの性質と、効率性を重視することをふまえれば、こういったシンプルなかたちでも十分な効果はあるような気がします。

f:id:deeeki:20090525220600j:image

そんなわけで、週末を利用するなどして週1くらいで作成していければと思ってます。

2009-05-23

PHPExcel テンプレートを用いた書き込み&書式の設定

PHPExcel - OpenXML - Create Excel2007 documents in PHP - Spreadsheet engine - Home
http://phpexcel.codeplex.com/

PHPExcelは、テンプレートとなるExcelファイルを用意しておいて、そこへデータを書き込むことも可能です。今回はそのサンプルです。ついでに罫線も出力してみます。

テンプレートの用意

せっかくなので、CSVではできないことをしてみます。セル結合をしたヘッダーにして罫線を付与、さらにウインドウ枠を固定します。

f:id:deeeki:20090523120701j:image

コード例

<?php
//配列作成
$cd_list = array(
    array('(3rd Album)', '2009', '07', '08', 'AL'),
    array('ワンルーム・ディスコ', '2009', '03', '25', 'SG'),
    array('Dream Fighter', '2008', '11', '19', 'SG'),
    array('love the world', '2008', '07', '09', 'SG'),
    array('GAME', '2008', '04', '16', 'AL'),
);

//セルの書式 (文字列、上下左右に罫線)
$cell_style = array(
    'numberformat' => array('code' => PHPExcel_Style_NumberFormat::FORMAT_TEXT),
    'borders' => array(
        'top'     => array('style' => PHPExcel_Style_Border::BORDER_THIN),
        'bottom'  => array('style' => PHPExcel_Style_Border::BORDER_THIN),
        'left'    => array('style' => PHPExcel_Style_Border::BORDER_THIN),
        'right'   => array('style' => PHPExcel_Style_Border::BORDER_THIN)
    )
);

//ライブラリのインクルード
set_include_path(get_include_path() . PATH_SEPARATOR . './PHPExcel/Classes/');
include 'PHPExcel.php';
include 'PHPExcel/IOFactory.php';

//テンプレートを読み込んでインスタンス化
$objReader = PHPExcel_IOFactory::createReader("Excel5");
$objPHPExcel = $objReader->load("./template.xls");
            
//データのセット
$row = 3;		//ヘッダの行数を除く
foreach ($cd_list as $cd) {
    $col = 0;
    foreach ($cd as $value) {
        $objPHPExcel->getActiveSheet()->setCellValueExplicitByColumnAndRow($col, $row, $value, PHPExcel_Cell_DataType::TYPE_STRING);
        $objPHPExcel->getActiveSheet()->getStyleByColumnAndRow($col++, $row)->applyFromArray($cell_style);
    }
    $row++;
}

//Excel2003以前の形式でファイル出力
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('./cd_list.xls');

出力結果

f:id:deeeki:20090523120726j:image

簡単な解説

  • PHPExcel_Worksheet#setCellValueExplicitByColumnAndRow()で、セルにセットする値のデータ型を指定できる
    • PHPExcel_Cell_DataType::TYPE_STRINGにすると、先頭の0もそのまま出力される
  • PHPExcel_Style#applyFromArray()で、セルに連想配列から書式を適用することができる
    • ライブラリに同梱のTests/05featuredemo.inc.phpを参考
    • 一度に適用する場合は、PHPExcel_Worksheet#duplicateStyleArray()を用いると良いっぽい
      • Tests/22heavilyformatted.phpを参考
      • 第二引数に「"A1:T100"」と文字でセルの範囲を指定する必要がある
  • 'numberformat' => array('code' => PHPExcel_Style_NumberFormat::FORMAT_TEXT)にするメリット
    • ファイルをデータのエクスポートインポート兼用で扱う場合
      • セルの表示形式が標準のままだと、Excel上で先頭が0の数字の値とかに変更しづらい
      • エクスポート時に表示形式を文字列にしておくと、データ変更がスムーズになる

関連記事:

PHPExcel xlsファイルのデータを読み込む - 130単位

PHPExcelを使ってみた ループ編 - 130単位

2009-05-22

WordPress MU カスタマイズ記 その1

今は主にContact Form 7の改造をしています。

で、ローカルで開発していたものをサーバーにあげたら挙動が変わりました。

Ajaxで送信していなかった(ローカル)のが、Ajaxによる送信(サーバー)になったのです。

どうも原因は、ローカルのみで出る以下のJavaScriptのエラーっぽい(FireBugコンソールより)。

jQuery("div.friendship-button a").livequery is not a function

この「livequery」ってのがどこにあるかというと、Contact Form 7ではなくてBuddyPressの中にあります。

ローカルもサーバーも両方BuddyPressを有効にしてるので、問題はおそらく別のところ。

てことでローカル環境のプラグインを片っ端から停止してみたら、解決。

競合が起きていたのは、BuddyPressとCubePointsでした。

でも、CubePointsには「livequery」なんて記述は一切無いのです。

謎です。

(※WordPress MU Ver2.7.1)

参考リンク

Contact Form 7 (日本語) « iDeasilo
http://ideasilo.wordpress.com/2007/10/22/contact-form-7-in-japanese/

問い合わせフォーム作成プラグイン

BuddyPress.org - A WordPress MU Based Social Network Platform
http://buddypress.org/

SNSプラグイン

CubePoints | TechCube
http://techcube.net/cubepoints/

ポイント管理プラグイン

2009-05-21

条件付きで集計するにはSUM(CASE WHEN ...)

区分値(もしくはON/OFFのフラグ)のカラムがあるとして、それぞれの区分値のレコード数をカウントしたものを、1度のSQLで同時に取得したい。

これを満たそうとして、ひどいSQLを書いてしまっていたことがテスト段階にて発覚。

  • サンプル
    • ページ情報のテーブルと、アクセスログのテーブル
    • 2つのテーブルから、各ページの月別アクセス数を求める
    • ただし、PCと携帯のアクセスは別々に集計する

こんな仕様とします。(※試したDBPostgreSQL 8.3.7)

間違ったSQL

select
    t1.page_id,
    coalesce(t2.count, 0) as pc_access_count,
    coalesce(t3.count, 0) as mobile_access_count,
    coalesce(t2.count, 0) + coalesce(t3.count, 0) as access_count,
    t2.target_yyyymm
from tbt_page t1
    left outer join (
        select
            page_id,
            count(page_id),
            to_char(add_date, 'yyyymm') as target_yyyymm
        from tbt_access
        where mobile_flg = '0'
        group by page_id, target_yyyymm) t2
        on (t1.page_id = t2.page_id)
    left outer join (
        select
            page_id,
            count(page_id),
            to_char(add_date, 'yyyymm') as target_yyyymm
        from tbt_access
        where mobile_flg = '1'
        group by page_id, target_yyyymm) t3
        on (t1.page_id = t3.page_id and t2.target_yyyymm = t3.target_yyyymm)
where a.del_flg = '0'

「カウントする=COUNT関数」しか頭になく、区分値をWHERE句に指定したサブクエリを年月で強引に結合しています。その年月で結合している部分がまずくて、t2に無くてt3に存在したときでも値が入ってきません。

正しいSQL

こういうときは、SUM関数とCASE式を組み合わせて使うのでした。

select
    t1.page_id,
    t2.pc_access_count,
    t2.mobile_access_count,
    t2.access_count,
    t2.target_yyyymm
from tbt_page t1
    left outer join (
        select
            page_id,
            sum(case when mobile_flg = '0' then 1 else 0 end) as pc_access_count,
            sum(case when mobile_flg = '1' then 1 else 0 end) as mobile_access_count,
            count(page_id) as access_count,
            to_char(add_date, 'yyyymm') as target_yyyymm
        from tbt_access
        group by page_id, target_yyyymm) t2
        on (t1.page_id = t2.page_id)
where t1.del_flg = '0'

結合も1度で済み、だいぶすっきりしました。以前にもやった経験があったはずなのですが、SUM関数の存在自体を完全に忘れていました。

そんなわけで、自戒の意味もこめて書き残してみた次第です。

参考リンク

SQLアタマ養成講座:第3回 SQL流条件分岐(3) 表頭の複雑な集計|gihyo.jp … 技術評論社
http://gihyo.jp/dev/serial/01/sql_academy/0003

2009-05-19

CrystalDiskMark フォーマット前後のベンチマーク結果

以前より、HDDのうちの一つがCrystalDiskInfoにて「注意」と出ていたのです。

f:id:deeeki:20090520001819j:image

そこで1TB増設したこの機会に、バックアップを取ってから一旦フォーマット(+スキャンディスク)してみることにしました。で、ついでにベンチマークも計測してみました。

計測結果

元の状態

f:id:deeeki:20090520001821j:image:w200

f:id:deeeki:20090520001820j:image

フォーマット後

f:id:deeeki:20090520001823j:image:w200

f:id:deeeki:20090520001822j:image

ファイルを戻した状態

f:id:deeeki:20090520001825j:image:w200

f:id:deeeki:20090520001824j:image

雑感

フォーマット後に数値が上がったのは当然納得がいくのですが、ファイルを戻したらめちゃくちゃ低い結果になったのはなぜなのでしょうかねー。また、フォーマット後の健康状態も「注意」のままで、結局何もやった意味がなかったような感じです。

リンク

ソフトの入手はこちらから。

Crystal Dew World - ソフトウェア - CrystalDiskInfo
http://crystalmark.info/software/CrystalDiskInfo/

Crystal Dew World - ソフトウェア - CrystalDiskMark
http://crystalmark.info/software/CrystalDiskMark/

関連記事:
CrystalDiskMarkを使ってみた - 130単位

2009-05-18

CrystalDiskMarkを使ってみた

Crystal Dew World - ソフトウェア - CrystalDiskMark
http://crystalmark.info/software/CrystalDiskMark/

HDDフラッシュメモリなどのベンチマークができるフリーソフトです。

6年前のマザーボードで未だにIDE接続だったりするわけですが、とりあえず接続されているHDD全てを計測してみました。

計測結果

  • ST380021A (80GB)

f:id:deeeki:20090518235329j:image

f:id:deeeki:20090518235330j:image

f:id:deeeki:20090518235331j:image

f:id:deeeki:20090518235332j:image

雑感

一般的な値がどれほどなのかよく分かってないのですが、やはりUSBは遅いんだな、といった感じでしょうか。

あと、AQUA風ボタンの見栄えが地味に心地よかったりします。

2009-05-17

1TBのHDDとUSB接続外付けケースを購入

f:id:deeeki:20090517232155j:image

WesternDigitalのWD10EADSと、PLANEXの外付けHDDキット。

デスクトップPCのHDDをAcronis Migrate Easy 7.0でお気軽換装 - Future Insight
http://d.hatena.ne.jp/gamella/20090416/1239808944

こちらの記事を参考に、まるまる同じ組み合わせで購入しました。用途としてはデータ類のバックアップに使うつもりです。

購入

HDD

価格.com - WESTERN DIGITAL WD10EADS (1TB SATA300) 価格比較

(限定) Caviar WD10EADS バルク品 (1TB/SATA) | sofmap.com

ソフマップが安いです。5/17現在、送料無料で7480円*1

ケース

PLANEX 高速USB2.0接続 3.5インチシリアルATA対応 外付けHDDキット PL-35STU

Amazonで1980円です。

取り付け

f:id:deeeki:20090517232156j:image

中身はこんな感じ。電源やUSBケーブルや縦置きスタンドなんかがあります。

f:id:deeeki:20090517232157j:image

内側のトレイを取り出し、HDDを装着したところ。固定のためにネジで4カ所留める必要があります。

あとはケースに戻して、ケーブル類をつないでPCに接続します。

フォーマット

コントロールパネル→コンピュータの管理→ディスクの管理へ。

f:id:deeeki:20090517232316j:image

初期化されていません」と出てます。

f:id:deeeki:20090517232317j:image

ディスク初期化を行います。

f:id:deeeki:20090517232318j:image

続いてパーティションを作成して、フォーマット(けっこう時間がかかりました)。

f:id:deeeki:20090517232319j:image

これで使えるようになりました。

f:id:deeeki:20090517232158j:image

ちなみに温度は他の内蔵HDDよりも10℃近く低く*2、アルミケースの放熱効果はかなり高そうな印象です。

余談

購入したあとで知ったのですが、ケースの選択肢としてはこちらも良さ気です。

10秒で余ったHDDを外付け化できる「ガチャポンパッ!」
http://zapanet.info/blog/item/1546

ネジ不要&冷却ファン付きで4000円みたいです。


関連記事:
EASEUS Partition Managerを使ってみた - 130単位

*1:GW中は7380円でした

*2:36℃程度、CrystalDiskInfoで計測

2009-05-16

フォームでのEnterキー押下について調べてみた

前回こんなことを書きましたが、なんとなく引っかかりがあったので調べてみたら、いろいろ間違っていたことが判明。

フォームの仕様?として、input要素で「Enterキー」を押下すると、フォームのactionで指定した先へ post または get されてしまいます。

javascriptでフォームを送信する際に気をつけること - パンプキンスパイスラテ

自分でブクマしておいて忘れていました。恥ずかしい限り。ただ、ブクマしておいて良かったとも思います*1

これまでの認識

type="button"にしておけば、ボタンが押されてもSubmitしない
↓
テキストボックスでEnterキーを押したときもSubmitしない

この認識がそもそも間違っていました。

わかったこと

ブラウザについて
  • Safariのみで起こるわけではない
  • IEFirefoxでも起こる
  • ただしSubmitの発動条件がブラウザで少し異なる(後述)
type="button"について
  • テキストボックスEnter押下でSubmitされるのに、type="button"のinput要素の存在は関係ない
  • テキストボックスしかないフォームでも、Enter押下でSubmitされる
  • 例:
他のinput要素
テキストボックスが複数の場合

【※追記】ブクマコメントで指摘があり、Operaで実際に試してみたらテキストボックス複数の場合はSubmitされませんでした。すみませんです。(Opera@USB Version 9.64 + WinXP)

参考リンク

Enterキーで送信されてしまうのを防ぐ - [ホームページ作成]All About
http://allabout.co.jp/internet/hpcreate/closeup/CU20080902A/

*1:自分自身で間違いに気づけたので

2009-05-15

<input type="button">のSafariでの挙動

【※追記】onsubmit="return false;"でキャンセルされること以外は全て間違いなので、以下記事も参照ください。
フォームでのEnterキー押下について調べてみた - 130単位



<form name="form1" method="post" action="save">
<input type="text" name="text"/>
<br/>
<input type="button" value="登録" onclick="document.forms[0].submit()"/>
</form>

Safariではbuttonタイプのinput要素にしていても、テキストボックスでのEnterキー押下に反応してしまうようなので。

<form name="form1" method="post" action="save" onsubmit="return false;">
<input type="text" name="text"/>
<br/>
<input type="button" value="登録" onclick="document.forms[0].submit();"/>
</form>

こうしました。

2009-05-14

SafariのJavaScriptの挙動に苦戦

使い慣れたFirebugに頼れないデバッグ作業、なかなかにヘビーでした。

$.getJSON()で落ちる

jQueryのgetJSON()してからモーダル画面を表示するってな処理がありまして。IEFirefoxでは問題ないのですが、Safariではダメなのです。レスポンスが返ってきてなく、通信エラーになってしまってるようでした。最初はContent-Typeの問題かと思ったのですが、どうもそうてはない様子。てことで変数をひたすらalertしてみたら、リクエストのURLに原因があったみたいです。

$.getJSON(url,          //url : http://example.com:80/app/getjson.php
    function(response) {
        callback(response);

        $("#" + target_id).fadeIn("fast");
    });

このようにポート指定のあるURLだとダメみたいです。実際にここから「:80」を除去したらうまくいきました。「:80」を付加したのは絶対パスを生成する社内製ユーティリティ関数で、そこが根本の原因でした(修正しておきました)。

ちなみにURL相対パスでも問題ないようで、そちらのほうが適しているといえるのかもしれません。

一部の要素が動的生成できない

モーダル画面で選択した項目のデータを、元画面に描画する処理。これもうまくいってませんでした。渡すデータはモーダル画面上のhidden項目で定義。で、その項目自体もJavaScriptで動的に書き換えるというややこしいことをしてます。なんですが、Safariではそれらのhidden項目が存在してませんでした。

以下、JSONデータからhtmlを生成して、ID指定した対象の要素に流し込むところをデバッグしたもの。

alert(html_str);                    //ここでは"<input type="hidden" ... >が確かに存在する

$("#" + target_id).html(html_str);

alert($("#" + target_id).html());   //ここでなぜかなくなってる

最初は原因がさっぱりでしたが、それ以外の部分に目を向けてみたらなんとなく解決へのきざしが。

上記のhtml_strの内容がこんなのでした。

<tr>
    <td>...</td>
    <td>...</td>
    <input type="hidden" ... >
    <input type="hidden" ... >
</tr>

この中の<tr>や<td>は普通に書き込まれていたのです。そこで、文法的に正しい(と思われる)htmlになるように書き換えてみました。

<tr>
    <td>...</td>
    <td>...
    <input type="hidden" ... >
    <input type="hidden" ... >
    </td>
</tr>

こうしたら、hidden項目もしっかり生成されるようになりました。

ちなみにこの現象はSafariChromeで起きました。どちらもレンダリングエンジンはWebKitというくらいの知識しかなくてあくまで想像なのですが、JavaScripthtmlの厳密さもチェックしていたりするのでしょうか。

参考リンク
<input type="hidden">にinnerHTMLしたらダメらしい - 生涯一マークアップエンジニアだっ!!
http://d.hatena.ne.jp/wonohe/20090323/1237793651

こちらの記事で、似たような?現象について書かれています。

2009-05-13

入力エラーチェック実装についてのメモ

自社のWeb開発において入力エラーチェックをする際、基本的にはJavaScriptを用います。ただ、携帯サイトの場合は事情が異なります。

で、ちょうどそんな状況に他の開発メンバーがなったとこだったので、参考になればと半年ほど前に自分が作った検証用クラスを掘り出してきてみました。

いざ見てみると、自分自身で使用法の理解に多少の時間を要したりしました。フレームワークに沿ったかたちでオーソドックスに作ったつもりではあったのですが。原因として考えられるのは、使う側のコード記述量が多かったことと、適切な変数名でなかったこと、でしょうか。

シンプルさと柔軟性、両方重要かと思いますが、どちらも満たすのはなかなか難しいとあらためて感じた次第です。

そんなわけで、エラーチェックに関してとりとめなくメモ書き。

  • エラーチェックの仕様
    • 全体で1つのエラーのみを表示する
    • 項目ごとに1つのエラーのみを表示する
      • 先のエラーを優先する
      • 後のエラーを優先する
    • 項目ごとに全てのエラーを表示する
  • 複数の入力項目によって1つの項目となる場合(ex.郵便番号、姓と名)
    • それぞれの項目でエラーチェック
    • つなぎ合わせた項目でエラーチェック
  • Viewでのエラーの表示方法
    • 各入力項目に隣接して表示
    • すべてのエラーをまとめて表示
  • その他
    • エラーメッセージは汎用的なものを作る必要がある
    • 桁数チェックの場合、検証メソッドに渡すパラメータが増える(引数が増える)
      • まとめてチェックする際の障壁となってると思う
    • 正規表現を用いる場合、許容する値により正解が微妙に異なる
      • カタカナに「ヶ」や「ヵ」は入るのか
      • メールアドレスは厳密にやると超複雑

2009-05-11

新しいデジカメ(IXY DIGITAL 510 IS)を買ってみた

Canon デジタルカメラ IXY DIGITAL (イクシ) 510 IS シルバー IXYD510IS(SL)

Canon デジタルカメラ IXY DIGITAL (イクシ) 510 IS シルバー IXYD510IS(SL)

といっても、自分用ではありませんが。

少しだけ触ってみたので、その感想を書いてみます。

良い点

  • 広角で撮影可能
  • ボタン等が少ないシンプルな構造
  • 再生ボタンと撮影モード変更スイッチが分離されてる
  • ダイヤルを回すときの感覚がなんとなく心地よい
  • 1280x720の動画撮影が可能
  • 顔認識機能あり

その他

液晶は2.8インチとありますが、増えたのはワイドになった分で、実質2.5インチと変わりません。もともと2.5インチを使っていたなら違和感はないですが、大きい液晶のものから乗り換える場合は注意が必要かもしれません。

価格.com - IXY DIGITAL 510 IS、IXY DIGITAL 800 ISの比較
http://kakaku.com/prdsearch/prdcompare.asp?PrdKey=K0000020915.00500210974

手持ちのデジカメ*1と比べてみた結果はこんな感じでした。

リンク

楽天市場】◎15,000円以上で送料無料! ★☆SDHCカード4GB+液晶保護フィルム+デジオンオリジナルQUOカードプレゼント!★☆Canon IXY DIGITAL 510 IS シルバー +オールインワンセット(QUOカード付き):デジカメ オンライン
http://item.rakuten.co.jp/emedama/2240480035422/

こちらで購入しました。カード等が不要であれば、価格com最安値をチェックするのが良さ気です(5/11現在、送料無料で¥24,290)。

キヤノンIXY DIGITAL 510 IS|概要
http://cweb.canon.jp/camera/ixyd/510is/index.html

公式サイトです。

*1:3年前に購入

2009-05-08

カレーらーめんを食した

金曜の夜というちょっとした開放感よっていざなわれ、カレーらーめんを初体験。

f:id:deeeki:20090509004534j:image

にらもやしらーめん小盛 ¥650。

これはこれでありかと思いますが、個人的にはココイチスガキヤ別々に食べるほうがいいかなーという感じです。

kone氏 itazu氏 ありがとうございました。

麺屋ここいち (ココイチが展開するカレーラーメン専門店)
http://www.menyacocoichi.jp/ 

ブクマが地味に付いているのにおどろきました。

2009-05-07

PHPExcel xlsファイルのデータを読み込む

PHPExcelを使ってみた ループ編 - 130単位

前回はファイル出力を試しましたが、今回は逆にファイルからデータの読み込みをしてみます。CSVのような単純な構造のシートを想定したとき、その中の各セルの値を繰り返し処理で取得するにはどうするか、です。

同梱されているサンプルの「Test/28iterator.php」を参考にして書いてみました。

<?php
//ライブラリのインクルード
set_include_path(get_include_path() . PATH_SEPARATOR . './PHPExcel/Classes/');
include 'PHPExcel.php';
include 'PHPExcel/IOFactory.php';

//ファイルを読み込んでインスタンス化 (※Excel2003以前の形式)
$objReader = PHPExcel_IOFactory::createReader('Excel5');
$objPHPExcel = $objReader->load('test.xls');

//アクティブなシートを変数に格納
$objPHPExcel->setActiveSheetIndex(0);
$worksheet = $objPHPExcel->getActiveSheet();

$list = array();
//行でループ
foreach ($worksheet->getRowIterator() as $row) {
    //ヘッダが2行分あったとして、それを飛ばす処理
    if ($row->getRowIndex() < 3) {
        continue;
    }

    $data = array();
    //列でループ
    foreach ($row->getCellIterator() as $cell) {
        if (!is_null($cell)) {
            $data[] = $cell->getValue();
        }
    }
    $list[] = $data;
}

var_dump($list);

こんな感じで、各セルの値が格納された二次元配列な$listができます。

留意点

  • 列のループの最後で$cellはnullとなってforeachの中をまわる
    • そのため!is_null()の判定が必要になってくる
    • 判定をしていないとgetValue()で落ちる
  • 値のないセルをgetValue()すると、NULLが返る
  • setIterateOnlyExistingCells()
    • セルのイテレータのメソッド
    • ループの前にfalseをセットしておくと、255列すべてみにいくようになる
    • デフォルトの値はtrue

【追記】

$data[] = $cell->getValue();

ここのところ、値が取れずによくわからないオブジェクトが取れてしまう現象に出くわしました。対象のセルの値が半角英数のみのときに発生しました。

$data[] = (string) $cell->getValue();

そこで、このように書いたら値(文字列)として取ることができました。

2009-05-06

Redmineの紹介動画&聴講メモ

今日から始めるRedmine / yando‐ニコニコ動画(ββ)
http://www.nicovideo.jp/watch/sm6537344

via : 第41回PHP勉強会@関東のムービー - おぎろぐはてな

D

Redmineの利用法について発表されている動画です。

  • BTS(バグ管理システム)とはどんなものか
  • 他の代表的なソフト(主にTrac)との比較

こういった点についても盛り込まれており、全体的に非常に分かりやすい内容になっていると感じました。

以下、自分なりにまとめてみたメモです。

特徴

概要

  • 作業の粒度
    • プロジェクト
    • バージョン(特定日付までの作業)
    • チケット(日次の作業)
    • 言葉の意味は場合によっては無視してもいい
  • チケット画面で右クリックからステータスを操作できる
  • バージョン管理システムと連携することで、ソースコードの差分を確認できる
  • マスタがDB管理のため、各設定値を柔軟に変更できる

導入

  • まずは操作に慣れる
  • 各自でTODOのつもりで気軽に使ってみる
  • バージョンは設定しておく
    • バージョンがないとチケット画面だけの操作となり、チケット多数となったときに使いづらい
    • ロードマップ画面に達成度のグラフが現れ、見通しが良くなる

運用

  • 溜まったチケットは定期的なミーティング等で見直す
  • チケットの粒度を適切な大きさに合わせる
  • 期限日と経過時間を入力する
  • プロジェクトの移動は右上のプロジェクト選択メニューから
  • マイページはパーソナライズ機能があり、カスタマイズ可能

リンク

第41回PHP勉強会Redmineに関する発表をしてきた&発表資料 - yandodの日記
http://d.hatena.ne.jp/yandod/20090323/1237824158

関連記事:

Redmineを開発フェーズから使い始めてみる - 130単位

2009-05-04

4月分の読書記録

3月分の読書記録 - 130単位

↑は先月分。

月初めに読んでいた『とめはねっ! 』にはかなりハマりました。次巻が待ち遠しいです。

『開発現場の掟』は、ソフトウェア開発を成功へ導くあらゆる原則が詰まった一冊。駆け出しエンジニアな自分にとっては、大いに学ぶものがありました。

4月分読書データ

f:id:deeeki:20090504215344j:image

4月の読書メーター
読んだ本の数:11冊
読んだページ数:2157ページ

会社のアカスリで利益10倍! 本当は儲かる環境経営 (朝日新書)会社のアカスリで利益10倍! 本当は儲かる環境経営 (朝日新書)
デュース=発生抑制が最も重要
読了日:04月25日 著者:酒巻 久
開発現場の掟 (プロの鉄則) エンジニアが現場で生き残るための極意 (開発の現場セレクション)開発現場の掟 (プロの鉄則) エンジニアが現場で生き残るための極意 (開発の現場セレクション)
エンジニアに必要なのは"分類"と"発見"を行う能力。
読了日:04月22日 著者:株式会社クロノス 山本 大
べしゃり暮らし 8 (8) (ヤングジャンプコミックス)べしゃり暮らし 8 (8) (ヤングジャンプコミックス)
あまり感情移入できなかった。色紙差し出したとこが印象的。
読了日:04月21日 著者:森田 まさのり
ニッポンを繁盛させる方法 (角川oneテーマ21 A 74)ニッポンを繁盛させる方法 (角川oneテーマ21 A 74)
紳助の立ち位置と柔軟な発想はさすが。
読了日:04月20日 著者:島田 紳助,東国原 英夫
はじめてのGTD ストレスフリーの整理術はじめてのGTD ストレスフリーの整理術
収集→処理→整理→レビュー→実行
読了日:04月19日 著者:デビッド・アレン
WordPress 2.7対応「導入&カスタマイズ」実践ガイド―個人ブログも企業サイトも簡単&無料で構築できる!WordPress 2.7対応「導入&カスタマイズ」実践ガイド―個人ブログも企業サイトも簡単&無料で構築できる!
プラグインの情報が豊富
読了日:04月18日 著者:吉村 正春
急に売れ始めるにはワケがある ネットワーク理論が明らかにする口コミの法則 [ソフトバンク文庫] (SB文庫 ク 2-1)急に売れ始めるにはワケがある ネットワーク理論が明らかにする口コミの法則 [ソフトバンク文庫] (SB文庫 ク 2-1)
少数者の法則、粘りの要素、背景の力
読了日:04月14日 著者:マルコム・グラッドウェル
徹底抗戦徹底抗戦
エネルギーを感じる本。独房のつらさが印象的。
読了日:04月09日 著者:堀江貴文
とめはねっ! 4 (4) (ヤングサンデーコミックス)とめはねっ! 4 (4) (ヤングサンデーコミックス)
恋愛要素がふえてきてますます面白い。
読了日:04月03日 著者:河合 克敏
とめはねっ! 3 (3) (ヤングサンデーコミックス)とめはねっ! 3 (3) (ヤングサンデーコミックス)
合宿たのしそう。読んでて書道の知識も身につく。
読了日:04月02日 著者:河合 克敏
とめはねっ! 鈴里高校書道部 2 (2) (ヤングサンデーコミックス)とめはねっ! 鈴里高校書道部 2 (2) (ヤングサンデーコミックス)
ストーリー展開とともに少しずつ世界が広がっていく感じ。とても読みやすい。
読了日:04月01日 著者:河合 克敏

読書メーター

2009-05-03

Petitwork ファイルダウンロードメソッド改良 その2

Petitwork ファイルダウンロードメソッド改良 - 130単位

続きです。

コメント欄の指摘を反映し、第一引数$contentsだけの場合でもコンバートされないように変更してみたものです。

<?php
function downloadFile($contents, $file, $enc)
{
    header("Content-Disposition: attachment; filename=\"" . mb_convert_encoding(basename($file), $enc) . "\"");
    header('Content-Length: ' . strlen($contents));
    header('Content-Type: application/octet-stream');
    if (func_num_args() <= 2) {
        print($contents);
    }
    else {
        print(mb_convert_encoding($contents, $enc, PW_ENCODE));
    }
    return PW_TERMINATE_PROCESS;
}

が、メソッド内1行目のmb_convert_encoding(basename($file), $enc)がまずい感じです。$encのデフォルト値を指定してないためです。

さらに改良

ファイル名に関する部分について検討してみます。

第二引数$fileが空の場合

どうも、ブラウザがうまく対応してくれるみたいです。実際試してみると、実行中のphpスクリプト名がデフォルトのファイル名として表示されました。($fileのデフォルト値を'unknown'などに設定しておくのも、それはそれでありかもしれません)

第二引数$fileが日本語のファイル名の場合

これはちょっと複雑で、おそらくフレームワーク自体のコード*1でもうまく動作していないっぽいです。ブラウザの判別処理が必要になってくるためです。

ファイル名が日本語のファイルをダウンロードすると文字化けする [Memo (Mantis, PHP etc)]
http://bacons.ddo.jp/wiki/mantis/tips/download_filename

上記ページを参考に修正を加えてみたのが以下。

<?php
function downloadFile($contents, $file, $enc)
{
    $ua = $_SERVER['HTTP_USER_AGENT'];
    if (strstr($ua, 'MSIE') && !strstr($ua, 'Opera')) {
        $file = mb_convert_encoding(basename($file), 'SJIS-win', PW_ENCODE);
    }
    else {
        $file = mb_convert_encoding(basename($file), 'UTF-8', PW_ENCODE);
    }

    header('Content-Disposition: attachment; filename="' . $file . '"');
    header('Content-Length: ' . strlen($contents));
    header('Content-Type: application/octet-stream');
    if (func_num_args() <= 2) {
        print($contents);
    }
    else {
        print(mb_convert_encoding($contents, $enc, PW_ENCODE));
    }
    return PW_TERMINATE_PROCESS;
}

テストするには各ブラウザで試す必要がありますが、とりあえずIEChromeで日本語ファイル名でも問題ないことは確認できました。

*1:Ver.1.0.0

2009-05-02

Petitwork ファイルダウンロードメソッド改良

Petitwork Framework - 概要 - EOS Project (PHP関連のオープンソースプロジェクト) - 日本発!
http://eos.exbridge.jp/projects/show/petitwork

※Ver1.0.0

xbpwControllerというコントローラーの大元のスーパークラスに、ファイルをダウンロードするメソッドがあります。

<?php
function downloadFile($contents, $file, $enc=PW_CSV_ENCODE)
{
    header("Content-Disposition: attachment; filename=\"" . mb_convert_encoding(basename($file), $enc) . "\"");
    header('Content-Length: ' . strlen($contents));
    header('Content-Type: application/octet-stream');
    print(mb_convert_encoding($contents, $enc, PW_ENCODE));
    return PW_TERMINATE_PROCESS;
}

引数に$contents(ファイルの中身)を指定していたり、第三引数デフォルト値にPW_CSV_ENCODEとあったり、どうもCSVファイルの出力に特化したような印象を受けます。

で、そうではない既存の作成済みファイルをダウンロードする場合。例えばExcelファイルをfile_get_contents()してこのメソッドに渡してみると、うまくいきません。文字化けが起きてしまいます。

おそらく原因は、$contentsをmb_convert_encoding()している部分。ファイルの文字コードを指すPW_ENCODEからのコンバート処理を、必ず行うようになってしまっているのが良くないと思われます。

というわけで改良してみます。

ボツ案

<?php
function downloadFile($contents, $file, $enc=PW_CSV_ENCODE, $file_enc=PW_ENCODE)
{
    header("Content-Disposition: attachment; filename=\"" . mb_convert_encoding(basename($file), $enc) . "\"");
    header('Content-Length: ' . strlen($contents));
    header('Content-Type: application/octet-stream');
    if ($enc === $file_enc) {
        print($contents);
    }
    else {
        print(mb_convert_encoding($contents, $enc, $file_enc));
    }
    return PW_TERMINATE_PROCESS;
}

ファイルの文字コードを第四引数で指定できるようにし、コンバート前後の文字コードが同じであれば、$contentsをそのまま出力するように変えてみました。ただ、考えてみたら第三と第四引数に同じものを指定する必要があり、ちょっとわずらわしい感じがします。なのでボツ。

採用案

func_num_args()というちょうど良い関数がありました。

説明

int func_num_args ( void )

関数に渡された引数の数を取得します。

PHP: func_num_args - Manual
<?php
function downloadFile($contents, $file, $enc)
{
    header("Content-Disposition: attachment; filename=\"" . mb_convert_encoding(basename($file), $enc) . "\"");
    header('Content-Length: ' . strlen($contents));
    header('Content-Type: application/octet-stream');
    if (func_num_args() === 2) {  //← if (func_num_args() <= 2) とも書ける
        print($contents);
    }
    else {
        print(mb_convert_encoding($contents, $enc, PW_ENCODE));
    }
    return PW_TERMINATE_PROCESS;
}

引数の数が2つであれば、そのまま出力するようにしています。文字コードを変えたい場合は第三引数を指定してね、という仕様です。

【追記】コメントで指摘がありましたが、if (func_num_args() <= 2) のほうが書き方として適していると思われます。

とりあえず今回は、xbpwControllerを継承したアプリ用のスーパークラスに、改良したメソッドをオーバーライドすることで対応しました。これで実際に文字化けの問題は解消されました。

2009-05-01

PHPExcelを使ってみた ループ編

PHPExcel - OpenXML - Create Excel2007 documents in PHP - Spreadsheet engine - Home
http://phpexcel.codeplex.com/

PHPExcel形式のファイルを入出力できるライブラリです。

(※この記事に用いたバージョン…Ver.1.6.7)

きっかけなど

通常のCSVファイルの、ヘッダの部分だけを加工したいという要望がありまして。Excel出力ができる方法を探してみたところ、このライブラリに辿り着いたのでした。

$objPHPExcel->getActiveSheet()->setCellValue('A1', 'Hello');

このようにセルを指定して値をセットしていけばいいみたいです。

ただ、DBから取得した連想配列のリストを出力したい場合、ループ処理で書きたいところです。上記メソッドだとアルファベットの指定になるため、いかにも面倒。そこで「setCellValue」でgrepをかけてみたら、それっぽい便利なメソッドがありました(Worksheet.php内)。

public function setCellValueByColumnAndRow($pColumn = 0, $pRow = 0, $pValue = null)

このメソッドに列の位置と行の位置を与えてやれば良さそうです。

コード例

アーカイブに同梱されていたTests/01simple.phpを基に書いてみたサンプルコードです。

<?php
//配列作成
$member_list = array(
                array('id' => '1', 'code' => 'kashiyuka', 'name' => 'かしゆか'),
                array('id' => '2', 'code' => 'a-chan', 'name' => 'あ〜ちゃん'),
                array('id' => '3', 'code' => 'nocchi', 'name' => 'のっち')
                );

//ライブラリのインクルード
set_include_path(get_include_path() . PATH_SEPARATOR . './PHPExcel/Classes/');
include 'PHPExcel.php';
include 'PHPExcel/IOFactory.php';

//インスタンス化
$objPHPExcel = new PHPExcel();

//データのセット
$row = 1;
foreach ($member_list as $member) {
    $col = 0;
    foreach ($member as $value) {
        $objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col++, $row, $value);
    }
    $row++;
}

//シート名のセット
$objPHPExcel->getActiveSheet()->setTitle('Perfume');

//Excel2003以前の形式でファイル出力
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('./Perfume.xls');

出力結果

f:id:deeeki:20090502035402j:image

わかったこと

  • setCellValueByColumnAndRow()の第一引数($pColumn:列)は0からはじまる
  • setCellValueByColumnAndRow()の第二引数($pRow:行)は1からはじまる
  • SJISで記述したphpファイルだと日本語が文字化けする*1
  • UTF-8で記述したphpファイルだと文字化けしない
  • 1ファイル1シートの場合は、$objPHPExcel->setActiveSheetIndex(0)をする必要はない

枠線なども設定できたりとかなり高機能なようなので、いろいろ試してみたいと思います。

参考リンク

SE奮闘記: PHPからエクセルを操作するPHP-Excelを使ってみた
http://se-suganuma.blogspot.com/2008/11/phpphp-excel.htmlハウツー】PHPExcelを使ってPHPExcelファイルを出力する (1) PHPExcelとは | エンタープライズ | マイコミジャーナル
http://journal.mycom.co.jp/articles/2009/03/06/phpexcel/index.html

*1:「ファイルが壊れている」的なエラーが出る