2011年12月25日日曜日

2011年を振り返って

2011年も残りあとわずか。このブログに投稿した内容を振り返ってみて、今年気になったキーワードのベスト5と、それに関連する投稿を挙げてみる。


5. Android

今年は予想されていたとおり、スマホ元年になった。そしてアメリカの状況を追うように、日本でもAndroidがiPhoneを上回りシェアを伸ばしている。
”Yahoo!”や”IE”を使っていた人たちがスマホを使うようになってきた、これは個人向けのサービスだけでなく企業向けのシステムをも飲み込んでいくのだろう。
タブレットも含めたスマホ以外へのAndroidの展開については、まだなんとも言えないけれど。(むしろこちらが来たら革命的に状況が変わるかも。)



4. Amazon EC2

今年は満を持してAWSのデータセンターが日本に上陸した。もともとシンガポールでもそんなに問題はなかった(アメリカは体感できるくらい遅かった)けど、やはり東京にあるに越したことはない。
その他にもAWSは立て続けに機能が追加されている。個人的にはAmazon Linux AMIの登場が良かった。CentOSよりyumでインストールできるパッケージのバージョンが新しいし。
以前は「突然落ちる!」という話が蔓延して大丈夫かなと思ってたけど、実際に使ってみて大丈夫な部分もそうでない部分も分かってきた。
来年は色んな環境をEC2へ移行していこうかなと夢想中。



3. jQuery UI

これは今年登場したわけではないけど、個人的に今年から本格的に使い始めたのでランクイン。
いわゆる”デザイン”ができない自分にとって、jQuery UIはまさに福音だった。classを指定するだけで簡単にそれらしいサイトができあがるし、その上バラエティに富んだテーマを選ぶことができる。企業向けのWebアプリならこれで充分でしょう。
はやくGridがリリースされないかな。



2. jQuery Mobile

そしてjQuery UIの弟分ながら既に兄貴とは比べものにならないくらいメジャーになり、(自分の中では)デファクトスタンダードにまでなっているjQeury Mobile。
jQuery UIのCSS Frameworkで実装されたclassさえ指定しておけばよいというやり方をさらに進化させ、data-*属性により動きまで指定するというやり方は黒魔術的だが、覚えてしまえば手軽に使うには便利。Ajax(実際にはHijax)による遷移も含めて、もうMobileだけじゃなくてPC向けにも取り入れればいいんじゃないかと思う。
とここまで書いて気づいたが、このブログではまともにjQuery Mobileについて書いたことがなかった。マニュアルを見れば他に調べる必要もないからか。



1. Titanium Mobile

1位に輝いたのはTitanium。チタニウムではなくタイタニウム。日本ではチタンに引っ張られてチタニウムと読みたくなるが、それでもどうしてもタイタニウム。
まだ発展途上の感は強いが、JavaScriptで、AndroidとiPhoneの両方のアプリが作れるというのは便利。
フォーラム等で回答をしたり見やすいAPI Documentも作ってくれたmasuidriveさんの活躍に負うところも大きいと思う。参考情報(日本語ならなお良し)の探しやすさは往々にしてソフトウェアがブレイクするかどうかにおいて、ソフトウェアの出来よりも影響が大きかったりする。来年も期待してます。



こうして見ると、やっぱりスマホの年だったと実感する。あとはJavaScriptか。
でも、ここでは出てこなかったけど、なんだかんだで個人的には今年もPHPが中心だったなあ。でもPHPは身近過ぎて、「今年」気になったキーワードという感覚にはならないんだよなあ。

2011年11月29日火曜日

Google Calendar Header and Navigation Switcherを 最新のGoogleカレンダーに対応

FirefoxのGreasemonkeyで、Googleカレンダーのサイドバーと上部コントロールを非表示にしてカレンダー部分を広くできる便利な「Google Calendar Header and Navigation Switcher」というのがあるが、これがGoogle+風の新しいGoogleカレンダーのデザインだと機能しない。

Userscripts.orgにこれの解決策が書いてあった。

Broken with new look - Userscripts.org
Fixed it.    Change line 88 to: var head = new DisplaySwitcher("head", "#vr-proto-header,#topBar,#cornerBookmarks,#gbar,#gbarl,#guser,#ft+.s,.gbh", (#vr-proto-header is the new header) and add after line 45 (or pretty much anywhere inside DisplaySwitcher.prototype.toggle declaration) the following line: if (this.id=="navi") { document.getElementById("mainbody").style.marginLeft = hide ? "0px" : "210px"; } (to fix the white space that the hidden sidebar leaves)

要約すると、
  • 88行目で指定する隠す対象の指定(後述)を変更する
  • 45行目あたりに、下記のif文を追加する(サイドバーを非表示にした時に空白のスペースが残るのを防ぐため)
    if (this.id=="navi") { document.getElementById("mainbody").style.marginLeft = hide ? "0px" : "210px"; }

88行目で指定する、隠す要素の指定についてはいろんな意見が出てる。
  • #vr-proto-header,#topBar,#cornerBookmarks,#gbar,#gbarl,#guser,#ft+.s,.gbh
  • #onegoogbar,#vr-proto-header,#vr-proto-nav,#topBar,#cornerBookmarks,#gbar,#gbarl,#guser,#ft+.s,.gbh
  • #onegoogbar,#vr-proto-header,#vr-nav,#vr-header,#vr-proto-nav,#topBar,#cornerBookmarks,#gbar,#gbarl,#guser,#ft+.s,.gbh

3番目のahbiさんのやつが一番指定要素が多いので一番シンプルになる。

ただ、自分の場合はアカウントの切り替えができるOne Google Barは残したいので、88行目を下記のようにした。
  var head = new DisplaySwitcher("head", "#vr-proto-header,#vr-header,#vr-proto-nav,#topBar,#cornerBookmarks,#gbar,#gbarl,#guser,#ft+.s,.gbh",
refleshCal);

うん、快適。

2011年11月17日木曜日

Google App Engineでデータを一括で削除する方法

Google App EngineがPreview版を卒業して正式版になったのに伴ない、2011/11/7から価格体系が変わり無料で使えるQuotaが減った。
特に、データ書き込み(Datastore Write Operations)がすぐに制限に達してしまう。

そんなにデータ登録してないけどな?と思って調べてみると、Datastore Write Operationsには登録・更新だけでなく削除も含まれるようだ。
過去データの削除をcronで動かしていたのが全てカウントされている。
そこで、過去データ削除のcronをコメントアウトすると、Datastore Write Operationsが大幅に減った。

残る問題は過去データの削除をどうするか?
調べてみると、Google App Engineの管理画面からDatastore Adminという機能を使えば削除できるらしい。

さっそくDatastore Adminを使ってみる。デフォルトでは無効になっているので、Enabledする。
すると...真っ白な画面が表示された。
調べてみても有効な情報がない。
・
・
・
1日経って気付いた。Googleのマルチアカウントが(例によって)悪さをしている?
いったんSign Outして再ログインしたら無事に表示された。

さっそく削除してみる。Entity Kind(テーブル)ごとの削除になる。(条件を指定して削除できれば完璧なのだが。)
実行すると、Datastore Write Operationsが制限に達して真っ赤になってしまった。Datastore Adminから削除しても、Quotaに含まれるらしい。
仕方ないのでQuotaがリセットされるのを待つ。
・
・
・
リセットされてからしばらく後で見てみると、無事にEntity Kindの削除が終わっていた。Datastore Write OperationsのQuotaの大部分を使ってしまっていたが、明日またリセットされればそれ以降は問題ない。
しばらくこの手でやりくりしてみるか。

2011年11月16日水曜日

Windows 7で Poderosaの接続履歴が保存されない問題

Windows7でPoderosaを使い始めたが、なぜか接続の履歴が保存されないので、毎回ユーザー名や鍵ファイルを指定しなければならないのが面倒。
そして試してみたら接続の履歴だけでなく、あらゆる設定が保存されていないことが判明。

対策は、Poderosaを起動する時に管理者として実行すること。

管理者として実行したら、接続の履歴も設定も保存される。
毎回管理者として実行するのは面倒なので、新しい接続設定を残したい場合や、その他の設定を変えたい場合のみやれば良いと思う。

あるいは、インストールする時にProgram Filesじゃないとこに入れればよかったのかもね。

2011年11月14日月曜日

PDOでテーブルの列名を全て取得する方法

テーブルの列名を取得するには、MySQLならDESCRIBEで簡単にできるが、PostgreSQLだとpg_attributeカタログから取得しないといけないらしい。

でもPDOを使えばMySQLでもPostgreSQLでも取得できた。
$pdo = new PDO("$driver:dbname=$db", $user, $password);
$pdoStatement = $pdo->query("SELECT * FROM $table_name LIMIT 0");

$columns = array();

for ($i = 0; $i < $pdoStatement->columnCount(); $i++) {
    $meta = $pdoStatement->getColumnMeta($i);
    $columns[] = $meta['name'];
}

var_dump($columns);

もしテーブルに1行以上データがあることが保証されているなら普通に1行SELECTして連想配列の列名見れば済む話だが、データなしでも動くようにしたらこうなった。


ただし、PDOStatement->getColumnMeta()のマニュアルを見ると、
この関数は、 実験的 なものです。この関数の動作・ 名前・その他ドキュメントに書かれている事項は、予告なく、将来的な PHP のリリースにおいて変更される可能性があります。 この関数は自己責任で使用してください。
PDO ドライバの全てが PDOStatement::getColumnMeta(). をサポートしているわけではありません。
と書いてあり、PHPやDBのバージョンによっては上手く動かないかもしれないが、とりあえず手元の環境では動いた。


これでPHPでO/R Mapperを作りたい人も安心だ。

2011年11月7日月曜日

Titanium Studioで作ったアプリを Android Marketに登録する手順


Titanium Stuidoで作ったAndroidアプリをMarketに登録できる証明書付きapkファイルにする手順は下記の通り。

  1. JDKのbinフォルダ内にあるkeytool.exeを使って、keystoreを作成する
    (作成時に入力するAliasとパスワードを覚えておくこと。)
    参考:keytoolコマンドで公開するandroidアプリに署名するための証明書(鍵)を生成する
  2. Titanium StudioのProject Explorerで該当のプロジェクトを右クリックする
    (Procejt ExploerはTitanium Studioの左側に表示されているView。表示されていない場合はメニューの「Window」→「Show View」から表示できる。)
  3. 表示されたコンテキストメニューから「Deploy」→「Distribute - Android」を選択する
  4. テキストボックスに必要事項を入力してFinish
    ※Distribution Location(apkファイルの作成場所)のパスに半角スペースを含むとエラーになるので注意。
  5. 慌てずにしばらく待つ(少し時間がかかる)
  6. 4で指定したフォルダにapkファイルが作られる

参考:295 デプロイと配布 - Training Lab Tutorials - Appcelerator Wiki


Android Marketに登録するには、最初にGoogle Checkoutで25ドル支払う必要がある。

また、Marketに登録する際にはスクリーンショット等の画像をアップロードできる。
参考:

2011年11月6日日曜日

Titanium Mobileで 特定のURLをブラウザで開くだけの Androidアプリを作成する方法


app.jsを下記の2行にする。(URLは起動したいURLにする。)
Ti.Platform.openURL("http://www.google.co.jp/"); // Googleの場合
Ti.Android.currentActivity.finish(); // ブラウザを起動したらアプリ本体は終了させる

Resources/androidにある下記の画像ファイルを適切な画像ファイルに置き換える。
  • appicon.png (アプリの起動アイコン)
  • default.png (起動時に表示されるスプラッシュ画像)

2011年11月2日水曜日

Seasar2入門の参考サイトとプロダクト選択のメモ

久しぶりにJava村に帰ってきた浦島さんの玉手箱メモ。


まずは概要を把握。



一口にSeasar2と言ってもたくさんプロダクトがあるので、Webアプリを作る場合にどのプロダクトを使うべきか調査。

  • MVCは、S2Struts or SAStruts or Teedaのどれがいい?
    • S2StrutsかSAStrutsだとどっち?
    • SAStrutsとTeedaでは?
      • Teeda
        • TeedaはJSFの実装
        • Teeda Extensionを使えばHTMLをテンプレートにできる
      • 「Seasarの問題点など」にそろそろ一言いっておくか - ひがやすを blog
        ただ、無責任に何でも自由というのは良くないので、SAStrutsとS2JDBCの組み合わせが、もっとも無難だというメッセージを出しているわけです。
      • SAStrutsとS2JDBCを作ったわけ - ひがやすを blog
        TeedaとS2Daoは、基本的に規約ベースのフレームワークです。規約を知っていれば、本当にさくさく開発できます。でも、規約ベースなので、規約を知らないと、何にもできなくなっちゃう。この辺が、大規模開発には向かないところ。
        SAStrutsとS2JDBCは、大規模案件にも耐えられるように最初から設計されています。
      • 感想:チームでの開発や今後のメンテを考えると、参考情報も経験者も多いStrutsの名前を冠するSAStrutsに比べてTeedaは学習コストがかかりそう
    • 結論:SAStrutsが無難
  • S2JDBC or S2Daoのどっちを使う?
    • HibernateとS2DaoとS2JDBCの考え方 - ひがやすを blogより引用
      • S2Daoについて
        S2DaoはSQLを中心に考えます。とはいえ、すべてのSQLを開発者が書くのは効率が悪いので、挿入、更新、削除は、S2DaoがSQLを自動生成しますが、検索は、開発者にSQLを書いてもらいます。
        デメリットは、SQLを書くのが面倒なことです。また、検索の結果セットごとにDTOを作らなければいけないので、DTOが増える傾向があります。
        Webのフレームワークとの組みあわせでいくと、Teeda Extensionは、S2Dao(DTO)と相性が良いように設計されているので、Teedaを使う場合は、S2Daoが良いと思います。
      • S2JDBCについて
        S2JDBCは、エンティティ(Java)とテーブル(データベース)は、同一のモデルだとみなしています。また、複雑なSQL以外は、すべて自動生成します。
        デメリットは、エンティティの設計が、テーブルに引きずられ、完全にドメインをあらわしたものにならないこと。
    • 感想
      • S2DaoはINSERT/UPDATE/DELETEのSQL自動生成と、手作りしたSQLの実行をしてくれるみたい
      • S2JDBCはDAOではなくApache CommonsのDbUtilsのようなSQLビルダー?
    • 結論:TeedaでないならS2JDBCで



久しぶりにJavaの世界に帰ってきたら、昔使ってたStruts1.3(1.x系は1.3で止まってるとは意外)のラッパーであるSAStrutsと、同じく昔使ってたJakarta Commons(現在は昇格してApache Commons)のDbUtilsに似たS2JDBCが最前線だなんて、奇遇と言うか、あるいは必然なのかな。

2011年10月17日月曜日

Windows XPに Titanium Studioをインストール


開発構築にリトライしたメモ。
インストールからKitchen Sinkを動かすまで。
Titanium StudioもAndroid SDKも重いので、なるべくパワーのあるPCでやった方がよい。


まずはインストール
  • JDK
    • Java SE Downloadsから、Java SE 6の最新版をダウンロードしてインストール
      • 7だとダメらしい
      • インストール時には、pathにスペースを含まないようにする?
    • Windowsの環境変数「PATH」にbinフォルダのpathを追加
      • 環境変数「JAVA_HOME」を登録し、PATHには"%JAVA_HOME%\bin"の形で登録しておくと、JDKのバージョンが変わった時の変更が楽になるし分かりやすい
  • Android SDK
    • Android SDK | Android Developersから、最新版をダウンロードしてインストール
      • インストール時には、pathにスペースを含まないようにする
    • SDK Managerを起動(通常は自動で立ち上がるらしい)
    • 必要なパッケージをインストール
      • SDK Platform Android 2.1は必須
        • これが無いとTitanium StudioがAndroid SDKを認識しないらしい
      • Google APIs by Google Incも必要
        • これが無いとエミュレータがうまく動かない
      • かなり時間がかかる
      • 迷うなら全部入れておけば無難(ただし時間はかかる)
    • platform-toolsフォルダ内のadb.exeを、toolsフォルダにコピー
      • 以前はtoolsフォルダにあり、Titanium Studioがそれに合わせた動きをするため
    • Windowsの環境変数「PATH」にplatform-toolsフォルダとtoolsフォルダのpathを追加
      • JAVA_HOMEと同様に、ANDROID_SDKとか環境変数として登録すると良いでしょう
  • Titanium Studio


動作確認
  • Titanium Studioを起動
    • Work Spaceの場所を訊かれる。スペースを含まないpathを指定する(?)
    • Titanium(appcelerator)のアカウントを訊かれるので入力
    • Firewallが警告を出してきたら許可
    • Gitが無いと言ってきたら、「Use PortableGit」をクリック?
  • Mobileのプロジェクトを作成
  • 実行
    • 実行前にadb.exeが実行されていたら、タスクマネージャからプロセスを終了(?)
    • プロジェクトをRun
    • Firewallが警告を出してきたら許可
  • 「I am Window 1」が表示されればOK!
    • 「[TRACE] adb devices returned 0 devices/emulators」が続いてタイムアウトしたら、タスクマネージャから「adb.exe」のプロセスを終了させてから再実行する


KitchenSinkを動かす


さあ始めよう


参考

2011年10月6日木曜日

スマートフォンのGeolocation API 調査メモ


AndroidやiPhone(そして実はPCでも)のブラウザで位置情報を取得するGeolocation APIについての調査メモ。



Androidではgoogle.gearsを使うという説明が多いけど、手元のAndroid(2.3.3)の標準ブラウザではiPhoneと同様にnavigator.geolocationでGeolocation APIが使えた。
(逆にgoogle.gearsを使おうとするとエラーになった。)



(2011/10/21 追記)

2011年10月3日月曜日

MySQLの dumpと restore


文字コード設定がされていないサーバからダンプする時に文字化けすることの対策のメモ。


dump
mysqldump -u user_name -p --compact --default-character-set=binary db_name > dump.sql

restore
DB(Schema)を作ってから、
sed 's/latin1/utf8/g' dump.sql > dump_utf8.sql
mysql -u user_name -p db_name < dump_utf8.sql

バイナリで出して文字コードの記述を置換してから取り込む。


参考

2011年9月30日金曜日

preg_match()の$は末尾に改行があってもマッチする


$は最後に改行があってもマッチする。(ただし、マッチした結果には改行は含まれない。)
preg_match('/^aaa$/', "aaa\n", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
"aaa"


$の代わりに"\z"(バックスラッシュ+小文字のz)にすれば、改行があるとマッチしない。
preg_match('/^aaa\z/', "aaa\n", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
""


Zが大文字だと$と同様に改行があってもマッチするので注意。
preg_match('/^aaa\Z/', "aaa\n", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
"aaa"


$は改行の後ろに何かあればマッチしない。
preg_match('/^aaa$/', "aaa\n ", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
""


例えそれが改行でも。
preg_match('/^aaa$/', "aaa\n\n", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
""


マッチした結果に改行まで含ませるとこうなる。
preg_match('/^aaa\n\z/', "aaa\n", $match);
echo '<pre>"', $match[0], '"</pre>';
↓
"aaa
"


参考

2011年9月29日木曜日

PHPExcelで PDFが文字化けする問題の解決方法


PHPExcelではExcelの他にPDFも出力できる。
$writer = PHPExcel_IOFactory::createWriter($xls, "PDF");
$writer->save($path);
しかし、これだとPDFで日本語を出力しようとすると文字化けする。

文字化けを回避するには、フォントをセットする必要がある。
$writer = PHPExcel_IOFactory::createWriter($xls, "PDF");
$writer->SetFont('arialunicid0-japanese');
$writer->save($path);
これができるようになったのはわりと最近のようだ。(参考:PHPExcel - phpexcel - View Issue #11919: Can't set font on writing PDF)

ただし環境によってはこれでも見られないらしい。(参考:PHPExcel の PDF出力で日本語文字化け2 携帯ビューア - PC・通信メモ)


また、PHPExcelで作るPDFはExcelとして出力した場合と比べていろいろ違う(罫線とか数値フォーマットとか横幅とか)ので、綺麗に出すにはPDF用にいろいろ工夫しないといけないようだ。


参考

2011年9月28日水曜日

JavaScriptフレームワーク/ライブラリの CDNいろいろ


prototype.jsとかは、もういいや。


プロダクト別CDN

(2013/3/19 追記)
(追記終わり)


CDNごとの特徴
  • Google Libraries API
    • HTTPS可
    • マイナーバージョン(もしくはリビジョン番号)を省略すると、指定したメジャーバージョン(もしくはマイナーバージョン)内で最新のファイルをロードする
    • 他にもprototype.jsやDojo、Ext core等メジャーなJavaScriptフレームワークがいくつかある
  • Microsoft Ajax Content Delivery Network
    • HTTPS可
    • 他にもメジャーなjQuery Pluginがいくつかある
  • jQuery CDN (jQuery CDN、jQuery CDN (jQeury Mobile))
    • HTTPS不可
  • YUI (YUI Configurator、YUI 2: Dependency Configurator)
    • HTTPS不可
    • 複数のファイルを結合して1ファイルとしてロードできる
  • cdnjs.com
    • HTTPS可
    • 最新バージョンの適用タイミングは遅いかも?


結論


おまけ
以下のCDNは更新されていないようだ。


関連

2011年9月15日木曜日

画面をキャプチャするブラウザのプラグインいろいろ

ブラウザで表示している画面のスクリーンショットを撮るプラグインのメモ。



いずれも、Flashの領域もキャプチャできたし、画面全体をスクロールしてキャプチャする機能もあった。

画像形式は「キャプチャー イット!ツールバー」はJPEG、それ以外はJPEGかPNGから選べる。

Google Chromeの2つは、キャプチャ直後に新しいタブが開き、そこでキャプチャした画像の編集ができる。そのまま1クリックで印刷もできるので、画面イメージを印刷する用途には便利。
でも逆に、ファイルとしてどんどん溜めていきたい場合には毎回タブで開くより「キャプチャー イット!ツールバー」のように黙々とフォルダに画像ファイルを保存して行ってくれた方が便利かも。(「Screen Capture」の方は、設定でそうすることもできる。)

Chromeの「Screen Capture」以外は日本語化されていた。


ブラウザのプラグインではないけど、JTrimは画面キャプチャから画像の加工までできて便利。

2011年9月9日金曜日

IEのバージョンと互換モードによる @_jscript_versionの値の違い

IEのJavaScript(正確にはJScript)でのみ使える、「条件付きコンパイル変数」の1つであるJScriptのバージョンを表す@_jscript_versionについて、IEの各バージョン、各モードでどんな値になるか調べたのでメモ。


  • IE10 PP2
    • 通常モード:10
    • 互換モード:10
      • IE5~10の全ての"Force IExx Document Mode"で試したが、全て10だった
  • IE9
    • 通常モード:9
    • 互換モード:9
      • 開発者ツールでブラウザーモード、ドキュメントモードを変えても、全て9だった
  • IE8
    • 通常モード:5.8
    • 互換モード:5.8
      • 開発者ツールでブラウザーモード、ドキュメントモードを変えても、全て5.8だった
  • IE7
    • 5.7らしい(未検証)
  • IE6
    • WinXP SP3以降:5.7
    • WinXP SP2以前:5.6らしい(未検証)


@_jscript_versionは互換モードかどうかに関係なく、JScriptのバージョンになる。


参考

2011年9月5日月曜日

Google Maps APIを使うための参考サイトまとめ


だいぶ前にもまとめた(もう一歩踏み込んでGoogle Maps APIを使いこなすための12の参考サイト)が、古くなってきたのでもう一度まとめてみる。



2011年8月23日火曜日

各ブラウザのconsole.log()実装状況


Firefox以外のモダンブラウザは、標準で装備していた。

ブラウザ調査した
バージョン
ログの表示方法その他
IE8ツール
↓
開発者ツール
↓
「スクリプト」タブ
IE8以降で搭載。
String型にCASTされて出力される。
(Objectの中身は見られない。)
Firefox6.0アドオンのFirebugを使う


Chrome11.0ツール
↓
JavaScript コンソール
↓
「Scripts」タブ

Safari5.1ページのメニューボタン
↓
開発
↓
JavaScriptのデバッグを開始
↓
「コンソール」タブ
Windows版で確認。
Opera11.50Operaボタン
↓
ページ
↓
開発者用ツール
↓
Opera Dragonfly
バージョン11から搭載。
ObjectやArrayの中身は見られない。
CSS等のエラーとごっちゃに出るので見辛い...


所感
  • SafariやOperaはコンソールの表示方法が分かり辛い。
  • IEやOperaはObjectの中身を見られない(Operaは配列の中身も見られない)ので使い辛い。
  • Operaは他のエラー(CSS等)と一緒に出力されるので見辛い。


参考

2011年8月5日金曜日

YUI3の Calendarウィジェット



YUI2にはあるけどYUI3には無いCalendarが、YUI3の次期バージョンである3.4でリリースされるようだ。


Calendar - YUI Libraryを参考に使ってみたら、簡単に使えた。
上記画像のように、YUI2のカレンダーよりちょっとかっこいい?
ただし、ここに書いてあってもまだ未実装の機能もあるようだ。
さらに、イベントハンドラ等、詳細についてはここには書いてない。詳細はAPI docsを見ろと書いてあるが、そのリンク先は現時点ではNot Found。


また、formへの日付入力で活躍するDatepicker機能はさらに次バージョンの3.5で実装予定のようだ。
The calendar is currently not enabled with popup functionality: it will be released as a calendar plugin in 3.5


2011年7月19日火曜日

C言語、 D言語だけじゃない。 アルファベット1文字のX言語たち


C言語のようにアルファベット1文字のプログラミング言語。
意外にいろいろあった。



P言語は俗称だしZ言語はプログラミング言語じゃないから除いた。

2011年7月14日木曜日

Excelで行をグループ化してカウントする方法

Excelで、下記のように各行にいろんな値が入っているデータがあって、これをグルーピングした場合の各グループの個数を調べる方法、のメモ。

A
A
B
C
C
C
C
D
D
D


調べたい列がA列の場合、その右の列等に下記数式を入れる。(行数に応じて「A$1000」のところは増やす。)
=COUNTIF(A$1:A$1000,A1)

結果はこうなる。

A2
A2
B1
C4
C4
C4
C4
D3
D3
D3


多い順、少ない順にソートしたい場合は2番目の列でソートする。


参考:Excel(エクセル)基本講座:カウント(COUNT)の関数

2011年6月30日木曜日

Windowsで git 調査メモ

とりあえずローカルのみで使ってみたい。


インストール
  1. msysgitをインストール
  2. tortoisegitをインストール
  3. ユーザー名とメールアドレスをセット(settings → Git → Config)


要調査事項


日本語のファイル名が扱えないと、ドキュメントの管理に使えない...
Bazaarを使うか。

2011年6月21日火曜日

PostgreSQLで 最後にVACUUM / ANALYZEした日時を取得する SQL

PostgreSQLで、最後にVACUUM/ANALYZEした日時(AUTOと手動のそれぞれについて)を確認するSQL。

SELECT relname, n_live_tup, n_dead_tup, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze
FROM pg_stat_all_tables
WHERE schemaname = 'public' -- schemaname or relnameで絞りこむと見やすい
ORDER BY relname

参考:

2011年6月13日月曜日

JavaScriptの HTMLエスケープ関数を 140字以内で書いてみる

JavaScriptで動的にWebページの内容を書き換える場合に、文字列のHTMLエスケープをしたい時がある。具体的には、「& " ' < >」の5つを変換したい。
PHPならhtmlSpecialChars()、Railsならh()でよいが、JavaScriptにはHTMLエスケープ用の関数が用意されていないので自分で書く必要がある。

せっかくなので、Twitterでつぶやける文字数以内で書くことを目指してみる。

で、こうなった。
function h(s){return s.replace(/[&"'<>]/g,function(m){return"&"+["amp","quot","#039","lt","gt"]["&\"'<>".indexOf(m)]+";"})}
123文字。
意外と余裕だ。



クォーテーションのエスケープをしないでいいなら(HTML要素の属性値のHTMLエスケープに使わないなら)、こんな方法もある。
function h(s,p){p=document.createElement("p");p.innerText=p.textContent=s;return p.innerHTML}
93文字。
(第2引数のpは変数宣言を避けて文字数を減らすためのダミーの引数なので、実際に使うときには第1引数のみ渡せばよい。)
innerTextはFirefoxでは使えないしtextContentはIEでは使えないので、両方に対応させるために両方書いている。


でも、innerTextには細かい問題ある(参考:DOM の textContent と innerText について - フリーフォーム フリークアウト)ようなので、環境依存を避けて丁寧にやりたいなら、少し長くなるけどdocument.createTextNode()を使った方が無難かも?
function h(s,d,p){d=document;p=d.createElement("p");p.appendChild(d.createTextNode(s));return p.innerHTML}
106文字。


でもでも、それなら最初の正規表現を使ったやり方のほうが短い。
function h(s){return s.replace(/[&<>]/g,function(m){return{"&":"&amp;","<":"&lt;",">":"&gt;"}[m]})}
99文字。



(2011/06/22 追記)
はてなブックマークやTwitterで教えてもらったので追記。


hatestさん
引数sがStringであることをチェックしてないから、{replace:function(){return "<script>"}}とかいうオブジェクト渡されたら終わるぞ
そうですね。用途によってはパラメータのチェックとか型変換とかすべきかも。


ひなしさん
function h(s){return s.replace(/[&<>"']/g,function(m){return "&#"+m.charCodeAt(0)+';'})} の88文字でよくない?
なるほど。こっちの方がスマートかつ短い。
(ところでTopsyの検索にひっかからないのは何故?)


uuuさん
最近はreturn s.replace(/["'&><]/g, function(m){return "&#"+m .charCodeAt(0).toString(16) + ";"})みたいのがマイブーム
こちらもcharCodeAt()。16進数なので"&#"のところは"&#x"の書き間違いと思われる。16進数にするメリットとかあるのかな?


ということでcharCodeAt()を使って書き直してみる。もうエスケープ対象文字の判別とか無しで、全てユニコード化してしまおう。
function h(s,i,t,r){for(i=t="";r=s.charCodeAt(i);i++)t+="&#"+r+";";return t}
76文字!

charCodeAt()を使っているのでJavaScript1.2未対応ブラウザ(IE3とか)では動かないだろう。あと文字コードによっては問題ある?
Null文字が入っていると変換の途中で終わってしまうが、NULL文字は非SGML文字らしいので良しとしよう。
インクリメントに使う「i」を空文字("")で初期化するのは気持ちが悪いがとりあえず動くみたい。JavaScriptの仕様としてはどうなんだろう。微妙なところか?(参考:JavaScript講座 : インクリメント/1加算)
(追記終わり)


関連:floatingdays: JavaScriptで HTMLエスケープ

2011年5月31日火曜日

Firefoxのアドオンから Java Consoleを削除する方法

Javaをインストールすると勝手にインストールされるFirefoxアドオンの「Java Console」。
要らないので削除したいのだが、通常のアドオンと違って「削除」ボタンが表示されないので普通には削除できない。

そこで、「Java コントロールパネル」で下図のように「ブラウザのデフォルトの Java」の「Mozilla ファミリ」のチェックを外したら、アドオン一覧に表示されなくなった。



同じような状況のアドオンとして「Java Quick Starter」があるが、これも同様に上記の図の「その他」のところにある「Java Quick Starter」のチェックを外せばアドオン一覧に表示されなくなる。

2011年5月25日水曜日

Twitterで情報収集するための便利ツールまとめ

Twitterで情報を集める上で便利なツールを集めてみた。

  • Advanced Twitter Search
    • Twitter自身によるTwitter Searchの詳細版
    • 要はTwitter Search Operatorsを使いやすいようにフォームにしたということか
    • キーワードはもちろん、発言者や言及先のユーザー、ユーザーの場所などいろいろ検索オプションがある
      • ユーザーの場所については、実は主にユーザーのプロフィールに書かれている場所からジオコーディングして取得してるだけなので結構間違ってたりする
    • OR検索は小文字の「or」ではなく大文字の「OR」なので注意
    • URLで検索すると、短縮URLは短縮前のURLで検索してくれる
    • 検索結果をRSSフィードで購読できる
    • Twitter本家からリンクしていないのはなぜ?
  • Google リアルタイム検索
    • Twitter等へのPOSTをリアルタイムで検索できる
    • Googleだけあって検索能力はTwitter Searchよりも強力
      • 例えば語句の揺れ(ひらがな⇔カタカナ、日本語⇔英語、タイプミス、等)に強いとか
    • 検索対象にFacebook等が加わったらしいけど、いまだに日本ではTwitterが独占状態
  • なんでも速報 Tweets on the Map
    • Googleリアルタイム検索の地図版
    • お天気専門の天気速報も
  • ホームページのつぶやき見える君(仮)
    • ブラウザで表示中のページのURLを含むTweetを表示してくれるChrome拡張 & Firefox用Greasemonkey
    • 短縮URLでも拾ってくれる
  • Twitter Streaming API
    • Twitter等へのPOSTをリアルタイムで取得できるAPI
      • 通常は取得できる内容に制限がある
      • 制限なしで全Tweetを取得できるStreaming APIの「Firehose」の提供先にdocomoが加わったのは記憶に新しい
    • APIなのでプログラムができないと使えない
    • キーワードを指定しての取得は、日本語には対応していない
    • 解説(英語):Streaming API Documentation | dev.twitter.com
    • PHPでTwitter Streaming APIを使って特定のキーワードを追跡する例:P2_Service_Twitter

2011年5月9日月曜日

Webベースのテキストエディタ ecoderのカスタマイズメモ

WebブラウザでPHP等を編集できるオンラインテキストエディタのecoderのセットアップ時の変更箇所のメモ。


前提知識
  • $_SESSION['live'] == 0 になるのはサーバがlocalhostの場合


変更箇所
  • /code.php
    • 一通り関係しそうな設定を変更する
  • /code/base/server.php
    • $_SESSION['google']を0にすると初期表示ページのAdSenseが非表示になる
  • /code/tree/type.php
    • 表示対象の拡張子を追加する場合は、if文の該当箇所に追加する
  • その他
    • .htaccessを使わない場合は、Noticeを抑制するために index.php の先頭あたりに下記を入れる?
      error_reporting(E_ALL ^ E_NOTICE);
    • ただしphp.iniでE_STRICTを有効にしている場合はStrictエラーが出てしまうことがある。
      PHPのパース時に出るので、PHP内でerror_reportingを変更してもこれには効かない。(参考:PHP: error_reporting - Manual)
(2012/04/18 追記)
  • /code/logs/analytics.php
    • Google Analyticsの読み込みをコメントアウトする
ちなみに上記はversion 0.4.9の話。今の最新は0.4.10みたい。
(追記 終わり)

2011年5月2日月曜日

IEの互換表示は印刷プレビューにも適用される

IEでアドレス(URL)欄と更新ボタンの間にある互換表示ボタンをクリックすると、下位バージョンのIEでの表示モードになる。(IE8の場合、IE7での表示になる。ただし厳密に言うと同じではないらしい。ほぼ同じだが。)

で、互換表示にした時に印刷プレビューについても互換表示が適用されるかどうか調べた。


調査に使ったHTML
IE8モード(以上)の場合「IE8」、IE7モード(以下)の場合「IE7」と表示される。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Which are you?</title>
<!--[if lte IE 7.0]><style> #ie8 { display: none} </style><![endif]-->
<!--[if gte IE 8.0]><style> #ie7 { display: none} </style><![endif]-->

</head>
<body>
<div id="ie7">IE7</div>
<div id="ie8">IE8</div>

</body>
</html>

結果
画面表示と同様に、印刷プレビューにも互換表示が適用された。

また、印刷プレビューと印刷で異なることは少ないので、おそらく印刷についても互換表示が適用されると思う。
細かいCSSの適用とかはどうなのかな。

2011年4月19日火曜日

Google Font APIはどうやってマルチブラウザ対応しているのか

WebFontsを読み込む場合のCSSの書き方はブラウザごとに異なるため、こんなsyntaxを使う必要がある。
しかし、Google Font APIで読み込むCSSをではそんな書き方はしていない。
そこで、試しにTangerineのCSSを各ブラウザで読み込んでみて、Google Font APIがどのようにマルチブラウザ対応をしているのか調べてみた。


IE 8
@font-face {
  font-family: 'Tangerine';
  font-style: normal;
  font-weight: normal;
  src: url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RPY6323mHUZFJMgTvxaG2iE');
  src: local('Tangerine'), url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RD8E0i7KZn-EPnyo3HZu7kw') format('woff');
}
URLはIE専用。
2行目のsrcはIE9用?


Firefox 4
@font-face {
  font-family: 'Tangerine';
  font-style: normal;
  font-weight: normal;
  src: local('Tangerine'), url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RD8E0i7KZn-EPnyo3HZu7kw') format('woff');
}
URLはChromeと同じ。


Chrome 10
@media screen {
@font-face {
  font-family: 'Tangerine';
  font-style: normal;
  font-weight: normal;
  src: local('Tangerine'), url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RD8E0i7KZn-EPnyo3HZu7kw') format('woff');
}
}
URLはFirefoxと同じ。
@mediaでscreenだけにしているのはAndroid対策か何かか?


Safari 5 (for Windows)
@font-face {
  font-family: 'Tangerine';
  font-style: normal;
  font-weight: normal;
  src: local('Tangerine'), url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RKCWcynf_cDxXwCLxiixG1c') format('truetype');
}
URLはSafari用(Operaと共通)。アンダーバーで区切ってるのはiPhone用(iOS用?)が別にあったりするためか?


Opera 11

@font-face {
  font-family: 'Tangerine';
  font-style: normal;
  font-weight: normal;
  src: local('Tangerine'), url('http://themes.googleusercontent.com/font?kit=HGfsyCL5WASpHOFnouG-RKCWcynf_cDxXwCLxiixG1c') format('truetype');
}
URLはSafariと同じ。OperaもTrueType組。


まとめ
おそらくUser-Agentで判断して振り分けているだけのようだ。
フォントファイルは大きく分けると下記の3つに分かれるようだ。
  • IE8-
  • IE9+、Firefox、Chrome
  • Safari、Opera


参考:Webフォント (Webfonts)を使う際の最新記述方法 Fontspring Syntax (The New Bulletproof@Font-Face Syntax) - フォントブログ

2011年4月11日月曜日

PHPのエラーメッセージのマニュアルへのリンクを変更する

PHPのfunctionでエラーが発生すると、エラーメッセージが該当するfunctionへのリンクになる場合がある。
array_merge('foo');
↓
Warning: array_merge() [function.array-merge]: Argument #1 is not an array in /var/www/html/test.php on line 2

このリンクのリンク先は、デフォルトでは有効なURLではない。

php.ini等でマニュアルの場所を指定してあげると、マニュアルの該当functionへのリンクにすることができる。
ini_set('docref_root', 'http://jp.php.net/manual/ja/');
array_merge('foo');
↓
Warning: array_merge() [function.array-merge]: Argument #1 is not an array in /var/www/html/test.php on line 3

このエラーメッセージをブラウザで見る場合は便利な場合もあるかもしれないが、このエラーメッセージはそのままエラーログにも出力されるので、エラーログが余計に増えてしまう。
(エラーログ上のマニュアルのURLを使うなら便利かもしれないが。)
このリンクを抑制するにはhtml_errorsをOffにする。
ini_set('html_errors', false);
array_merge('foo');
↓
Warning: array_merge(): Argument #1 is not an array in /var/www/html/test.php on line 3

すっきりしたね。


参考:PHP: 実行時設定 - Manual

2011年4月5日火曜日

PostgreSQLで日付や日時の差を計算する

PostgreSQLでは単純に引き算すれば日付間の差を取得できる。
SELECT '2011-12-31 23:59:59' - TIMESTAMP '2011-01-01 00:00:00' -- => "364 days 23:59:59"
結果はInterval型になる。

もちろん普通の日付型や日時型の列でもOK。
SELECT updated_at - created_at



条件として使う

条件として判定したい場合は下記のように文字列と比較できる。
SELECT '2011-12-31 23:59:59' - TIMESTAMP '2011-01-01 00:00:00' > '300 days' -- => TRUE
SELECT '2011-01-31 23:59:59' - TIMESTAMP '2011-01-01 00:00:00' > '300 days' -- => FALSE
SELECT '2012-12-31 23:59:59' - TIMESTAMP '2011-01-01 00:00:00' > '1 year' -- => TRUE
左辺を考慮して'300 days'のような文字列はInterval型にCASTして比較してくれる。
もちろWHERE句でも使える。



注意点

DATE型とDATE型の引き算の場合は結果がInterval型ではなく、日数を表すInteger型になる。
SELECT '2011-12-31' - DATE '2011-01-01' -- => 364
これを条件として判定したい場合は、'300 days'のような文字列(あるいはInterval型)ではなく、素直に数値で判定するか、あるいはTIMESTAMP型にCASTにする。
-- 数値で判定
SELECT '2011-12-31' - DATE '2011-01-01' > 300

-- TIMESTAMP型にCAST
SELECT '2011-12-31' - TIMESTAMP '2011-01-01' > '300 days'



参考:日付/時刻関数と演算子 (PostgreSQLマニュアル)

2011年4月4日月曜日

PHPの crypt()で SHA2のハッシュを生成する

PHPのcrypt()を使うと、パスワードで使うのに便利な文字列を生成できる。(説明のために3色に色付けした。)
$str = crypt('test'); => $1$X0zFikbH$z9QaylK29Eu4VQajK6PKw0

生成された文字列は$記号で区切られた3つの部分から構成されている。
  • $1$ → MD5でハッシュを生成したことを表す
  • X0zFikbH → ハッシュ生成に使ったsalt。crypt()の第2引数でsaltを指定した場合は指定したsaltが使われるが、指定しないと自動生成されたsaltが使われる
  • z9QaylK29Eu4VQajK6PKw0 → 生成されたハッシュ


この文字列を使ってパスワードが正しいか確認したい場合、下記のようにcrypt()だけで確認できる。
if (crypt($input_password, $str) === $str) {
    echo 'OK';
} else {
    echo 'NG';
}

crypt()の第2引数としてcrypt()で生成した文字列を渡すと、saltの部分だけを取り出してsaltとして使ってくれる(後ろのハッシュ値は無視される)ので、わざわざsaltだけを取り出す必要はない。(便利だが一見しただけでは分かり辛い...)


crypt()の第2引数でsaltを指定しなかった場合のハッシュアルゴリズムは、手元の環境ではMD5が使われた。
第2引数でsaltを指定する場合は、saltの前に付ける文字列によって下記のようにハッシュアルゴリズムを指定することができる。
  • 何も付けない → DES(拡張DESではなく標準DES?)
  • $1$ → MD5
  • $2a$ → Blowfish
  • $5$ → SHA-256 (PHP 5.3.2以降)
  • $6$ → SHA-512 (PHP 5.3.2以降)

上記のように、PHP 5.3.2以降ではcrypt()でSHA2(SHA-256/512)が使えるようになった。
(既に脆弱性が発見されているSHA-1はスキップされたようだ。)

BlowfishやSHA-256/512を使う場合は自動生成のsaltが使えないので、文字列生成時にはsaltを渡してあげないといけない。
saltは推測可能な値でも構わない(元の文字列が同じでもハッシュが異なるようにすることに意味がある)ので、uniqid()あたりでいいんじゃないかな。
$str = crypt('test', '$6$' . uniqid());


参考:PHP: crypt - Manual


関連記事

2011年4月1日金曜日

PHPで 簡単にGET / POSTできるように file_get_contents()を拡張する

file_get_contents()は便利だが、POSTとかエラー対応とかは少し面倒なので、手軽に使えるようにラップしてみた。
PHPのバージョンは5.2.10以降または5.3.0以降が対象。
function file_http(
    $url,
    $params = null,    //パラメータがあれば配列で渡す
    $method = 'GET',    //GET or POST
    &$status = null,    //参照渡しでレスポンスのHTTP Status Codeを返す
    &$http_response_header = null,    //参照渡しでレスポンスのHTTP Headerの配列を返す
    $request_header = array()    //追加したいリクエストのHTTP Headerがあれば
) {
  
    $opt = array(
        'method' => $method,
        'header' => (array)$request_header,    //PHP 5.2.10 / 5.3.0 以降は配列でもOK
        'ignore_errors' => true,    //PHP 5.2.10 / 5.3.0 以降で有効
    );
  
    if ($params) {
        $query_string = http_build_query($params);
      
        if ($method === 'GET') {
            $url .= '?' . $query_string;
        } else {    //POSTの場合
            $opt['header'][] = 'Content-type: application/x-www-form-urlencoded';
            $opt['content'] = $query_string;
        }
    }
  
    $res = file_get_contents($url, false, stream_context_create(array('http' => $opt)));
  
    //レスポンスのHTTP Headerは$http_response_headerにセットされている
    if (is_array($http_response_header)) {
        preg_match('@^HTTP/1\\.. ([0-9]{3}) @i', $http_response_header[0], $matches);
        $status = $matches[1];
    }
  
    return $res;
}

使用例
$res = file_http(
    'http://localhost/test.php',
    array('foo' => 'テスト'),
    'POST',
    $status,
    $responseHeaders,
    array('User-Agent: ゆーざーえーじぇんと', 'Referer: りふぁら')    // 1つだけの場合は文字列でもOK
);

echo $status;    // => "200"
var_dump($responseHeaders);

実際に使う場合には結果の判断等でレスポンスのHTTPステータスコードが欲しい場合があるので、パラメータの参照渡しで取得できるようにした。
そしてステータスコード以外のHTTP Headerを参照したいケースもあるので、これも参照渡しで配列として取得できるようにした。

また、ignore_errorsを指定することにより、レスポンスのHTTPステータスコードが400以上でもWarningを出さない、かつレスポンスのBodyを取得できるようにした。(参考:[メモ] PHPのfile_get_contentsを、HTTPリクエストに使うときのTIPS ::ハブろぐ)
ただしホスト名の名前解決ができない場合はその手前でWarningが出てしまうので、PHPで URLのホスト名(ドメイン)が存在するかチェックする方法のような対応が必要。


以下は余談。
普段は変数名等はcamelCaseにするのだが、$http_response_header等に引っ張られてアンダーバー繋ぎにしてみた。
関数名は、
  • http_request
  • http_get
  • httpRequest
などを考えたのだが、どれもPECLで既に使われているので諦めた。

2011年3月31日木曜日

「lexicon (XLLEX.DLL)が見つからないか、または壊れています。」の修復

Windows XPでMS Office 2007のアプリを起動できなくなった問題に対して、試行錯誤した上で何とか回復できたことのメモ。
回り道が多くて余分なこともしてると思うが、誰か(あるいは自分)の役に立つかもしれないので記録しておく。


いつものようにExcelを開こうとすると「lexicon(XLLEX.DLL)が見つからないか、または壊れています。」というエラーメッセージが表示され、Excelが開けない。
また、Wordも開かなくなっている。(開こうとすると何も書かれていなくてOKボタンしかないダイアログが表示される。)
XLLEX.DLLというファイルはOfficeのフォルダにあるので、レジストリがおかしくなっている?
↓
Googleで調べてみたが、Windowsを再インストールするか、あるいはWindowsユーザーを新しく作り直すしか対策が見つからない。(それは嫌だ。)
↓
「プログラムの追加と削除」でOfficeをアンインストールして、OfficeのインストールCDから再インストール。しかし状況変わらず。何回か繰り返したが駄目。
↓
Windowsの「システムの復元」を使って、Excelが開けた頃にWindowsを戻す。
↓
Excelを立ち上げようとすると、これまでとはまた別のエラーが出るようになった。
それに対してOfficeを再インストールしようと試みるも、そもそもアンインストールができない。
  • 「プログラムの追加と削除」から「変更」「削除」ボタンを押しても、数秒固まるだけで何も起きない
  • OfficeのインストールCDのSetup.exeを起動すると、インストールエラーが発生して終了してしまう
この状態でインストールしようとしてもエラーになってインストールできない。
↓
Microsoft Office 2007をアンインストール(削除)ができない|星屋工作室で紹介されているMSのサイトの「Fix it で解決する」というのをダウンロードして実行したら、Officeをアンインストールできた。
↓
CDからOfficeを再インストール。
↓
ExcelもWordも使えるようになった!


もしかしたら最初からFix itを使えば解決したのかもしれない。
Office2007だけでなく、2003や2010もアンインストール用の「Fix it」があるようだ → コントロール パネルからアンインストールできない場合、Office 2003、Office 2007 または Office 2010 スイートをアンインストールする方法


また、この後Microsoft UpdateによるOffice2007 SP2のインストールがどうしても失敗する事象が発生。
↓
Office2007のサービスパックが当たらない - りぶろくを参考にWindows Installer 4.5をダウンロードしてインストール
↓
SP2もインストールできた。

2011年3月25日金曜日

プログラム言語とフレームワークのオンラインマニュアル29選


Webで公開されている、プログラム言語・フレームワーク・DBのマニュアル(リファレンス)サイトへのリンクをまとめてみた。
選んだ基準は、できるだけ日本語で、なるべく分かりやすいこと。それを満たすなら公式リファレンスより非公式のものを優先している。



JavaScriptのマニュアルは他にも色々あり、使う人のレベルや用途によってどれが使いやすいかが変わってくると思うが、昔大変参考にさせて頂いた杜甫々版を挙げておいた。

Python、Perl、Objective-Cについては公式/準公式のリンクを書いたが、有志によるマニュアルでもっと良いものがあるのかもしれない。(これらの言語はあまり使わないので知らない。)

2011年3月24日木曜日

PHPで URLのホスト名(ドメイン)が存在するかチェックする方法

PHPでURLのホスト名(ドメイン)が有効なものかどうかをチェックする例。
file_get_contents()でignore_errorsをtrueにしてstream_context_create()してもホスト名が名前解決できなくてWarningが出てしまう問題に悩んでいる場合などにどうぞ。
$url = 'http://www.example.com/path';

$array = parse_url($url);

if ($array && $array['host']) {
    $ip = getHostByName($array['host']);
    $long = ip2long($ip);
  
    if ($long === false || $ip !== long2ip($long)) {
        echo '名前解決できなかった';
    } else {
        echo 'OK';
    }
} else {
    echo 'URLが正しくない';
}

DNSで名前解決できたらOKにしている。
また、ホスト名がIPアドレス(IPv4)の場合はどんなIPでも(たとえ255.255.255.255でも)OKにしている。

ip2long()で得た値をlong2ip()でIPアドレスに戻してチェックしているのは、ip2long()が「0.0.256」のような値を「0.0.1.0」などと解釈してしまうため。
参考:(IPv4) インターネットプロトコルドット表記のアドレスを、適当なアドレスを有する文字列に変換する - PHP 5.3 日本語マニュアル
ip2long() を、それ単体で IP の検証に利用するべきではありません。long2ip() と組み合わせて利用します。

<?php
// IP が有効であることを確認します。また、不完全な形式の IP を
// 以下で示すような正しい形式(ドットで 4 つに区切られている)に変換します。
$ip = long2ip(ip2long("127.0.0.1")); // "127.0.0.1"
$ip = long2ip(ip2long("10.0.0")); // "10.0.0.0"
$ip = long2ip(ip2long("10.0.256")); // "10.0.1.0"
?>


これはIPv4を使ってるけど、今後IPv6が普及したら...その時までにPHPも進化しているでしょう。


参考

2011年3月23日水曜日

PHPの SimpleXMLを配列に変換する

シンプルなXMLなら、SimpleXMLElementオブジェクトをarrayにキャストするだけで連想配列に変換できる。
$xml = '<?xml version="1.0" ?>
<root>
<test>TEST1</test>
<test>TEST2</test>
<attr trouble="MISSING">WHY?</attr>
</root>';

$sx = simplexml_load_string($xml);

var_dump((array)$sx);
↓
array(2) {
  ["test"]=>
  array(2) {
    [0]=>
    string(5) "TEST1"
    [1]=>
    string(5) "TEST2"
  }
  ["attr"]=>
  string(4) "WHY?"
}

同じ要素名の要素がある場合(上記の例ではtest要素)、まとめて添字が0から始まる配列になる。
しかし、なぜか属性とテキストノードの両方がある要素の属性(上記の例ではattr要素のtrouble="MISSING")が無視される。

また、子要素や属性のあるXMLの場合、配列の中まで再帰的にキャストしていないのでSimpleXMLElementのままになってしまう。
$xml = '<?xml version="1.0" ?>
<root>
<parent>
<child>MUSUKO</child>
</parent>
<attr foo="FOO" bar="BAR" />
</root>';

$sx = simplexml_load_string($xml);

var_dump((array)$sx);
↓
array(2) {
  ["parent"]=>
  object(SimpleXMLElement)#3 (1) {
    ["child"]=>
    string(6) "MUSUKO"
  }
  ["attr"]=>
  object(SimpleXMLElement)#2 (1) {
    ["@attributes"]=>
    array(2) {
      ["foo"]=>
      string(3) "FOO"
      ["bar"]=>
      string(3) "BAR"
    }
  }
}




これに対して、PHPマニュアルのコメント欄に一発で配列に変換する方法が書いてあった。
$xml = '<?xml version="1.0" ?>
<root>
<parent>
<child>MUSUKO</child>
</parent>
<attr foo="FOO" bar="BAR" />
</root>';

$sx = simplexml_load_string($xml);

var_dump(json_decode(json_encode($sx), true));
↓
array(2) {
  ["parent"]=>
  array(1) {
    ["child"]=>
    string(6) "MUSUKO"
  }
  ["attr"]=>
  array(1) {
    ["@attributes"]=>
    array(2) {
      ["foo"]=>
      string(3) "FOO"
      ["bar"]=>
      string(3) "BAR"
    }
  }
}



json_decode()の第2引数(戻り値を連想配列にするかどうか)をtrueにするのがポイント。
属性は@attributesというKEYの連想配列に格納される。


しかし、属性とテキストノードの両方がある要素の属性が無視される問題は、このjson_encode/json_decodeを使った方法でも発症する。
$xml = '<?xml version="1.0" ?>
<root>
<attr trouble="MISSING">WHY?</attr>
</root>';

$sx = simplexml_load_string($xml);

var_dump(json_decode(json_encode($sx), true));
↓
array(1) {
  ["attr"]=>
  string(4) "WHY?"
}

Why?
まあでも属性値がないことが分かっているXMLならこれで使えそう。(後から属性値を使いたいということになったら大変だけど。)

きちんとやりたいなら、SimpleXMLで取得したオブジェクトを属性も含めて配列に変換 | とりさんのソフト屋さんのやり方がスマートで良さそう。

2011年3月18日金曜日

AWS CloudFormationで PHP Hello World Applicationを作成してみた

AWS(Amazon Web Services)のCloudFormationの「PHP Hello World Application」に関する情報があまりないので試してみた。


まずはAWS Management Consoleから「PHP Hello World Application + SSH enabled」のstackを作成。
場所はAsia/Pacific 東京リージョンを選択できた。
インスタンスタイプはMicroインスタンス、OperatorEmailには自分のメールアドレスを記入した。


しばらくすると、こんなのが作成された。
  • S3
    • 空のバケットが作成された(バックアップ用?)
  • EC2
    • Root Device Typeがebsのインスタンスが1つ作成された
    • EBSのCapacityは8GiB
    • Security Groupが1つ作成された
      • SSHとHTTP(ポート番号は8888)のポートで、ともにIPアドレス制限無し
    • Load Balancerが起動した
      • 80番ポートを待ち受けてインスタンスの8888番ポートに向ける
    • Elastic IPは作成されなかった
  • CloudWatch
    • Alarmが3つ作成された
      • RequestLatencyAlarmHigh
      • CPUAlarmHigh
      • TooManyUnhealthyHostsAlarm
    • 閾値に達したら登録したメールアドレスにメールで知らせてくれるようだ
  • CloudFormation
    • stackが1つ作成された(そりゃそうだ)
  • RDS
    • DB Instanceが1つ作成された
      • DB Engine Versionは5.1.50
      • DB Instance Classはdb.m1.small
      • DB Storageは5GiB
      • Backup Windowは15:00~15:30(日本時間?)
      • Maintenance Windowは日曜14:00~14:30(これも日本時間?)
    • DB Security Groupが1つ作成された
      • 上記のEC2 Security Groupが適用されている
    • DB Parameter Groupのcharacter_set関連は「engine-default」になっているが、UTF-8使えるのかな?
  • SNS
    • CloudWatchのメール通知用のTopicが1つ作成された


EC2のLoadBalancerのドメインにHTTPでアクセスすると、Wellcomeメッセージとともにphpinfoが表示された。
phpinfoによるとバージョンは下記の通り。
  • Apache : 2.2.16
  • PHP : 5.3.3

SSHでアクセス(SSHのログインユーザーはrootでなく"ec2-user"なので注意。"ec2-user"はsudoができる)してみると、/var/www/html の中には index.php しかなかった。
ユーザー"ec2-user"のviはPHPのソースがハイライトされて見やすい。(少し目がチカチカするが。)

PHP拡張については主なものは入っているが、mbstringが入っていない。
yumで入れたら普通にインストールできた。
sudo yum install php-mbstring

mbstringを有効にするためにApacheを再起動。
すると、アクセスできなくなった。EC2のLoadBalancerからインスタンスが外れている。
SNSからのアラートメールもいくつも送られてきてる。

調べてみると、httpd.confでポート番号が80になっていた。
8888に変更して再起動。

これでアクセスできるようになった。mbstringも使えるようになった。


使い終わったら、AWS Management ConsoleでCloudFormationのstackを削除。
するとCloudFormationが作った一連のものをきれいに削除してくれた。
例外はS3で、S3だけはバケットが残っていた。


あとこれは今回の調査に直接関係ないが、AWS Management ConsoleのS3とEC2が重くなった気がする。(この前の改善の影響?)


結論
ささっとPHP実行環境を作りたいなら、これもありかもしれないと思った。
RDSを使いたいかどうかは状況によるけど、CloudWatchとかSNSの設定が楽なのは便利そう。