2010-12-29

【MySQL】同一マシン上の異なるデータベース間でのテーブルコピーの方法

レンタルサーバーなどで複数のデータベースが作成できるMySQLを使用している場合、
 「データベース1つ作成ごとに課金」
という方式を取っている業者もあります(たとえばKagoyaとか)。

経済事情などでデータベースを1つに統合したいときもありますよね?
でもmysqldump等のMySQL附属ツールでは文字化けしてエクスポートが失敗することがよくあります(phpMyAdminでも失敗することがある)。
自分は携帯サイトを運営しているので、エクスポート時に「絵文字」やらが文字化けしてしまうことがものすごく多いです。

そういった方のために参考までに自分でやってうまくいった方法を紹介します。ただ他の環境でうまくいくかはよく分かりません。試せる環境がないので。

---
◆前提
1)同じサーバマシン内でデータベースを複数使用していること。
2)phpMyAdminを使用していること

◆手順
△テーブルの「構造のみ」をエクスポート
1)「phpMyAdmin」にログインして「移動したいテーブル」で「エクスポート」をクリック。
2)「構造」にチェックが入っているか確認する。
3)AUTO_INCREMENTを使用しているのであれば「AUTO_INCREMENT値を追加」もチェックする。
4)あわせて「データ」にチェックが入ってないかを確認する。
5)エクスポートを実行する。以下エクスポートした「構造SQL」を単に「構造」という。

△エクスポートした「構造」を「移動したいデータベース」で実行する
1)「phpMyAdmin」で移動したいデータベースに「SQL」または「インポート」で「構造」を実行する。
2)テーブルが作成されればOK。

△データを移動する
1)データを移動する方法は「SQL」でスクリプトを作る。
2)例としては

INSERT INTO dest_table1 SELECT * FROM src_db.src_table1;
INSERT INTO dest_table2 SELECT * FROM src_db.src_table2;
INSERT INTO dest_table3 SELECT * FROM src_db.src_table3;
INSERT INTO dest_table4 SELECT * FROM src_db.src_table4;
※destは移動先。srcは移動元

という風なSQLを「移動先データベース」で実行すればOKです。

---
データが文字化けせず移動されたか確認して終了です。
参考になれば幸いです。

2010-12-22

【Amazon】AWSを使ってすばやい表示をするサイトを作る

表題の通り、AmazonのWebAPIであるAWS(名前がころころ変わるからこれでいいのか分からないw)を使ってすばやい表示のサイトを作った時のメモ。

まず、ページを表示するたびにAPIへ接続しデータを取得するようなサイトは表示が「遅い」し、ページビュー数が増えてくるとAPI提供側から規制が掛かったりする。
そこで、すばやくするためにはどうしたらよいかを考えた。

考えた結果、以下の2つを目標とすることにした。
・表示を早くする
・APIへのアクセスを低減する


という2つの目的を同時に実現するために以下のことをした。

---
1.自サイトを置いているサーバにAPIの結果をキャッシュとして保持し、それをファイルに保存しておく

2.APIへアクセスする時のURLはほぼ一意(ユニーク)なので、URLをmd5やsha1等でハッシュした結果をキャッシュのファイル名とした

3.APIのデータはXMLで返されるので、キャッシュに保存するのは「XMLをパースした結果のシリアライズされたもの」とする。読み込み時にアンシリアライズすればデータ取得が容易になる
---

1.で保存したキャッシュが「存在するならばAPIへはアクセスしない」というプログラムにすれば「APIアクセス低減」と「表示の高速化」が実現する。
しかし、APIで返されるデータは日々更新されるので、いつかは古いデータとなってしまう。これを回避するには「キャッシュを更新」する必要がある。
しかし、更新間隔を狭めて頻繁にAPIにアクセスするようなプログラムにすると結局「遅い」し「規制に掛かる」可能性がある。
この問題には以下のように対処した

---
1.個々の商品詳細データは「ほぼ更新されない」という「前提にした」(実際は価格などが更新される)ので、キャッシュの更新はしないこととした

2.商品一覧データは売れ筋が上に来る(APIで異なる指定が可能だが)ので、サイト構成上重要だから1週間で更新されるようにした

3.更新自体はプログラムがキャッシュへアクセスするときに「ファイル作成日付を確認し」1週間より前なら「APIへアクセスしデータを取得する」、とした
---

これでもAPIが規制に掛かってしまってエラーが返されたら、それは保存せずに従前のキャッシュを返すようにもした。
これで表示に大体1ページ数秒掛かっていたのが、1秒以内で表示されるようになった。


---
データベースが使えるならそちらのほうがプログラムが簡単かもしれない。データベースに全てのデータを突っ込んでおけばメンドウはないかもしれないし。
自分はデータベースを使用する方がメンドウだ、と作ったときは感じたのでそうしたけどね。

あと、この方法は小規模のそれほどページビューが多くないサイトを想定してます。具体的には1日1万ページビューくらい。
なので、もっと大規模なサイトならそれにあわせたものにしないとだめでしょう。

2010-12-21

【Web】JavaScriptのデバッグプリント

JavaScriptでプログラムを作る機会があったので、そのとき知った小技をメモ。
そのとき作ったサイト:MHP3rdスキル逆引きサービス

・コンソールにデバッグプリントする方法
Firefoxしか使えないけど、結構便利なデバッグプリントの方法。
→デバッグプリントとは、変数の中身を何らかの方法で出力し内容を確かめること、というような意味。
普通はメッセージボックスを使って変数の中身を出しているけど、いちいちメッセージボックスを閉じるのがメンドイよね?
そこで、

----
console.log( 何らかの変数 );
----

と書くとFirefoxのJavaScriptコンソールに書き出せる。

JavaScriptにはデバッグ用の機能が少ないから微妙にめんどくさいね。
PHPみたいな「var_dump」や「print_r」みたいなものがほしいよ。

2010-12-15

【ブログ】BloggerにPHPからメールで投稿する方法

翌日発売するマンガやラノベのデータを自動でBloggerに投稿するシステムを開発して運用しています。
プログラミング言語はPHPを使っているのですが、ちょっとめんどくさかったのでメモを残しておきます。

基本的にPHPでメールを送信するには「mb_send_mail」という関数で送信します。また、日本語メールは一般的にJISコードが使用されています。
ですが、Bloggerのメール投稿は日本語エンコードがUTF-8なので、メールもUTFエンコードに変換して送らなければなりません。

例としては、

----
mb_language( 'uni' );
mb_internal_encoding( 'UTF-8' );

$to = 'xxxx@xxxx.jp';
$subject = 'ブログタイトル';
$body = 'ブログ本文';

mb_send_mail( $to, $subject, $text );
exit();
----

といったプログラムになると思います。
ですが、これだけではBloggerに投稿した際に文字化けを起こしてしまいます。

そこで、改良版として以下のようにしています。

----
mb_language( 'uni' );
mb_internal_encoding( 'UTF-8' );

$to = 'xxxx@xxxx.jp';
$subject = 'ブログタイトル';
$body = 'ブログ本文';
$from = 'From: xxxx@xxxxx.jp' . "\r\n";
$from .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";

mb_send_mail( $to, $subject, $text, $from );
exit();
----

$from変数には、Fromヘッダだけではなくて他のいろんなメールヘッダを挿入することができます。
例の通り、「Content-Type」ヘッダを追加してcharset属性でもUTF-8を指定しています。これで文字化けなく投稿することが出来ました。
注意する点は、$fromに挿入するヘッダの各行ごとに「\r\n」を末尾へ挿入することぐらいでしょうか。

ちなみに、メールで投稿するブログ本文にもHTMLタグを挿入することができ、投稿してから編集する必要はありません。
ですが、「ラベル」と呼ばれるBloogerのタグをメール投稿に付加することが出来ないので、これは投稿してから編集する必要がありますね。

2010-12-07

【資格】宅建・マン管・管業を受験した感想的なもの

今年の宅地建物取引主任者試験、マンション管理士試験と管理業務主任者試験が12月5日で終了しました。
自分の結果としては
・宅地建物取引主任者 : 43点で合格
・マンション管理士 : 34点
・管理業務主任者 : 44点
となりました。
やはりマンション管理士は合格率7~8%だけあって難しかったですね。今回は多分合格できないでしょう。来年受けるかどうかはまだ未定です。
宅建、管業については予想以上に出来ました。宅建は合格していますし、管業も「マークミス」が無ければおそらく合格でしょう。
上の資格3つを取ることを「三冠」とネット上では言うらしいですw
今のところ自分は「ニ冠」は達成できたかも、と思っております。

んで、タイトルの通り感想などを書いていきたいと思います。

・宅建について
試験の難易度的には民法「難しい」、宅建業法「簡単」だった気がしますね。
宅建業法の簡単さは驚きました。何せ初受験の自分でも20問全問正解でしたしね。
合格基準点(ボーダー)が今回36点でした。宅建試験史上2回目の高得点な基準です。
いろんなテキストにも「35点取れればほぼ合格です」と書いてあって「70%の得点が出来ればいいのか」と自分も思っていました。
ですが、70%を超える得点を取らねばならないこともある、ということをこれから気にしなければならないのでしょう。
何というかこれから受験をする方は気の毒に思いますが、自分はホントに「今年取れてよかった」と思ってますwwww

・マン管について
試験の難易度的には、民法「難しい」、マンション関連法令「普通」、建築・設備「知らない」って感じでしたw
問題の最初に民法の問題(10問程度)が配置されているのですが、そこで30分も使ってしまい、焦ってしまって誤答が多くなってしまいました。
見直しの時間も十分とれず、見直しすればあと2~3問程度確実に取れるようなケアレスミスが何個か残ってしまいました。悔しいです。
50問で構成される国家試験の中では最高峰の難しさではあるようです。大変でした。

・管業について
試験の難易度的には民法「普通」、マンション関連法令「簡単」、建築・設備「消去法で何とかなる」といった感じでした。
この試験の問題の特徴としては、選択肢を4~6個並べて「正しいもの(誤っているもの)はいくつか」という形で出題される「個数問題」というのが多いことです。選択肢自体は「簡単」なのですがそれらを「全て知っているかどうか」はまた別の問題で、解くのが大変な問題です。
こういった個数問題が増えることは今後も予想されていて、いろんな資格学校の方が言っている通り「今後も試験の難化が予想される」とおっしゃられてます。
自己採点ではよい点数だったのですが、「マークミス」が無いことを願うのみです。

・試験会場について
試験会場が「宅建・マン管」が一緒で高校を使用したものでした。「管業」は大学が会場でした。
どちらも、JRの駅からすぐ(高校のほうは徒歩1分、大学の方は「駅がくっついている」ところだったw)なのでよかったです。
基本的に11時~11時半ころに試験室へ入れるのですが、自分は大体10時半ころに会場入りして勉強の最終確認して、トイレをすまします。
試験室に入っても、試験が始まる前に2~3回トイレに行くようにしてますw

・勉強量について
上の3つの試験合わせて、5冊程度のテキストと10冊程度の問題集を使いました。
問題集は最低でも10回繰り返しています。2~4回で知識が定着します。
その後は解けない部分をテキストやネットで補強し、それをテキストなりノートにまとめるようにしました。
自分が気をつけたのは「まとめたら終り」ではなく、「問題集を1回全て解いたら、まとめたテキスト(ノート)を一度全部読み返す」ようにしたことですね。
毎回新しいことに気づくのでやはり10回は繰り返したほうがいいでしょう。

今回はこんなところです。

2010-12-03

【資格】宅建主任者試験合格

このブログでも2回ほど取り上げているけど、10月に受験した宅建主任者試験にこのほど合格いたしました。
12月1日に合格発表で3日に合格証書が届きました。合格証書はA4くらいの紙で結構ペラペラだったですw
ちなみに合格証書の他には、主任者登録手続きの手引きなどが入ってました。宅建主任者になるには「登録」して「主任者証を発行」してもらわなければならないんですよね。
まぁ、今のところ登録するつもりは無いです。不動産業やってるわけじゃないので。

今回の合格点は36点で合格率は15.2%です。
50点満点なので72%の得点をしないとダメだったようですね。かなり高い合格点だったといえるでしょう。
合格率も去年よりは下がっているようです。宅建試験で36点の合格点は2002年以来2回目でした。

ちなみに直近10年の合格点と合格率は以下の通り。
 2000年(平成12年)30/15.4%
 2001年(平成13年)34/15.3%
 2002年(平成14年)36/17.3%
 2003年(平成15年)35/15.3%
 2004年(平成16年)32/15.9%
 2005年(平成17年)33/17.3%
 2006年(平成18年)34/17.1%
 2007年(平成19年)35/17.3%
 2008年(平成20年)33/16.2%
 2009年(平成21年)33/17.9%
 2010年(平成22年)36/15.2%

久しぶりに国家試験に合格しました。以前に合格したのは確か、情報処理技術者試験のソフトウェア開発技術者試験だった気がします。この名前の試験もなくなっちゃいましたけどね。法律系の試験は初めての受験で始めての合格でした。
次は「管理業務主任者試験」を受験します(これを書いている翌々日試験日です)。この試験が終わればヒト段落。少し休みたいですねw

2010-11-16

【青色申告】個人事業主の手続きメモ

3年位前に個人事業主として仕事を始めたときにした手続きメモ。
開業するまでにはちょっとした手続きが必要(青色申告するときも)。

1)開業前
会社勤めなどをしていた場合は、社会保険の手続きをする。
→「健康保険(中小企業なら政府管掌の健康保険だと思われる)」
→「厚生年金」
に加入しているので、これを脱退して
→「国民健康保険」
→「国民年金」
に加入する。
厚生年金&健康保険の脱退は会社がやってくれると思うので、国民健康保険と国民年金の加入手続きをする。
加入手続きは住民票がある地方自治体(市役所や町役場など)の「年金課」的なところが窓口なのでそこで行う。

2)開業手続き
近所の税務署にいって、窓口で「個人事業を開業したい。青色申告もしたい」と言うと「開業届け」みたいな書類が渡される。
それに個人情報と青色申告用の「記帳する台帳に○をつけ」て提出。多分税務署の職員さんに聞けば分かるはず。
注意すべき点は「屋号」。屋号を決めておかないと書類にかけないので。
青色申告には2種類あって「簡易な簿記」と「正規な簿記(複式簿記のこと)」があって、自分が開業の申請に行ったときは「正規な簿記」の申請を職員さんが勝手に書いてくれたよ(笑
違いは課税される所得額(課税標準という)から控除される金額。確か簡易な簿記は課税標準から10万円控除で、正規な簿記は65万円控除される。
あと、専従者や従業員を雇うときは別な手続きがある。自分は一人で仕事してるので詳しいことまでは分からない。

手続きは以上で完了。

3)帳簿をつける
個人事業主の事業年度は毎年1月1日から12月31日まで。企業のように事業年度を設定できるわけじゃない。

1年の流れ的には、
1)1月1日から何らかの取引があれば記帳していく(領収書も何かに貼り付けて保存すること)
2)12月31日で帳簿を締める
3)決算をしたら台帳やらを保存(5年保存なのでファイルに閉じて物置へ)
4)2月~3月になったら「確定申告書」を用意して税務署へ行き確定申告して納税する。
※確定申告書は確定申告が近くなったら税務署から送られてくる。
といった感じ。
自分は「紙の帳簿をつける」なんてやったこと無かったので「やよいの青色申告」というソフト使ってる。
決算も確定申告書も印刷できるので便利。

4)決算
帳簿と現預金に誤差が無いか確認したら、総勘定元帳、貸借対照表と損益計算書、青色申告書を作成する。
これらの書類自体はソフトが作ってくれるので印刷するだけでOK。これで終り。
総勘定元帳はかなりの印刷量になるので注意すること。これらをファイルに閉じて終り。

5)確定申告
所得税の確定申告は2月~3月中旬までに行う。確定申告書は時期が近づいたら税務署から郵送されてくる。
申告方法的には、
1)自分の手で書いて税務署へ持っていく
2)ソフトで印刷して税務署へ持っていく
3)電子申請用のデータをソフトで作って申告用のソフト(e-Taxという)を使用し電子申請する
4)電子申告書作成サイトで申告データを作成し電子申請する
→こんな感じ: http://www.nta.go.jp/tetsuzuki/shinkoku/shotoku/kakutei.htm
の4つくらい。
自分は自治体から住民基本台帳カードを発行してもらってるので3)の方法で電子申請してる(電子署名を読み取る機械必要、↓こんなの)。


税務署に手で持っていくと全ての書類を添付しないといけないけど、電子申請ならデータのみでOK。
あとは納税額を納税用の口座へ振り込めば終り。

以上。

2010-10-18

【資格】宅建を受験

10月17日は宅建の試験日。受験してきたよ。自己採点結果は43点。合格できたと思いますw

2日前くらいから何故か右足が痛くなって辛かったんだけどシップを貼って歩かないようにしてたら、当日の朝は何とか痛みも引き無事試験会場までいけた。
こういうアクシデントは初めてでかなり辛かったw

11:30に開場なんだけど、自分は11時頃に開場入り。会場内のベンチで「暗記モノ」を復習。
あと、会場では通信教育や資格学校の業者さんたちがいっぱいいて、「法律の改正部分」や「マーケット統計」が載った小冊子を配ってたよ。

12:30に試験監督の人から試験の説明を受けた。かなり厳重な「不正行為排除」の姿勢がうかがわれた。
まずは「不正行為をしたらどうなるか」の説明。
「不正行為をしたら都道府県知事から3年以内の受験禁止を命じられる可能性があるので注意すること」」
ということらしい。
これは宅建業法に定められていることなので事前に勉強してた。
次は「携帯電話を含む無線通信機器」のこと。試験場の机の上には「携帯電話等封筒」という茶封筒が置いてあって、「携帯電話は電源を切った上で封筒に入れ、封をすること。試験開始後封筒に入れずに所持していることが分かったら不正行為とみなす」と説明された。
↑こんな感じの。


さらに「トイレ等理由を問わず途中退室を認めない」ということ。
他に受けたことのある資格試験(気象予報士、情報処理技術者試験など)より大分厳しい。途中退室は認めてほしかったと思う。

試験終了後は一気に受験生が試験室から出てくるのでかなり混みあった。試験会場までは電車で来たのだけど駅で混雑しそうなので会場で30分くらい時間をつぶしてから駅に向かった。
それでもまだ受験生で混んでいた。もうちょい待ってもよかった。

---
試験内容の感想をつらつらと。
◆権利関係
自分の得点10/14。4問間違ったけどまぁまぁでしょう。
権利関係分野はモノの本や資格学校の講師さんによると「難化」しているらしい。
しかし、それは見たことない条文や判例が出てただけで難易度的にはたいしたことないのではないかな、とは思った。
それに試験全体でも見たことない分野の問題は5~6問で合格するには大して影響がないとも思った。

◆宅建業法
自分の得点は20/20。全問正解だった。
ほぼ基本問題だったので簡単だったよ。かねてからの話題だった「特定住宅瑕疵担保責任法」からも1問出題されたけど基本的な部分の問だったので簡単。
引っ掛け問題が多いこの分野では、問題演習のときから結構引っかかって失点していたんだけど、今回はひとつも引っかからずに終わったのはうれしいねw
例としては↓な感じ。
・問42の選択肢3
「宅地建物取引業者が居住用建物の貸主及び借主の双方から媒介の依頼を受けるに当たって借主から承諾を得ていなければ、借主から借賃の1.05月分の報酬を受領することはできない」
自分が注目したのは「双方からの媒介」、「1.05月分の報酬」というワード。この2つのキーワードは間違ってない。双方から媒介依頼を受けたら1.05月分の報酬を受けられる。
ただ、よく読むと「居住用建物」や「承諾を得ていなければ」というワードも見えてくる。「居住用建物」の媒介依頼の報酬は「1/2月分(承諾を得ていなければ)」しかもらえない。なので、この選択肢は正しく正解だったというわけ。
急いで解くと読み飛ばしてしまいそうになる選択肢をじっくり読むことで失敗を防げる。今回はそれがよかったと思う。

◆法令上の制限・税
自分の得点は10/11。建築基準法の用途規制で「過半が工業地域で工業専用地域にまたがった敷地に共同住宅を建築できるか?」という問題で間違った。住宅系を建てられないのは過半もしくは全てが工業専用地域だったことをわすれてたw
後の問題は結構簡単で税金の問題もたいしたことなかった。気になったところは、いつも出てる所得税が出なくて贈与税が出たところくらい。

◆免除科目
自分の得点は3/5。住宅支援機構と統計の問題を間違えました。
景品表示法で「マンションの敷地に傾斜地が含まれる場合、それを明示しなくてもよいか?」という問題が出たけど、自分が勉強したテキストには「マンションを除く」ときちんと書いてあったので得点できたよ。
土地・建物の問題は全部以前の本試験に出たことあるようなものだったので簡単だった。

---
今回自分が使ったテキストと問題集には以下の通り。他には一切手を出してない。
◆テキスト
LECの出る順宅建合格テキスト(権利関係、宅建業法、法令上の制限・税・その他)


◆過去問題集
LECの出る順宅建ウォーク問(権利関係、宅建業法、法令上の制限・税・その他)分野別問題集

TAC分かって受かる宅建 過去10年分本試験問題 年度別問題集


◆予想模擬試験
LECの大予想模擬試験
TACの実力診断模試

2010-09-18

【資格】宅建勉強方法

宅建の勉強方法を今後のためにメモしておくことにした。
今までの経験から、自分は「手を動かさないと覚えられない」ことがわかっていたし、勉強を早く始めた(3月くらいだった気がする)ので時間はあったのでなるべく手で書いて覚えることにした。

基本的には「テキスト読み込み」「過去問をやる」といったことを繰り返すだけ。

具体的には、下のような感じでやった。

1)最初はテキストを1回全て読み込む(自分ではノートにまとめた。全部で4冊くらい)
2)過去問題集を1冊全て解く(過去10年分で500問くらい。当然1回目ではほとんど解けないので割り切ること。間違った問題を控えておく)
3)テキストを読む(2で間違ったところにメモ。自分は1で書いたノートに書き込んでたけど)
4)過去問題集を1冊全て解く(2と同じように間違ったところを控えておく)
5)テキストを読む
6)過去問題集を1冊全て解く
※1500問程度

1)を1ヶ月くらいで終わらせて、2)、3)~4)、5)~6)を各1~2週間かけてやった。
6までくると大体問題集の8割以上は解けるようになる。だけど、問題になれて微妙に内容を覚えてしまう。
そこで、今度は違う形式の問題を解くようにしてみた。上でやってたのは「分野別問題集」というヤツで科目ごとに並んだものだったので、今度は「年度別問題集」をやってみることにした。
年度別問題集は宅建の場合、大体10年分くらいが1冊になってることが多いので、下のようなスケジュールでやってたよ。

月曜日:テキストを読んで復習
火曜日:2年分過去問題を解く
水曜日:2年分過去問題を解く
木曜日:2年分過去問題を解く
金曜日:2年分過去問題を解く
土曜日:2年分過去問題を解く
日曜日:休み
(12週間×500問=6000問程度)

という感じの、「1週間1セット」を12週間(4ヶ月弱程度か)くらい続けた。ちなみに得点は12週終わった時点で10年間分平均で47点(50点満点)くらいになってた。
あと、法律が改正されていたのでその改正部分や追加部分を確認した。
-----

ここまでが12日以前のこと。12日は「国内旅行業務取扱管理者試験」の試験日だった。宅建の試験日が来月17日なのでちょうどいい区切りとなった気がする。
ここから追い込みに掛かることとする。
年度別の問題集も微妙に問題を覚えてしまったので、ホントに平均47点も取れるような実力が付いたかわからなくなってきた。
そこで、各出版社から出ている「予想模擬試験問題集」を買ってやってみることにした。大体4回分の模擬試験が入ってて、1500円くらいのを3冊買ってやってみた。
出版社毎に難易度が違うけど、平均して40点程度取れる実力があるようだった。

宅建の試験日までちょうど1ヶ月をきった。今後は「予想問題集」と「過去問」を同時にやっていこうと思っている。

2010-09-15

【プログラミング】Haskell勉強中

Haskellを勉強中です。面白い。ループ無いんだなLispとかにはあるのに。

・高階関数(関数自体も式として扱える。引数に関数を取れるし、関数も返せる)
・遅延評価(値が必要になるまで処理されない。だから、「無限長のリスト」というのもアリ)
・静的な型チェック(コンパイル時の型チェックということ。型が合わないとコンパイルエラーとなる)
・代入不可(変数を初期化することは出来ても、その後値を変えられない。グローバル変数がマジで無い)

最初本読んだときに「代入不可とかループ無しででかいシステム作れんの?」とか思った。
でもPerl6のコンパイラ&インタプリタ(Pugsというらしい)はHaskellで実装されてるんだってさ。すげぇな。

これでシステムかけるようになれば面白いことも短いプログラムで出来そうだ。

ちなみに勉強に使ってる本はこれ↓

2010-09-14

【広告】サイトへ掲載する広告選びの方針研究

以前別の場所で書いた日記を転載。ちょうど2年前くらいの情報ということに注意してください。

---

掲載する広告選ぶ時の方針として何がいいのかということを考えたのですが、その結果のメモです。備忘録ですね。

自分のサイト2つを題材として比較検討します。
1)「掲示板(1)」(※上の画像でアクセスが少ないほう)
    →以降、「1」とする。
2)「掲示板(2)」(※上の画像でアクセスが多いほう)
    →以降、「2」とする。

で、現実の事象として、

・1の現象
  →広告クリック数は少ない
  →同じ広告をずっと張り替えなくても比較的クリック数は落ちない
  →一人平均PVが少ない(※)
  →ユーザとしては「女性」で、「10代~30代」の人がほぼ
  →Yahoo!モバイルにカテゴリ登録済み
  →Googleモバイルでワード1位
  →1日の広告クリック数:400回~600回
  ※つまり一人のユーザが見るページがすくない。言い換えれば「サイトへきてもすぐ帰っちゃう」ということ。

・2の現象
  →クリック数が多い。
  →広告を張り替えないと顕著にクリック数が下がる
  →一人平均PVが多い(現在では大体一人当たり30~40PVある)
  →ユーザとしては「男性」で、「30代~50代」の人がほぼ
  →Yahoo!モバイルのカテゴリ登録済み
  →Googleモバイルでワード4~5位(安定しない)
  →1日の広告クリック数:2500回~4000回

ということがわかってます。

以上をまとめると、
  →1は新規ユーザがよく来るしクリック率も悪くないが、PVの母数が小さいのでクリック数自体が少ない
  →2は新規ユーザよりリピータが多くてクリック率はそれほどよくないが、PVの母数が大きいのでクリックも比較的多い。
ということがわかります。

・結論
  →1は単価の高いアフィリエイト広告。文言変更や画像をそれほど変更しなくてもよい
  →2は単価は低くてもよいので、クリック保障広告。ただし文言や画像を頻繁に変える必要がある
という方針がよさそう。

実際、2は1クリック1円でも2500円程度になるし。
PPM(IT系の人なら習う経営戦略の基礎で出てくる)で言うなら、2は広告の変更が頻繁だから、投資が必要なので「花形」っぽいな。1は「負け犬」っぽいけど、投資が必要ないので規模の小さい「金のなる木」になるのかな?

ただ、1にGoogleアドセンス携帯版を掲載してるんだけどこちらも結構稼いでくれる。
Googleの広告選定が最近良いらしく、ePCM(※)が1ドルくらいになってる。なので無理やりアフィリエイトにすることもないかもしれないな。
※広告を1000回表示していくら売上げがあるかの単位
だけど、2に関してはアフィリエイト広告はダメな気がする。クリックの無駄が多すぎるという精神的なストレス(笑)があるので、クリック保障の方がいいと思う。

【WEB】アクセスログ解析システムの自作

某アクセス解析サイトが、もうホントに止まってばっかりなので自前のアクセス解析システムを持とうかと思っています。
以前GIGAZINEで見たのだけど、「Visitors」っていうWebサーバのアクセスログを解析してHTMLを生成するプログラムが紹介されてた。
参考リンク: http://gigazine.net/index.php?/news/comments/20070305_visitors/
これをとりあえず使ってみることにしてみました。

それだけだといまいち面白くなかったので、「プログラム開発を行わず」にやってみてます。
で、どうやってるのかというとUNIXのシェルスクリプトでやっとります。

■システム内容
---
○仕様
1)システム上のルートディレクトリに解析したいサイト用のサブディレクトリを置く
2)システム上のルートディレクトリにバッチ処理用シェルスクリプトを置く
3)サイト用サブディレクトリが増えても2)のシェルスクリプトを書き換えが不要なものにする
4)1)で作ったディレクトリにログダウンロードとHTML生成シェルスクリプトを置く
5)1)で作ったディレクトリにログ置場用ディレクトリと生成したHTMLファイルを置く

ディレクトリ構成は下のような感じ
/サイト名1/access_log_YYYYMM.html
/サイト名1/logs_YYYYMM/access_log_DD.log
...
/サイト名N/access_log_YYYYMM.html
/サイト名N/logs_YYYYMM/access_log_DD.log
※YYYY:年4桁 MM:月2桁 DD:日2桁

仕様上2)のシェルスクリプト
#! /bin/sh
NOW_DIR=`pwd`/
for filename in `ls -1`
do
if [ -d ${filename} ]; then
"${NOW_DIR}${filename}/ftp.sh"
fi
done

仕様上3)のシェルスクリプト
#! /bin/sh
FTP_HOST_NAME="ホスト名"
FTP_USER_NAME="アカウント"
FTP_USER_PASS="パスワード"
LOCAL_DIR="/仕様1)で作ったサブディレクトリ/"
GET_DIR="/ホストのログ置場/"
ONE_DAY_AGO=`date --date '1 day ago' +%Y%m%d`
NOW_YEAR_MONTH=`date --date '1 day ago' +%Y%m`
NOW_DAY=`date --date '1 day ago' +%d`
FILE_NAME="access_log_${ONE_DAY_AGO}.gz"
STORE_DIR="${LOCAL_DIR}logs_${NOW_YEAR_MONTH}/"
STORE_FILE_NAME="${STORE_DIR}access_log_${NOW_DAY}"
REPORT_FILE_NAME="${LOCAL_DIR}access_log_${NOW_YEAR_MONTH}"

ftp -n ${FTP_HOST_NAME} << _EOF_ user ${FTP_USER_NAME} ${FTP_USER_PASS} bin lcd ${LOCAL_DIR} cd ${GET_DIR} get ${FILE_NAME} bye _EOF_ mkdir ${STORE_DIR} gunzip -c ${LOCAL_DIR}${FILE_NAME} > ${STORE_FILE_NAME}
visitors -A -m 50 ${STORE_DIR}* -o html > ${REPORT_FILE_NAME}.html
rm -f ${LOCAL_DIR}${FILE_NAME}
------
で、仕様上2)のシェルスクリプトをCRONに登録して1日1回実行する、としておけばOK。

Visitorsの性能なんだけども、
▼1ファイル16~18MB程度
▼同時処理ファイル数が5個
という環境でも1秒かからなかった。なかなかのスピードです。
とりあえず1ヶ月くらい動作させて問題がなかったら徐々に移行しようかと思ってます。

2010-09-13

【資格】宅地建物取引主任者・マンション管理士・管理業務主任者の関連について

宅地建物取引主任者(以下宅建)、マンション管理士(以下マン管)、管理業務主任者(以下管業)の各試験に共通する科目を一緒に勉強すれば1度に3つの資格を取れるという話。

まず、なぜ3つの資格試験を同時進行させると取りやすいの?というところから。
理由としては、
1)試験範囲の内容がかぶりまくり
2)試験の日程が近い
3)まぁまぁ実用性が高い
4)まぁまぁの実用性なのにそれなりに簡単に合格できる
といったことがあげられる。
同時進行すれば国家資格を同時に3つも取れるのはうれしいかもしれない。いざというとき役立つかもしれない資格なのがいい。


次は勉強の方法について。
自分の意見としては、宅建の勉強を最初にするのがオススメ。
理由は以下の通り。
1)マン管よりは簡単
2)マン管・管業を先に勉強すると宅建に時間が掛かる。
3)マン管・管業の試験にでる法律の基礎がわかる
4)いちばん早く試験が行われる
1)、2)、3)をまとめて説明すると、自分で勉強した感じでは「マン管」は宅建よりは難しい(管業は宅建と同レベル)と思う。簡単なほうで足場をしっかり作っておくのがいい。
それに、宅建の勉強をせずに「マン管&管業」の勉強を始めてしまうと「汎用性がなくなる」可能性があると思う。そもそもマン管・管業試験は「マンション」の法律や建物の知識に特化したものであって専門性が高いんだよね。それを先に勉強してしまうと、なかなか次につながらない。
そこで、宅建試験の勉強をして「民法(区分所有法含む。後述)等」「宅建業法」「都市計画法・建築基準法」の知識を得た上で、専門性の高いマン管・管業の勉強を始めたほうが効率がいい。

次、4)について。
今年(平成22年)の試験スケジュールとしては「宅建10月第三日曜日」「マン管11月末」「管業12月初旬」といった感じ。スケジュールに従うなら宅建が最初という当然の結果だけども。


3番目は詳しい内容について。
まず宅建についてなのだけど、主要な科目としては以下の通り。
・民法
・宅建業法
・その他税法など
マン管・管業試験に共通する科目としては、
1)民法自体
2)民法科目に含まれる「区分所有法(分譲マンションの法律)」
3)宅建業法
4)その他税法に含まれる、都市計画法・建築基準法
がある。
これらをきっちり押さえておけばマン管・管業を勉強するとき「ほぼ過去問解くだけで対策OK」になる。

次はマン管・管業の内容。
主要な科目は以下の通り。
・民法
・区分所有法(分譲マンションの法律)
・マンション標準管理規約
・マンション標準管理委託契約書
・建築の知識
・マンション管理適正化法
・その他(宅建業法・都市計画法・建築基準法も含む)
宅建試験の知識のみでOKなのは「民法」「宅建業法」「都市計画法」「建築基準法」「区分所有法(の基礎部分のみ)」といった具合。マンション関係に特化した内容なので区分所有法などはかなり突っ込んだ問題が出るので注意。
個人的に難しかったのは「建築の知識」で、知らないとわからない問題が結構出る。たとえば「コンクリート圧縮強度の試験方法は何か?(ちなみにシュミットハンマー法がよく使われる)」とかね。


概略だけどこんな感じで勉強すれば、試験までにかなりの実力を養成できると思う。
勉強の仕方自体は個人でやり方は千差万別だろうから言及しないけど(暇があれば書くかもしれないけどね)、大体の目安で言えば3~4ヶ月のあいだ1日2~3時間の勉強でOKだと思うよ。

2010-09-12

【資格】国内旅行業務取扱管理者試験を受けてきたよ。

まず、テキストすら買わないで受験したことを明言しておきますね^^
でも、ネットやらで調べてから受けましたよ?

じゃあ、なぜ受験したのか?
10月にある、宅建の試験会場と同じなので建物の中まで合法的に下見ができるから。なんと開始時間まで一緒だったしね。
1)どうやって試験会場まで移動するか。電車の時間などのシミュレーション。
2)どんな「机」「椅子」を使うのか
3)部屋に時計はあるのか?(結構重要だったり)
4)部屋にはエアコンがあるのか?
といったことを調べてました。結果、机や椅子は普通の学校にありそうなやつ。時計あり・エアコンありだった。

この試験は「法規」「標準約款」「実務」と3科目に分かれてて、全ての科目で60点以上取れれば合格。
毎年合格率は30%前後らしい。ホントに少し勉強すれば取れそうだ、とは思ったけど、ほとんど勉強しなかった。

んで、自分の成績の話。
法規:70点
標準約款:72点
実務:49点
といった結果になりましたよ。
何というか、法規と約款は「ちょろい」感じだったけど、実務は「知らなきゃ絶対わからない」感じの問題だったよ。
たとえば、

問題:世界遺産「古都京都の文化財」の登録物件に入っていないものはどれか。
ア.延暦寺
イ.清水寺
ウ.鞍馬寺
エ.本願寺

といった具合。ちなみに答えは「ウ.鞍馬寺」。
あと、空港の「コード」を問う問題が全然わからなかった。青森空港→AOJとか。知らんもんこんなのw

昔すんでた北海道(層雲峡)や地元の県(伊豆沼・内沼)からの出題もあったけど、生かしきれず惨敗でしたよ。
---

とまぁ、結果的にはこんな感じ。
でも、旅行が好きな人ならホントに簡単な試験だと思う。
法規やら約款はテキスト読んで数回過去問とけばOKなレベルだし、実務の内容は「旅行好き」なら知ってそうな感じだった。
一度受けてみてはどうかと思う。

2010-09-11

【オンラインショップ】売れないサイトの条件

売れないオンラインショップの条件
http://japan.internet.com/busnews/20080303/6.html

確かに、自分がやってるAmazonのアフィリエイトページでも同じようなことが起こってるかも。
以前、商品の詳細ページにレビューを全部表示してたときはすごく注文が多かったんだけど、
現在はページが重くなるからって、別ページにしたんだよ。そしたら注文数がかなり減った。。。

newsingのコメントの中に書いてあったのだけど、
「売れているサイトは更新する必要が感じられない → 汚いページのまま」
っていうことが書いてあったけど、これは真理かも知らんね。

【Linuxメモ】FatでフォーマットしたUSBハードディスクのマウント

Linuxサーバに接続しているUSBハードディスクへ書き込めないことが判明しました。
Linuxを再起動して、自動マウンタの設定が変えられたのが原因みたい。

USBハードディスクはFat32でフォーマットされているのだけど、このファイルシステムには「パーミッション」っていう概念がなくて、うちの Linuxでただマウントすると「755」のパーミッションになってしまう。所有者はrootユーザ。
rootユーザでchmodすればOKじゃないのか?と思ってやってみたんだけど、ダメ。そもそも書き込みがどのユーザでやってもすべてダメだっ た。

今度は、マウント時点ですべてのユーザに書き込み権限を与えてしまえばいいや、と思って下のコマンドを打ってみた。

# mount -t vfat -o umask=000 /dev/sda /mnt/xxxxx/

これで書き込めるようにはなったけど、何が悪いのか良くわからないままで微妙に気分が悪いw

---
相変わらずLinux関係はオイラにゃ荷が重い。
「XWindowシステムで使用する自動マウンタ」
と、
「再起動時に動作する自動マウンタ」
の設定が変わっているからだと踏んでいるのだけど、どこを確認したらいいのかがわからないや。

【WebAPI】WebAPI処理クラス

前にホテル検索サイトをじゃらんのAPIで作ったときのメモ。

以前からWebAPIのXMLデータをパースするのがめんどくさくてしょうがなかったんだよね。
で、何とか簡単にパーサを組めないかと思って作ってみたのが「API抽象クラス」。
特にオブジェクト指向とか勉強したわけじゃないので、ぐっちゃりしたコードになってるけどご勘弁を。

仕組み的には抽象クラスにして「XMLパラメータとパーサをくくりだした」だけのものなんだけど、実際に抽象クラスから派生させたクラスにはパラメータ定義とパースのプログラムを書くだけになった。
一つ一つのクラスは小さく見通しの良い物にしようとしてるけど、結局は自分で使うものなのでテキトーな感じになってしまうのは仕方ないね。

抽象クラスの下にあるコードは実際にじゃらんのAPIをパースするクラス。例としてのせておきますね。

◆WebAPI抽象クラス

<?
  /*
  *  APIクラス処理クラス(親クラス)
  *    DATE : 2008/10/17
  */
  // MySQL接続クラス
  include_once( dirname( __FILE__ ) . '/MySQL.php' );
 
  abstract class WebApi
  {
    protected    $params;       // リクエストパラメータ(連想配列)
    protected    $url;          // パラメータが付与されたURL
    protected    $xml;          // 取得XML
    protected    $data;         // パースされたデータ
    protected    $max_count;    // データの最大件数
   
    public function __construct(){}
   
    /**
      リクエストパラメータ配列初期化処理
      このメソッドの中でparamsの連想キーを設定する。
    */
    abstract protected function init_params();
   
    /**
      APIのURL(パラメータ無し)を返す
    */
    abstract public function get_url();
   
    /**
      XMLをパースする(抽象メソッド)
    */
    abstract protected function parse_xml();
   
   
    /**
      リクエストパラメータが存在するか
    */
    public function is_param( $param_name )
    {
      if( isSet( $this->params[ $param_name ] ) ) {
        return true;
      } else {
        return false;
      }
    }
   
    /**
      リクエストパラメータ取得
    */
    public function get_param( $param_name )
    {
      if( $this->is_param( $param_name ) ) {
        return $this->params[ $param_name ];
      } else {
        return false;
      }
    }
   
    /**
      リクエストパラメータ設定
    */
    public function set_param( $param_name, $value )
    {
      if( $this->is_param( $param_name ) ) {
        $this->params[ $param_name ] = $value;
        return true;
      } else {
        return false;
      }
    }
   
    /**
      XMLデータ取得
      $uri : APIのURI。(終端に記号('?' or '&')を入れないこと。
      パース結果を返す。
    */
    public function get_xml( $uri )
    {
      // URL編集
      $temp = array();
      foreach( $this->params AS $key => $param ) {
        if( $param != "" ) {
          $temp[] = sprintf( '%s=%s', $key, $param );
        }
      }
     
      // $uriがすでにパラメータ指定がされているかどうか。
      if( substr_count( $uri, '?' ) > 0 ) {
        $this->url = sprintf( '%s&%s', $uri, implode( '&', $temp ) );
      } else {
        $this->url = sprintf( '%s?%s', $uri, implode( '&', $temp ) );
      }
     
      $strSql  = "SELECT * FROM web_api_result ";
      $strSql .= sprintf( "WHERE md5 = '%s' ", md5( $this->url ) );
      $con = new DataBaseConnect();
      $rec = new ResultSet( $con->executeQuery( $strSql ) );
     
      if( $rec->getRowCount() > 0 ) {
        $temp = unserialize( $rec->getField( "serial" ) );
        $this->max_count = $temp[ 'max_count' ];
        $this->data = $temp[ 'data' ];
      } else {
        $this->xml = $this->exec_method();
        $this->parse_xml();
        $this->store_xml();
      }
     
      return $this->data;
    }
   
    /**
      ページタグの取得
    */
    public function get_page_tag( $file_name, $current_page, $max_page, $param )
    {
      if( $current_page == 1 ) {
        if( $max_page > 1 ) {
          $page_tag = sprintf( '←|%s / %s|<a href="/%s?%s&p=%s">→</a>', $current_page, $max_page, $file_name, $param, ($current_page + 1) );
        } else {
          $page_tag = sprintf( '←|1 / 1|→' );
        }
      } else {
        if( $current_page >= $max_page ) {
          $page_tag = sprintf( '<a href="/%s?%s&p=%s">←</a>|%s / %s|→', $file_name, $param, ($current_page - 1), $current_page, $max_page );
        } else {
          $page_tag = sprintf( '<a href="/%s?%s&p=%s">←</a>|%s / %s|<a href="/%s?%s&p=%s">→</a>', $file_name, $param, ($current_page - 1), $current_page, $max_page, $file_name, $param, ($current_page + 1) );
        }
      }
      return $page_tag;
    }
   
    /**
      データベースにXMLを保存
    */
    protected function store_xml()
    {
      // md5用SQL
      $sql_md5  = "SELECT * FROM web_api_result ";
      $sql_md5 .= sprintf( "WHERE md5 = '%s' ", md5( $this->url ) );
     
      $strSql  = "INSERT INTO web_api_result (md5, md5_sql, regist, api_url, xml, serial) VALUES(";
      $strSql .= sprintf( "'%s', ", md5( $this->url ) );
      $strSql .= sprintf( "'%s', ", md5( $sql_md5 ) );
      $strSql .= sprintf( "'%s', ", date( 'Y-m-d' ) );
      $strSql .= sprintf( "'%s', ", $this->url );
      $strSql .= sprintf( "'%s', ", mysql_real_escape_string( $this->xml ) );
      $strSql .= sprintf( "'%s') ", mysql_real_escape_string( serialize( array( 'max_count' => $this->max_count, 'data' => $this->data ) ) ) );
      $con = new DataBaseConnect();
      $con->execute( $strSql );
    }
   
    // URLを確認してPOST or GETを選び実行する
    private function exec_method()
    {
      return $this->get();
    }
   
    // パラメータの桁数が256Byte以下の場合はGetメソッドで取得する
    private function get()
    {
      mb_regex_encoding( 'SJIS' );
      $temp = mb_convert_encoding( @file_get_contents( $this->url ), 'SJIS', 'UTF-8' );
      $temp = mb_ereg_replace( "[■□◆◇●○▲▼△▽☆★♪]+", '', $temp );
      return $temp;
    }
  }
?>
-------------------------------------------------------------------------------------

◆宿データAPI処理クラス

<?
  /*
  *  じゃらん宿データAPI処理クラス
  *    DATE : 2008/10/18
  */
  include_once( dirname( dirname( __FILE__ ) ) . '/config.php' );
  include_once( LIB_JARAN_HOTEL );
 
  class JaranHotelAdvance extends WebApi
  {
    const URI       = 'http://jws.jalan.net/APIAdvance/HotelSearch/V1/?key=[アクセスキー]';
    const PAGE_PAR_COUNT = 10;
   
    private    $response_fields;    // レスポンスフィールド定義。
   
    public function __construct()
    {
      $this->init_params();
    }
   
    public function get_url()
    {
      return self::URI;
    }
   
    public function get_page_par_count()
    {
      return self::PAGE_PAR_COUNT;
    }
   
    public function get_max_count()
    {
      return $this->max_count;
    }
   
    protected function init_params()
    {
      // リクエストパラメータ設定
      $this->params[ 'pref' ]      = '';    // 都道府県コード
      $this->params[ 'l_area' ]    = '';    // 大エリアコード(都道府県内を分けたコード)
      $this->params[ 's_area' ]    = '';    // 小エリアコード(大エリアをさらに分けたコード)
      $this->params[ 'h_id' ]      = '';    // 宿コード(これを指定すると他すべて無視)
      $this->params[ 'h_name' ]    = '';    // 宿名
      $this->params[ 'h_type' ]    = '';    // 宿タイプ(パラメータは仕様書参照)
      $this->params[ 'o_id' ]      = '';    // 温泉ID
      $this->params[ 'x' ]         = '';    // 経度
      $this->params[ 'y' ]         = '';    // 緯度
      $this->params[ 'range' ]     = '';    // 緯度経度から半径rangeKMの範囲を探す。
      $this->params[ 'o_pool' ]    = '';    // 屋外プール(0:なしdefault 1:あり)
      $this->params[ 'parking' ]   = '';    // 無料駐車場(0:なしdefault 1:あり)
      $this->params[ 'pub_bath' ]  = '';    // 内湯・大浴場(0:なしdefault 1:あり)
      $this->params[ 'onsen' ]     = '';    // 温泉(0:なしdefault 1:あり)
      $this->params[ 'prv_bath' ]  = '';    // 貸切風呂(0:なしdefault 1:あり)
      $this->params[ 'sauna' ]     = '';    // サウナ(0:なしdefault 1:あり)
      $this->params[ 'jacz' ]      = '';    // ジャグジー(0:なしdefault 1:あり)
      $this->params[ 'mssg' ]      = '';    // マッサージ(0:なしdefault 1:あり)
      $this->params[ 'r_ski' ]     = '';    // 貸しスキー(0:なしdefault 1:あり)
      $this->params[ 'r_brd' ]     = '';    // 貸しスノーボード(0:なしdefault 1:あり)
      $this->params[ 'pet' ]       = '';    // ペットOK(0:なしdefault 1:あり)
      $this->params[ 'esthe' ]     = '';    // エステ(0:なしdefault 1:あり)
      $this->params[ 'p_pong' ]    = '';    // 卓球(0:なしdefault 1:あり)
      $this->params[ 'limo' ]      = '';    // 送迎(0:なしdefault 1:あり)
      $this->params[ 'late_out' ]  = '';    // チェックアウト11時以降(0:なしdefault 1:あり)
      $this->params[ 'pict_size' ] = '1';    // 画像サイズ(詳細は仕様書)
      $this->params[ 'order' ]     = '';    // 並び順(0:宿コード順 1:50音順)
      $this->params[ 'start' ]     = '';    // 何件目から表示するか
      $this->params[ 'count' ]     = self::PAGE_PAR_COUNT;    // 1ページに何件表示するか
      $this->params[ 'xml_ptn' ]   = '1';
     
      // レスポンスフィールド設定
      $this->response_fields[] = 'hotelid';
      $this->response_fields[] = 'hotelname';
      $this->response_fields[] = 'postcode';
      $this->response_fields[] = 'hoteladdress';
      $this->response_fields[] = 'region';
      $this->response_fields[] = 'prefecture';
      $this->response_fields[] = 'largearea';
      $this->response_fields[] = 'smallarea';
      $this->response_fields[] = 'hoteltype';
      $this->response_fields[] = 'hoteldetailurl';
      $this->response_fields[] = 'hotelcatchcopy';
      $this->response_fields[] = 'hotelcaption';
      $this->response_fields[] = 'pictureurl';
      $this->response_fields[] = 'picturecaption';
      $this->response_fields[] = 'accessinfomation';
      $this->response_fields[] = 'checkintime';
      $this->response_fields[] = 'checkouttime';
      $this->response_fields[] = 'x';
      $this->response_fields[] = 'y';
      $this->response_fields[] = 'sampleratefrom';
      $this->response_fields[] = 'hotelnamekana';
      $this->response_fields[] = 'onsenname';
      $this->response_fields[] = 'numberofratings';
    }
   
    protected function parse_xml()
    {
      $this->xml = preg_replace( "/\s+/", " ", $this->xml );
      $this->data = array();
     
      $ret = preg_match( "@<numberofresults>([0-9]+)</numberofresults>@i", $this->xml, $max_count );
      $this->max_count = (int)$max_count[ 1 ];
     
      $ret = preg_match_all( '@<hotel>(.*?)</hotel>@i', $this->xml, $hotels );
      foreach( $hotels[ 1 ] AS $hotel ) {
        $temp = array();
       
        // レスポンスフィールド設定による読み出し。
        foreach( $this->response_fields AS $field ) {
          $pattern = sprintf( '@<%s>(.*?)</%s>@i', $field, $field );
          $ret = preg_match( $pattern, $hotel, $result );
          $temp[ $field ] = $result[ 1 ];
        }
       
        // フィールド設定では取れない取得物
        // フィールド設定では取れない取得物
        $ret = preg_match_all( '@<accessinformation name="(.*?)">(.*?)</accessinformation>@i', $hotel, $accesses );
        $temp2 = array();
        for( $i = 0 ; $i < count( $accesses[ 1 ] ) ; $i += 1 ) {
          $temp2[ $i ] = array( $accesses[ 1 ][ $i ] => $accesses[ 2 ][ $i ] );
        }
        $temp[ 'accesses' ] = $temp2;
       
        $ret = preg_match( '@<creditcard[^>]+>(.*?)</creditcard>@i', $hotel, $credit );
        $temp[ 'creditcard' ] = explode( ',', $credit[ 1 ] );
       
        $ret = preg_match( '@<lastupdate day="([0-9]+)" month="([0-9]+)" year="([0-9]+)"/>@i', $hotel, $updates );
        $temp[ 'lastupdate' ] = sprintf( '%s-%s-%s', $updates[ 3 ], $updates[ 2 ], $updates[ 1 ] );
       
        $this->data[] = $temp;
        unset( $temp );
      }
    }
   
  }
?>

2010-09-10

【MySQL】データバックアップについて

自分のサイトを置くサーバは一部Kagoyaのサーバを使用してます。

参考リンク: http://www.kagoya.jp/

Kagoyaでは、1日1回自動的にデータのバックアップをしてくれているのですが、「mysqldump」というMySQL付属のツールでデータをダンプしているために、ひどい文字化けが発生していて、そのままでは使えないデータをバックアップしてくれちゃっているのです。

調べたところ、mysqldumpへ「binary」データでダンプするよう指示するオプションがあるようです。が、試した結果は0バイトのファ イルができるだけで使えないことが判明。

で、結局「データをダンプするツール」自体を探すハメに。
いろいろ探したところ、「phpMyBackupPro」というツールを発見。心配だった文字化けも発生しませんでした。プログラムはPHPで記 述されててインストールも簡単でしたよ。
処理スピードも5秒ほどですべてバックアップできました。(全部で7つほどデータベースで容量は合計100MBくらい)

PHPの設定でメモリ使用量が「50MB以下」となっていたため1つのデータベースがダンプできなかったのですが、Kagoyaサーバ(専用サー バのみですが)ではphp.iniの設定を変更できるためこれは回避できました。

ダンプファイルは自動的に1個のファイルに圧縮し、自動で事務所のサーバへFTPダウンロードをするよう設定しました。
これでとりあえず1日前までは戻らせることができるでしょう。

【Google Chart API】使ってみたよ。


事業主なので帳簿はつけているわけですが、「事業主」に対して報酬や生活費を事業から支出した場合、勘定科目を「事業主貸」にすること、というふうに決 まってます。
ですが、「事業主貸」にした時点で事業の帳簿処理は終わってしまいます(まぁ当たり前ですけどねw)。

そこからは事業主の家計になるので、お金の管理を行うシステム(家計簿システムですな)がほしいと思ってました。
集計はデータベースからデータを引っ張るときにやれるのでプログラム的には簡単なのですが、
「グラフ表示もほしい」
けど、
「自分でプログラムを実装するのは面倒だな」
と思うわけです。
実際画像を扱ったりするのはプログラムが複雑になったり、ひどく煩雑な手順を踏まないとできないのです。
で、何かいい方法を探してみたのですが、さすがGoogle。グラフの画像を出力してくれるAPIを公開してくれてました。IMGタグのsrcに APIのURLを設定するだけで利用できます。

参考リンク: http://code.google.com/intl/ja/apis/chart/

利用する上で注意点がひとつ。
・XY軸に登録できる目盛りが【数値】のみ
これはすごくイタイです。けど、今回は支出の推移を視覚的に捕らえたいだけなので、まぁ言いかと。

使用してみたものは上の画像で出てるグラフです。

何かの参考になればいいと思います。

【お酒】たまご酒

 
うちの近所にあるスーパーで売られてました。この色と、ただ「たまご酒」というラベルにどきどきしちゃってつい衝動買い。何というか、こういうストレートな商品が好きです。
作ってるのは勝山酒造みたいですね。

飲んでみましたけど、ほんとに玉子酒でしたw 甘くてカスタードみたいな味がします。
これは冬にコタツでぬるくお燗したらすごくおいしそう。今度試そうとおもいますw

【Amazon】Amazon AWS APIについて

AmazonのAPIが変わって「Product Advertising API」というものになったらしい。
名前変わっただけか?と思ったんだけど、どうやらAPIへリクエストを出すときに「認証」する必要があるらしい。
RESTに関してPHPでちょっと作ってみたのでメモ。

ドキュメントURL http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/rest-signature.html

class Request
{
  const    AWS_ACCESS_KEY_ID  = 'AWSのアクセスキー';
  const    AWS_SECRET_KEY_ID  = 'AWSの秘密鍵  AWSに発行してもらうこと';
  const    AWS_END_POINT    = 'ecs.amazonaws.jp';
  const    REQUEST_METHOD    = 'GET';
  const    REQUEST_URI      = '/onca/xml';
 
  const    HASH_ALGO      = 'sha256';
 
  public static function get_hashed_url( $url )
  {
    $url = $url . '&Timestamp=' . self::get_timestamp();
   
    $ret = preg_match( '/^(.*?)\?/i', $url, $domains );
   
    $ret = preg_match( '/\?(.*?)$/i', $url, $params );
    $params[ 1 ] = str_replace( ':', '%3A', $params[ 1 ] );
    $params[ 1 ] = str_replace( ',', '%2C', $params[ 1 ] );
    $temp_request = $params[ 1 ];
    $temp_params = explode( '&', $temp_request );
    sort( $temp_params, SORT_STRING );
   
    $request = self::REQUEST_METHOD . "\n";
    $request .= self::AWS_END_POINT . "\n";
    $request .= self::REQUEST_URI . "\n";
    $request .= implode( '&', $temp_params );
   
    $hash = base64_encode( hash_hmac( self::HASH_ALGO, $request, self::AWS_SECRET_KEY_ID, true ) );
    $hash = urlEncode( $hash );
   
   
    return $domains[ 1 ] . '?' . implode( '&', $temp_params ) . '&Signature=' . $hash;
  }
 
  private function get_timestamp()
  {
    return date( 'Y-m-d', gmmktime() ) . 'T' . date( 'H:i:s', gmmktime() ) . 'Z';
  }
}

---

お知らせメールに
>we pay out hundreds of millions of dollars per year to websites that advertise our products.
とか書いちゃうところがすごいな。なかなかに大変みたい。

【PHP】簡単TCPクライアント

 
TCP通信のテストにクライアントが必要だったわけです。
ですが、こんなチョコッとしたものに、GUIのアプリを作るなんて面倒なので、昔ながらのCUIで作ってみたよ。
久方ぶりのコンソールアプリに興奮しました。
ちなみに、上がクライアント側、下がサーバ側。

'exit'と入力されるまで回る感じです。

<?php
  $url = 'tcp://IP or ドメイン名:ポート番号';
  $port = ポート番号;
  $timeout = 30;

  $fp = fsockopen( $url, $port, &$errno, &$errstr, $timeout );
  if( !$fp || $errno > 0 ) {
    print( "$errno ($errstr) \n" );
    exit();
  }

  while( true ) {
    print( 'input>' );
    // scanf関数は下のほう参照。
    $input = scanf();
    $send_text = sprintf( "%s %s\n", date( 'YmdHis' ), $input );

    print( 'SEND>>' . $send_text );
    fwrite( $fp, $send_text );
    print( 'RECV<<' . fgets( $fp, 4096 ) );

    if( $input == 'exit' ) {
      break;
    }
  }
  fclose( $fp );
  exit();
?>

---
PHPを使って、標準入力から入力するやり方を今まで知らなかったことに気づいた。

// 擬似scanf
function scanf()
{
    $stdin = fopen( "php://stdin", "r" );
    $line = trim( fgets( $stdin, 64 ) );
    fclose( $stdin );
    return $line;
}

という感じで、実際には「標準入力から1行読む」というようなことをしてる。

2010-09-09

【SheevaPlug】サーバ構築についての作業メモ。

SheevaPlugのサーバ構築についての作業メモ。

▼計画した作業
 ●ハードウェア関係
  →ハードディスク増設

 ●インストール・設定
  →FTPサーバ&クライアントインストール
  →Apache2インストール
  →MySQLインストール
  →PHP5インストール

▼実施した作業
 ・ハードディスク増設
  →FDISKでパーティションを作成
  →「mkfs.ext2 /dev/sda1」でフォーマット。
  →/mntへマウント。
  →/etc/rc.local へ「mount /dev/sda1 /mnt」追記
 以上。

 ・FTPサーバ&クライアントインストール
  →FTPサーバをインストール。今回はProFTPDをインストールした。
  →「apt-get update」でリスト更新
  →「apt-get install proftpd」を実行しインストール。
  →「/etc/ftpusers」に自分が使ってるアカウントが記載されていないか確認。
  →/etc/hostsや/etc/hosts.allow、/etc/hosts.denyも適切に設定すること。
  →「apt-get install ftp」を実行しクライアントをインストール。
 以上。

 ・Apache2インストール
  →「apt-get install apache2」を実行しインストール。
  →ドキュメントルートを増設ハードディスクへ移動する。
   「/etc/apache2/sites-available/default」内の「/var/www」を目的のパスへ変更し Apache再起動。
 以上。

 ・MySQLインストール
  →「apt-get install mysql-server」を実行しインストール。
  →初期ユーザのIDとパスワードは以下の通り。
   USERID: debian-sys-maint
   PASSWD: /etc/mysql/debian.cnfファイル内に記載されている、「passowrd=*********」を参照。
  →上のユーザでログインし、
   「GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '上のパスワードを利用' WITH GRANT OPTION; FLUSH PRIVILEGES;」
   を実行する。
  →普段使うユーザも作成しておく。
  →外部のサーバからも接続できるようにする。
   「/etc/mysql/my.cnf」の
    「bind-address = 127.0.0.1」
   を
    「bind-address = 現在のIPアドレス」
   に変更する。
  →データベースファイルのパスを増設ハードディスクへ移動する。
   「/etc/mysql/my.cnf」の
    1)datadir=**************** を 移動したいパスへ変更する。
    2)移動したいパスへ現在のデータベースファイルをコピーまたは移動する。
    3)移動したデータベースファイルのパーミッションをコピー元と同様の設定に変更する。
    4)再起動する。
 以上。

 ・PHP5インストール
  →「apt-get install php5」を実行する。
  →「apt-get install php5-mysql」を実行する。
  →「apt-get install php5-cli」を実行する。
 以上。

【Linux】Vimのコマンド

Vimのコマンドメモ。
-----------------
■終了・ファイル
コマンドライン引数で開くファイルを指定する。
:e  ファイルを開く。
:q  終了
:q!  変更を破棄して終了
ZZ  上書き&終了 or :wq
:w  ファイル名を付けて保存 or 上書き

■カーソル移動
h   カーソルを左へ
j   カーソルを下へ
k   カーソルを上へ
l   カーソルを右へ
+   カーソルを次の行へ or Enter
-   カーソルを前の行へ
w   単語単位で右へ
b   単語単位で左へ
0   カーソルを行頭へ(数字のゼロ)
$   カーソルを行末へ
^   カーソルを行最初の単語の1文字目へ
C-d  半画面下へスクロール
C-u  半画面上へスクロール
C-f  1画面下へスクロール
C-b  1画面上へスクロール
:[0-9]+ 指定行へ移動
gg  ファイルの先頭へ
G   最終行へ

■画面分割
:sp  ウィンドウを分割。あるファイルを開いた状態で「sp: ファイル名」とすると、そのファイルを開いて分割。
C-w w ウィンドウを移動
:close 現在のウィンドウを閉じる。
:only 現在のウィンドウ以外を閉じる。

■挿入モード
i   カーソル位置で挿入モード
a   カーソルの1文字後で挿入モード
o   カーソル行の下に新しい行を追加し挿入モード
r   カーソル位置の文字を1文字変更。挿入モードにはならない
cc  行全体をいったん削除し変更する。
c0  カーソルから行頭まで削除し変更。
c$  カーソルから行末まで削除し変更。

■削除
x   カーソル位置の1文字削除。前に数字を入れるとその数字分削除。
dw  カーソル位置から後ろの1単語削除
d0  カーソル位置から行頭まで削除
d$  カーソル位置から行末まで削除
dd  カーソルがある行を削除
[0-9]+dl  カーソル位置から文字数分削除
※ヤンクバッファにたまる。つまりWinの「切り取り」と同じ。

■コピー(ヤンク)&ペースト
yw  カーソル位置から後ろの単語をコピー
y0  カーソル位置から行頭までコピー
y$  カーソル位置から行末までコピー
yy  カーソル行をコピー。前に数値を入れると行数分コピー。
[0-9]+yl  カーソル位置から文字数分コピー
p   ペースト

■アンドゥ
u   アンドゥ

■検索・置換
/pattern  後方へ検索。正規表現可能。
?pattern  前方へ検索。正規表現可能。
n   直前の検索と同じ方向へ続ける
N   直前の検索と反対方向へ続ける
[renge]s[/pattern/replace/][flag]
置換。
→renge : ファイル全体「% or 1,$」 行数指定「1,50」(1行目から50行目まで)
→pattern : 検索文字列。正規表現可。
→replace : 置換文字列。正規表現でキャプチャした場合、\1~\9、&(マッチ全体)が使用可能。
→flag : 確認しつつ置換「c」 全てのマッチを置換「g」。指定しないと最初のマッチのみ置換。
例)「satou nanashi」というテキストに
→%s/satou \([a-z]+\)/suzuki \1/g
の置換を行うと、
「suzuki nanashi」となる。
※「/」が検索文字列に入ってるときは違う記号で区切る。

【Linux】Emacs コマンドメモ

Emacsエディタのコマンドメモ。一応ここにも。
-------------------------------------
Emacsコマンドメモ。

■起動・ファイル
C-x C-c 終了
C-x C-f ファイルオープン
C-x C-k 現在のバッファを保存し、別のファイルをバッファに呼び出す。
C-x C-s 上書き保存
C-x C-z 中断し、シェルへ戻る。fgコマンドで再開。

■バッファ
C-x o   次のバッファへ移動。
C-x b   バッファ選択(バッファの名前を入力し選択)
C-x C-b バッファ一覧表示

■カーソル移動
C-f  カーソル右へ
C-b  カーソル左へ
C-n  カーソル下へ
C-p  カーソル上へ

C-a  カーソル行頭へ
C-e  カーソル行末へ

C-v  下へスクロール(ページダウン)
M-v  上へスクロール(ページアップ)

M-f  単語単位でカーソル右へ
M-b  単語単位でカーソル左へ

■アンドゥ
C-x u  アンドゥ。Emacsのバージョンが>=22ではC-/でもOK。

■削除
DEL    直前の1文字削除(BackSpaceと同じ)
C-d    カーソル位置の1文字削除(DELと同じ)

■カット&ペースト
C-k    カーソル位置から行末までカット(キル)
C-SPC  選択(リージョン)開始のマーク付け。マークからカーソル位置まで選択(リージョン)
M-w    選択(リージョン)をコピー
C-w    選択(リージョン)をカット(キル)
C-y    貼り付け

■検索・置換
C-s    インクリメンタル検索(後ろへ)
C-r    インクリメンタル検索(前へ)
M-%    対話置換。
1)検索文字列入力
2)「with:」プロンプトの後に置換文字列入力
3)「y」or「n」or「!」で置換するかしないか選択。
M-x replace-regexp
対話置換の正規表現用。

■シェル
M-!    コマンド実行。ミニバッファか専用バッファに結果出力。
M-|(Shift-\) 選択(リージョン)をコマンドの標準入力に食わすことが出来る。

------------------
■Slime関係
M-x slime Slime起動
C-c C-z REPLバッファへ移動
C-c C-k Lispファイル保存→コンパイル→REPLへロード
C-c C-c カーソル上の関数定義を評価

【音楽】自作音源製作

ソフトウェアで音源作成してます。
サイン波の波形は簡単に作れる(大抵のプログラミング言語には最初からsin関数がついてる)んだけど、三角波やノコギリ波、矩形波にパルス波を 作り出そうとすると結構めんどい。

まぁ、最初なのでファミコン(チップチューンとかいうジャンルらしい)のような音になる予定。

以下、メモ的に少し具体的な話を。

1)テンポが120だとすると、大体2秒で1小節。よって4分音符は0.5秒だと分かる。
2)A4(ラの音ね)の音を出す場合、1秒間に440回サインカーブの波形を作成する。これを440Hzという。
3)4分音符なら0.5秒なので440÷2=220Hz。例えば全音符なら440*2=880の周波数となる。
4)この波のデータは単位円の話なので-1~1までの実数になる。
5)CDの音質だとこの波形データから44100回サンプリングする。44100Hzの標本化周波数という。
6)この取り出した44100個のデータを16ビット(0~65535まで)の情報として量子化する。
7)Waveファイル形式として書き出し。

と言う感じの流れになってる(これで正しい処理かどうかは分からないw)。
たぶん、2)~7)を音を替えながら繰り返せば曲データとして保存可能。
後はディジタルフィルタなんかを実装すればリバーブとかの効果を持たせられる。

実は既にディジタルフィルタのプログラムは作ってある(高速フーリエ変換のプログラムも)ので、音源ができればWebサービスとして公開可能だっ たりします。

---
ここで分からない人のための三角関数のおさらい。

◆サイン
単位円(半径が1の円のことね)の線上をある点が移動するときのY座標の値を返すもの。
つまり、Yの高さを得られるわけだね。
角度が90度の時はY=1になったり、0度や180度の時はX軸上にあるからY=0になったりする。

◆コサイン
こっちは単位円の線上をある点が移動するときのX座標の値を返すもの。
つまりXの長さを得られる。
角度が0度の時X=1だし、90度の時はX=0。180度の時はー1になる。



ちなみに、サインカーブの周波数を変えてどんどん足していくといろんな波形にできる(たとえばノコギリ波とか)。
その「いろんな周波数」を分解して「どんな周波数が足されているのか」を見るために「フーリエ変換」を使用したりする。
普通の波のグラフは横軸が「時間(t)」になってるけど、フーリエ変換後のグラフは横軸が「周波数」になる。見え方を変えられる処理ということ。

ローパスフィルターやハイパスフィルターはこのフーリエ変換された周波数のデータから低い周波数のみ通したり、高い周波数のみ通したりするディジ タルフィルタ。

【PHP】IOを多重化する方法

ネット麻雀システムを作ってる関係で、ソケットやストリームを多重化する方法を覚えたよ。
んで、これって実はWEBAPIに応用できるものなんじゃね?と気づいた。

PHPのプログラムはWEBAPIからデータを取得しようとすると、1つの通信が終わってからじゃないと次の通信が行えない。だけど、以下の方法を使えばIOを多重化することが出来て、結構な速度が出るプログラムになると思われる。

PHPの関数に、
 1)stream_socket_client
と、
 2)stream_select
って言うのがある。

WEBAPIのURLを配列にして、ひとつひとつ1)の関数に与えるとストリームが取得できる。
んで、取得したストリームをまた配列にして、2)の関数に与えると、受信できる「ストリームを返してくれる」というもの。
返されたストリームからXMLを受信し、すべてのストリームにデータがなくなったときにパーサを動かせばOK。

参考URL: http://www.ibm.com/developerworks/jp/opensource/library/os-php-multitask/index.html

---
stream_selectの使い方がまだイマイチ良くわかってないけど、結構面白いことが出来そうだね。

【MySQL】全文検索

MySQLには全文検索を行える機能がついてるのだけど、何らかのパッチを当てたり、違うシステムを組み込まないとマルチバイト文字(日本語もマルチバイ ト文字)が使えないのです。

さらに、MySQLの全文検索は結構制限があって、
 「検索文字は4文字以上」
 「50%以上のレコードがヒットすると、結果を返さない」
というちょっとひどい仕様になっています。

で、どうにかして「マルチバイト文字」の全文検索を「パッチを当てず」に使用したい。

50%の制限は、「IN BOOLEAN MODE」って指定をすると解除されるので問題ないのだけど、4文字制限がちときつい。
で、結構力技な方法を考えた。

以下が具体的な方法。
 1)FULLTEXTインデックスをはるカラムはLONGTEXTなどの大容量にしておく
 2)検索対象文字列を1文字ずつばらばらにしMD5でハッシュにする
 3)ハッシュを半角スペースで区切りカラムに保存

というように、結構簡単に「マルチバイト文字列」で「全文検索」が実現可能だった。ただしめちゃくちゃ容量を食うけどね。
日本語で1文字の検索でもハッシュ化すると半角32文字まで増えるのでMySQLの制限もクリア。

ハッシュ化する関数。引数$sourceはハッシュ化対象文字列。ちなみにエンコードはUTF-8です。
function make_search_token( $source )
{
  $chars = preg_split( '//u', $source );
  $temp_token = array();
  foreach( $chars AS $char ) {
    $temp_token[] = md5( $char );  
  }
  return implode( ' ', $temp_token );
}

多分、AND検索などの細かい指定は出来ないけど、ちょっと使う分には簡単で、便利だと思うがどうだろうか?

ZenBack

WebMoney ぷちカンパ