カテゴリー : web & pc

airtunesを使ってみた

自宅では、無線LANを利用するのに AirMac Expressを使ってます。
以前から、DJの先輩が、無線LANでiTunesの音楽をスピーカーに飛ばしてるってことを教えてもらっていたのですが、1Kの部屋ではなかなかメリットもなく、後手後手になってました。。で、今回やってみました!!

http://www.apple.com/jp/airmacexpress/features/airtunes.html
ここを見ながらやったんですが、AirMac Expressのステレオピンジャックを利用してアンプに接続し、iTunesの右下にあるメニューから、”AirMac Express”を選択すると、ステレオ経由で音が流れてきました。オーディオインタフェース経由でやってたんですが、これで有線接続しなくてもiTunesの音が楽しめます!

ここで、youtubeとか、radikoとかブラウザで音楽を楽しむことってありますよね。
iTunes以外でも、AirMac Express経由で音を出せないものなのか!?ということで調べたら、こんな記事が。
http://mylifelog.sunnyday.jp/wordpress/2010/03/21/647

この Airfoil っていうアプリを使うと、AirTunesをiTunes以外のアプリでも使えました。
とりあえず動作確認まで。有料アプリなので、もっとひろい部屋に引っ越したとき、購入しようと思います。
http://rogueamoeba.com/airfoil/mac/

他にもアプリを作成されてたので、これもメモ。
http://rogueamoeba.com/

Zend_Db_Selectのcolumnsメソッドではまった

Zend_Db_Selectのメソッドにcolumnsというものがあります。
selectする対象を後付で追加できるメソッドです。使い方はこんな感じ。

1
2
3
4
5
6
7
$adapterは、Zend_Db_Adapter_Pdo_Mysql。
 
$adapter->select()
        ->from(array("t1" => "hoge_table"), array("id", "account"))
        ->columns(array("password", "update_date"))
        ->where("account = ?", "testest");
        ->query()->fetchAll();



今回やっていたのは、2つのSQL文をUNIONで結合するという内容でした。
取得するカラムが、”id”, “account”, “state”, “update_date”として、UNIONで結合するのですが、結合する2つのSQL文の対象となるテーブルに、”state”っていうカラムがないために、後付で”0″をつけるっていうことをやっていました。(実際は複数のテーブルを結合していて、複雑なので、簡略化してます。)

1
2
3
4
5
6
7
8
9
10
11
$select1 = $adapter->select()
                   ->from(array("t1" => "hoge_table"))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->where("t1.id = t2.account_id")
 
$select2 = $adapter->select()
                   ->from(array("t1" => "hogehoge_table"))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->columns(array("state" => new Zend_Db_Expr(0)));
 
$adapter->select()->union(array($select1, $select2))->query()->fetchAll();



テーブルのイメージはこう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
create table hoge_table (
    id int , 
    account varchar(16), 
    state varchar(8), 
    update_date timestamp, 
 
    primary key `id`
);
 
create table hogehoge_table (
    id int, 
    account varchar(4), 
    update_date timestamp, 
 
    primary key `id`
);
 
create table hogehogehoge_table (
    id int auto_increment, 
    account_id int, 
    name varchar(128),  
 
    primary key `id`
);



こういう場合、columnsで追加したカラムは、取得結果でも、後ろに追加した形ででてきます。

1
2
3
4
5
--------------------------------------------
| id | account | update_date | name | state | 
--------------------------------------------
| 1  |  test   | 2010-11-12  | hoge  | valid  |
---------------------------------------------


しかし、もともとテーブルに含まれるものについては、Zend_Db_Selectを利用しているためか、SQL文が作成される際に、並び替えられていて、stateがどの位置にくるか分かりません。(ここが問題の原因となります。)
しかも、カラム名、カラム数が一致しているのでUNIONにもエラーがでません。

columnsを利用しなかったSQL文の取得結果が、

1
2
3
4
5
--------------------------------------------
| id | account | update_date | state | name | 
--------------------------------------------
| 3  |  test   | 2010-11-15  | valid  | aaaa  |
---------------------------------------------

という順番で取得された場合、UNIONの結果は、

1
2
3
4
5
6
7
--------------------------------------------
| id | account | update_date | state | name | 
--------------------------------------------
| 3  |  test   | 2010-11-12  | valid  | aaaa  |
---------------------------------------------
| 1  |  test   | 2010-11-15  | hoge  | valid  |
---------------------------------------------


となって取得されます。

項目名と違う値が入ってくるのです。今回は、互い違いになったのが数値と日付で、それをsumして合計値を取得してたために、全く予測できない値が取得されてしまいました。

解決策は、片方でcolumnsを使って、カラム名を追加した場合は、UNIONで結合するSQLは全て、同じカラム名は、columnsを使って追加する方法をとるということです。

今回の例だと。

1
2
3
4
5
6
7
8
9
10
11
12
13
$select1 = $adapter->select()
                   ->from(array("t1" => "hoge_table"), 
                          array("id", "account", "update_date"))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->columns(array("state" => "t1.state"))
                   ->where("t1.id = t2.account_id")
 
$select2 = $adapter->select()
                   ->from(array("t1" => "hogehoge_table"))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->columns(array("state" => new Zend_Db_Expr(0)));
 
$adapter->select()->union(array($select1, $select2))->query()->fetchAll();


と書くことです。または、columnsを使わない形で、このような書き方もできると思います。

1
2
3
4
5
6
7
8
9
10
11
12
$select1 = $adapter->select()
                   ->from(array("t1" => "hoge_table"))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->where("t1.id = t2.account_id")
 
$select2 = $adapter->select()
                   ->from(array("t1" => "hogehoge_table"), 
                          array("id", "account", "state" => new Zend_Db_Expr(0), "update_date")))
                   ->from(array("t2" => "hogehogehoge_table"), array("name"))
                   ->columns(array("state" => new Zend_Db_Expr(0)));
 
$adapter->select()->union(array($select1, $select2))->query()->fetchAll();


テーブルのカラム数が多いとcolumnsで後付した方が、記述量が少なくなるので、どちらを使うかはその時のテーブルによるかなと思います。重要なのはcolumnsの利用の有無を揃えること。


この説明、うまくやるの難しいですね。。。

wordpressのwp_headとwp_footer

wp_head()とwp_footer()というメソッド。
wordpressのコア部分のメソッドなのですが、恥ずかしながら今まで知りませんでした。

javascriptを利用したプラグインを利用するときは、これらは必須です。
今回、テンプレートにlightboxを導入する際に動ず、調べていたら、ここに行き着きました。

wp_headは、通常はwordpressのバージョン情報等をmetaタグで表示するくらいですが、wp_headが呼ばれたタイミングで、事前に登録したメソッドを呼び出せる機能ももっているのです。この機能を利用して、pluginの動作に必要なcssとかjavascriptとかの記述を行っているpluginが多いのです。
wp_footerも同様です。こちらはjavascriptの実行文を書いてあることが多いです。

今回使ってたテンプレートには、このどちらもなかったので wp-lightpopが動作しなかったというのが、動作不良の原因でした。

pluginによっては、jqueryを読み込んだり、prototype.jsを読み込んだりするので、バッティングして動作しなくなることもありますし、自前でjqueryを読み込んでたりする上に、wp_headでさらに読み込まれるとおかしくなることもあります。この辺は、試しながら調整する必要がどうしても出てきそうです。

add_action(‘wp_head’, ‘自作メソッド名’) で、処理追加
remove_action(‘wp_head’, ‘自作メソッド名’)で、処理削除

自分でプラグインを作成するときは、この辺は覚えておくと便利ですね。

htaccessでredirectする際に、パラメタ(query string)を引き継ぐ

wordpressを使うとき等に、htaccessにはお世話になってますが、以前$_GETをrewrite_condでひっかけて、redirect先へ引き継ごうとして、断念していました。
どうしても、正規表現でquery string(?key=valueの部分)がひっかけれなくて。

その時は無理矢理、http://test.com/key/value/の形式にリダイレクトして、プログラム側で、REQUEST_URIから、パラメタ名と、値を取得したんですが、今回いいものを見つけました。

それが、QSAオプション。Query Strins Appendの略です。
これをつけておくと、リダイレクトをかけても、そのままquery stringも引き継いでくれます。しかも、redirect時に、自分でquery stringを付け足しても、うまいこと後付してくれる賢さです。

http://www.hoge256.net/2008/04/119.html

サンプルはこんな感じ。

1
2
3
4
5
RewriteEngine On
 
RewriteCond %{REQUEST_URI} ^/test/
RewriteCond %{REQUEST_URI} !\.(js|ico|gif|jpg|png|css|html)$
RewriteRule ^(.*)$ / [P,L,QSA]

WordPress3.0にして変わったこと

wordpress3.0にアップグレードしたら挙動が変わった部分を発見したのでメモ。

wordpressの場合、category-xx.php (xxはカテゴリID)というテンプレートを作成していると、該当のカテゴリIDを指定して記事一覧画面を出す場合(http://hoge.com/?cat=xx など)に、優先的にIDまで名前に入ったテンプレートを選択してくれていた。

基本的には、3.0でも一緒だが、変わっていたのは、指定されたカテゴリIDに対応する記事が1件もなかった場合。2.9までは、記事がなくてもcategory-xx.phpが呼び出されていたが、3.0からは、index.phpが呼び出されるようになっていた。archive.phpも置いてみたけど、archive.phpではなくindex.phpが呼び出された。

カテゴリID指定のテンプレートはあまり作る機会は無いが、複数の指定カテゴリの記事一覧を表示するとき等に、架空のカテゴリIDを指定して、テンプレート内にて複数カテゴリIDを指定したり、特定カテゴリIDを除外した記事一覧を取得して表示したりしていた。

今後は、index.phpを使うってことで。架空のカテゴリIDを複数使いたい場合は、index.phpの中で、$_GETの中身を見て切り替えることになりそうです。

この挙動は、タグ指定とかでも一緒だと思われます。

ZendFrameworkを使ってBasic認証を行う

ZendFrameworkで構築したサイトの一部にbasic認証をかけたいけど、どうしたらできるか知ってる?と聞かれたのでやってみました。
考えたことなかったですが、.htaccess使うとindex.phpと同じ階層に置くことになって、サイト全体にしかかけれないのかもしれません。試してはないので推測です。

やりたかった内容は、特定のURLにbasic認証をかけて、認証NGな場合は他の画面を表示し、認証OKな場合は、そのまま指定されたURLの画面を表示するというものです。

サンプルソースは、以下になります。
今回は、controller内に全部書きました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    public function testAction()
    {
 
        $config = array(
            'accept_schemes'  => 'basic',    // basic認証指定
            'realm'           => 'aaaaa',    // realm(passwd.txtの内容と一致させる必要あり)
            'digest_domains'  => '/login/',  // このURL以下には全てbasic認証要
            'nonce_timeout'   => 3600
        );
 
        $resolver = new Zend_Auth_Adapter_Http_Resolver_File();
        $resolver->setFile('passwd.txt');  // index.phpがある階層と同じところに置いてます。
 
        $adapter  = new Zend_Auth_Adapter_Http($config);
        $adapter->setBasicResolver($resolver)
                ->setRequest($this->getRequest())
                ->setResponse($this->getResponse());
 
 
        $result = $adapter->authenticate();
        if (!$result->isValid()) {
            // 認証エラーの場合
            return $this->_forward('test1');
        }
 
        // 認証OK
    }



passwd.txtの中身はこちら

1
test:aaaaa:hogehoge


左から、アカウント、realm、パスワードです。パスワードは生パスワードでOKです。
realmは、はプログラム内で指定したものと一致する必要があります。
アカウントとrealmが一対となっていて、それに対してパスワードが存在するイメージです。

basic認証の画面は、authenticate()の部分で生成され、Zend_Controller_Response_Httpに設定されています。
authenticate()の部分で実行されるということは、認証画面が表示される際は、必ず “認証エラー” のルートを通ることになります。
なので、このルートを単なるエラールートと捉えない方がいいです。例えば、Exceptionをthrowしたりしたら、必ずthrowされます。

あと、はまった点が1つありました。”認証エラー”のルートに $this->_redirect()を利用すると、期待する動きはしません。
basic認証画面の出力より、リダイレクト処理が優先されてしまい、常にリダイレクトされることになります。
そのため、上記サンプルでは $this->_forward()を利用しています。これなら、認証画面にてキャンセルを押した場合にforward先の画面が出力されます。

Zendのソースを見つつ、認証画面にてキャンセルを押された場合を検出しようとしたんですが、判別の方法がわかりませんでした。
認証画面をキャンセルした際に、サーバ側にリクエストがきてないようだったので、サーバ側で判別するのは無理と判断しました。
今回は、Responseにbasic認証の情報と、forwardの情報を両方設定し、basic認証がキャンセルされたら、forwardが実行される形になりました。

wordpressにyoutubeとかをはれるようにするプラグイン

こちらからダウンロードできます。
http://blog.embed.ly/embedly-wordpress-plugin
http://wordpress.org/extend/plugins/embedly/stats/

http://api.embed.ly/
このAPIを利用したプラグインのようなので、対応サービスもこれだけあって、大概のものは利用できそうで、いいですね。

サイトで利用されているツールがわかるfirefoxのアドオン

twitterのタイムラインを見てて発見した、このアドオン。
サイトで使わているツールやCMSが何かを表示してくれます。

僕のサイトを見ると、google analyticsとwordpressのアイコンが出ました。
wordpressでここまでできるんだとか、そういう発見ができそうです。

インストールはこちらからどうぞ。
http://wappalyzer.com/

情報元はこちらです。
http://twitter.com/evian/statuses/15088794173

chromeにも同様のものがあるようです。
アドオンはあまり利用しないので、今まで知りませんでした。便利ですね。

iPadのDJアプリ

iPadの画面の広さがあれば、より本格的なDJアプリが作成されそうだなと思ってたんですが、すでにありました。



スクラッチとかもできているのがすごい。
多少ラグはあるだろうけど、この程度に収まっているのはすごいなと思います。

4つ打ちのDJアプリをやるなら、ピチコンをもっと大きくして操作性を上げて、インタフェースもターンテーブルよりもCDJにして、キューの位置とか決めれるようにして、波形とかだせちゃったらいいだろうなー。

そのうち誰かが作ってくれることに期待。

Zendを使ってZip圧縮

ZendFramework使って、ディレクトリのzipってできますか?
と聞かれたので調べたらでてきた。しかも、filterのところで。

filterは、validateが不正データを検出するのに対して、フィルタリングするってイメージで、入力チェックのイメージが強かったから意外だった。

filterを通すことで、データを変換するってイメージならファイル圧縮がfilterにあるのも納得できる。あー、なるほどねーって思わされた。

使い方は、こんな感じ。

1
2
3
$filter = new Zend_Filter_Compress('Zip');
$filter->setArchive(作成したい圧縮ファイルのパス付ファイル名);
$filter->filter(圧縮したいファイルのパス付ファイル名);



他にもこんな書き方もできそう。

1
2
3
4
5
$filter = new Zend_Filter_Compress(array(
     'adapter' => 'Zip', 
     'options' => array('archive' => '作成したい圧縮ファイルのパス付ファイル名')
));
$filter->filter(圧縮したいファイルのパス付ファイル名);



中身は、ZipArchiveクラス使ってました。

%d人のブロガーが「いいね」をつけました。