という話

技術ブログにしたい

FuelPHPで全てのコントローラーにフィルタをかける

全部のコントローラーで決まった処理、例えば認証処理とかを行いたい場合、Symfonyみたいな全部のコントローラーにかかるフィルタが欲しいところですが、用意されてないようです(見つけられてないだけかも)

なので今までずっと、それぞれのコントローラーにbefore(),after()メソッドを書いていたんですが公式ドキュメントをちゃんと読んだら解決できました。

ベースコントローラー

コントローラ - 概要 - FuelPHP ドキュメント

<?php
class Controller_Public extends Controller_Template
{
  public function before()
  {
    parent::before();

    // 認証処理などの共通処理を記述
  }

  public function after($response)
  {
    $response = parent::after($response); 

    // アクション実行後に行いたい共通処理を記述
    return $response;
  }
}

こんな感じで共通処理だけを記述したベースとなるコントローラーを作成します。
そして共通処理を行いたいコントローラーに継承させます。

<?php
class Controller_Top extends Controller_Public
{
  public function before()
  {
    parent::before();
  }

  public function after($response)
  {
    $response = parent::after($response); 
    return $response;
  }

  public function action_index()
  {
     // 処理
  }
}


Controller_Publicを継承することで、毎回before()メソッドなどに処理を書かなくてよくなります。
今回はベースコントローラーをController_Templateを継承して作成しましたが、Controller_HybridでやればTemplateもRestも対応できます。


ちゃんとドキュメント読まなきゃダメですね

FuelPHPで画像圧縮と圧縮率

webページの表示速度を上げるうえで必ずネックになる画像。
圧縮するとどのくらい変わるものなのか調査してみました。

FuelPHPで画像圧縮

いつもどおりFuelPHPです

$filepath = 'image.jpg';
Image::forge(array('quality' => 90))->load($filepath)->output();

Image::forgeメソッドに配列でqualityキーと値を渡します。
qualityが90%になるように?圧縮してくれます。

圧縮率

元画像が307KBでした。
クオリティ90%で110KB
80%で75KB
70%で60KB
60%で51KB
50%で45KB
40%で39KB
30%で33KB
20%で25KB
10%で17KB

と、なりました。
90%の時点で約3分の1にまで小さくなるでの非常に有効ですね。

勿論画像自体も汚くなるのですが、僕の見た限りでは70%くらいまでは余裕で使えるなーという感じでした。
参考画像を上げれなくて申し訳ないです。

圧縮の不思議

JPGは圧縮すると素直に容量も小さくなったのですが、PNGは圧縮すると逆に容量が大きくなりました。
またGIFはほぼ変わりませんでした。

GDのせいなのか、はたまたPNG,GIFアルゴリズムのせいなのかは分かりません。
webで使われてるのは圧倒的にJPGが多いので、JPGだけ圧縮するようにして対応してます。

Chromeで日本語変換中の文字色が変わる時の対処

Chromeアップデートしたら日本語変換中に文字が消えてしまい、調査した結果。


Chromeのバージョン36から変換中の文字に、選択時の文字色CSSが反映されるようになったみたいです。
つまり日本語変換中に文字色が変わる場合は::selectionでcolorなどを弄ってるはずなので、そこを削除すればなおります。

::selection {
  background-color: #999;
  color: #fff;
}
::-moz-selection {
  background-color: #999;
  color: #fff;
}

僕はこんな感じで指定していたので変換中は文字色が白になってしまい、あたかも消えたようになって見えたのでした。

::selection {
  background-color: #999;
}
::-moz-selection {
  background-color: #999;
}


こうすることで直りました。
が、テキスト選択中の色が普通のままなので見づらくなりました。対策方法は見当たりません。


変換中の文字に選択中のCSSを当てるのはいいとして、何故文字色だけにしたんでしょう。

日本語ドメインからfile_get_contentsを使ってHTMLを取得する

file_get_contentsって日本語ドメインに対応してないので、

$url = 'http://日本語.jp/';
$html = file_get_contents($url);
echo $html;

とかやろうとすると

PHP Warning:  file_get_contents(http://日本語.jp/): failed to open stream: php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known in nihongo_domain.php on line 2

とか出て怒られます。

punycode

日本語ドメインってpunycodeという、普通のURLと同じような半角英数で出来たURLに変換されるようです。

日本語.jpだと
http://xn--wgv71a119e.jp/
というURLに変換されます。

このURLならfile_get_contentsでも取得できそうです。

日本語ドメインpunycodeに変換する

PHP標準ライブラリでは変換出来ないのでPEARのライブラリを使います。

sudo pear channel-update pear.php.net
sudo pear install Net_IDNA2-0.1.1

PHPで日本語ドメインを扱う方法(Punycode変換)
ここを参考にしてやってたんですが、

Non-static method NET_IDNA2::getInstance() should not be called statically.

ってエラーが出たのでちょっと変えてこうします

require_once 'Net/IDNA2.php';

$idna = new Net_IDNA2();
$idna_instance = $idna->getInstance();

$url = 'http://日本語.jp/';
$encoded_url = $idna_instance->encode($url);

$html = file_get_contents($url);
echo $html;

これで日本語ドメインpunycode変換してfile_get_contentsでhtmlを取得できます

HTML5で背面カメラを取得する

HTML5が世に出て久しく立ちますがあまりカメラを使ったサービスって見ないですね。
ピントが合わせることが出来なかったり対応してるブラウザが少ないのが原因だと思いますが。。。

HTML5 カメラ」とかで検索するとgetUserMediaを使ってカメラ映像を取得しよう!みたいな記事が多いんですが、スマホなどで2つ以上カメラがある場合どちらか一方(ほとんどが内側カメラ)しか取得出来ないんですね。

なので背面カメラを取得したいと思います。

MediaStreamTrack

端末にあるカメラとかマイクの一覧を取得するAPIとしてMediaStreamTrackというものがあります。
MediaStreamTrack.getSourcesというAPIを使用するとカメラやマイクのIDを取得することが出来ます。

MediaStreamTrack.getSources(function(data)
{
  console.log(data);
});

という感じで呼び出すと、対応したブラウザでかつカメラやマイクがあるならコンソールに以下の様な感じで吐き出されます。

0: SourceInfo
  facing: ""
  id: "bf9f10e6cf64b14a4c5b544ccda64932e9565706316e78c2f97864ed2fd0338a"
  kind: "audio"
  label: ""
1: SourceInfo
  facing: ""
  id: "b65d00ea51cf8ea7cd33c31fc0dfc7e08ae7ee6b89b55b21d9454bf43efc16b7"
  kind: "audio"
  label: ""
2: SourceInfo
  facing: ""
  id: "3d75291cbeaffcdd1907f3fb9ec933c1846991f74795f02ad7ac72201b06f186"
  kind: "video"
  label: ""

これはMacbookAirでやった場合です。
このidがマイクやカメラへアクセスするときに必要になります。

背面カメラを取得する

getUserMediaで{video:true}みたいな感じでカメラを取得すると端末のデフォルト?のカメラが勝手に取得されますが、先ほど取得したIDを変数などに保持しといて以下のようにすると、対象のカメラを取得できます

navigator.getUserMedia({
  video: {
    optional: [{sourceId: VIDEO_SOURCE_ID}]
  }
});

VIDEO_SOURCE_IDの部分を変更してください。
マイクも一緒に取りたい場合は以下のようにしてください。

audio: {
 optional: [{sourceId: AUDIO_SOURCE_ID}]
},
video: {
  optional: [{sourceId: VIDEO_SOURCE_ID}]
}

デモ

Androidの最新版Chromeなどで見てください。Android標準ブラウザは対応していません。
iPhoneはどのバージョンでも対応してません。
HTML5で背面カメラを取得する - 遊び場


参考

ここに書いてあることのほとんどはここを参考にしました。というかほぼ一緒です。
simpl/getusermedia/sources/js/main.js at master · samdutton/simpl · GitHub

日本語の文章が少ないので増えて欲しいところですねー