June 29, 2013

FuelPHPのArr::mergeとPHP標準関数のarray_mergeの違いメモ

メモです。

1次元な配列のマージ
$a1 = array(
    'name' => 'mamor',
    'age' => '16',
);
$a2 = array(
    'name' => 'mamoru otsuka',
    'age' => '20',
);
Arr::mergeとarray_merge、同じ結果です。
array(
    'name' => 'mamoru otsuka',
    'age' => '20',
);
多次元な配列のマージ
$a1 = array(
    'name' => 'mamor',
    'age' => '16',
    'detail' => array(
        'email' => 'mamor@example.com',
        'hobby' => 'sleeping',
        'love' => 'money',
    ),
);
$a2 = array(
    'name' => 'mamoru otsuka',
    'age' => '20',
    'detail' => array(
        'email' => 'mamoru.otsuka@example.com',
    ),
);
Arr::mergeは
array(
    'name' => 'mamoru otsuka',
    'age' => '20',
    'detail' => array(
        'email' => 'mamoru.otsuka@example.com',
        'hobby' => 'sleeping',
        'love' => 'money',
    ),
);
array_mergeは
array(
    'name' => 'mamoru otsuka',
    'age' => '20',
    'detail' => array(
        'email' => 'mamoru.otsuka@example.com',
    ),
);
になりました。

場合に応じて使い分けるのが良いと思います。

June 28, 2013

FuelPHPでWebPayのAPIを叩いてみる

先日、WebPayというサービスが正式リリースされました。
https://webpay.jp/

PayPalのようなクレジットカード決済の代行が出来るみたいです。PayPalのAPI周りは前々から調べてみたかったのですが、中々きっかけもなく、また、何処から手をつけるべきかも良くわからず、結局は触らずじまいのままでした。

対して、WebPayは日本発のサービスのようで、APIドキュメントが凄く見やすいです。
https://webpay.jp/docs/api/php

また、テスト環境も整備されているようで、PayPalと比べると敷居はかなり低い印象です。
https://webpay.jp/docs/introduction

試しに、FuelPHPでAPIを一つ叩いてみます。
https://webpay.jp/docs/api/php#charges

FuelPHP 1.6.1をインストールして composer install が完了している状態とします。

WebPayのPHP用ドキュメントにStripe PHPが必要。と書かれているので、インストールします。

FuelPHPのルートにあるcomposer.jsonのrequireに以下を追記して composer update します。
"stripe/stripe-php": "1.*"
Stripe PHP
https://github.com/stripe/stripe-php
http://packagist.org/packages/stripe/stripe-php

尚、Stripe PHPはstripeという海外サービス用のライブラリのようで、WebPayは、そのStripeのAPI仕様に準じている。という感じみたいです。
https://stripe.com/

どこかのコントローラに以下を書いてアクセスしてみます。ドキュメント丸コピですが。。。
// テスト用のAPIキーなはずです
Stripe::setApiKey("test_secret_eHn4TTgsGguBcW764a2KA8Yd");

// これをしないとAPIエンドポイントが前述のStripeに向いてしまうはずです
Stripe::$apiBase = "https://api.webpay.jp";

// APIを実行してみます
$charge = Stripe_Charge::create(array(
    "amount" => 400,
    "currency" => "jpy",
    "card" => array(
        "number" => "4242-4242-4242-4242",
        "exp_month" => "11",
        "exp_year" => "2014",
        "cvc" => "123",
        "name" => "KEI KUBO"
    ),
    "description" => "アイテムの購入"
));

// リターンを確認してみます
Debug::dump($charge);
(課金?)ID入りのStripe_Chargeオブジェクトが返ってきました。


P.S.
パッケージ化も考えたのですが、Stripe PHPに一通り揃っているので、たぶん、app側でアプリケーションの都合に応じたラップクラスを作るのが良いのかなーと、今のところは思います。

June 27, 2013

MAMPでYUI Compressorを使おうとしたらエラー

MAMPでYUI Compressorを使おうとしたら
Unable to load native library: libjava.jnilib
とエラーが出ました。

調べてみると、以下が見つかりました。
http://stackoverflow.com/questions/7650013/java-1-6-broken-when-called-by-background-symfony-task

/Applications/MAMP/Library/bin/envvars の以下の2行をコメントアウトしてMAMPを再起動すると、無事に動きました。
DYLD_LIBRARY_PATH="/Applications/MAMP/Library/lib:$DYLD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH

June 16, 2013

Bootstrapで簡単にコンファームダイアログを作る

Bootbox.jsを使うと、Bootstrapで簡単にコンファームダイアログを作れます。自作した場合とで必要なコード量の差は、公式サンプルを見れば一目瞭然です。
http://bootboxjs.com/


以下、サンプルです。


bootbox.min.jsをDLします。今回は、v3.2.0を用いました。
https://github.com/makeusabrew/bootbox

当然ですが、BootstrapもDLします。今回は、v2.3.2を用いました。
http://twitter.github.io/bootstrap/


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link type="text/css" rel="stylesheet" href="bootstrap/css/bootstrap.min.css" />
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
<script src="bootbox.min.js"></script>
</head>
<body>

<button id="confirm" class="btn">Confirm</button>

<script>
$('#confirm').click(function() {
    var confirm = bootbox.confirm('Are you sure?', function(result) {
        // OKならtrueに、Cancelならfalseになります
        console.log(result);
    });

    // Modal内の要素にも簡単にアクセスできます
    console.log(confirm.find('.btn-primary').text());
});
</script>

</body>
</html>
非常に簡単ですね。

Confirm以外にも
* Alert
* Prompt
* Custom Dialog
と用意されています。

JSDuckでJavaScriptのドキュメントを生成してみる

Backbone.jsのライブラリであるBackgrid.jsを調べていて、APIドキュメントを見てみると、右下に"Generated on Tue 07 May 2013 23:21:44 by JSDuck 4.8.0."とありました。
http://backgridjs.com/api/index.html

JSDuck
https://github.com/senchalabs/jsduck

というわけで、使い方のメモです。

1. インストール
gemでインストールするように書いてあります。
$ sudo gem install jsduck
2. Backgrid.jsのドキュメントを生成してみる
JSDuckを知る切っ掛けになったBackgrid.jsのドキュメントを、実際に作ってみます。
$ mkdir xxx #適当なディレクトリです。
$ cd xxx
$ mkdir docs #ここに生成してみます。
$ wget https://github.com/wyuenho/backgrid/archive/0.2.6.zip
$ unzip 0.2.6
$ jsduck backgrid-0.2.6/lib/ -o docs
なんかWarningが大量に出ましたが、docs/index.htmlにアクセスすると、それっぽいドキュメントが生成されていました。色々とオプションが有るようなので、確認せねば。

June 15, 2013

FuelPHPでWebSocketする(これまでの)まとめ

暫く放置してしまっていましたが、これまでに書いた、FuelPHPでWebSocketを扱うためのリンクや記事をまとめておきます。



以下、各公式サイトです。

FuelPHP
http://fuelphp.com/
* PHPのフレームワークです。

Ratchet
http://socketo.me/
* PHPでWebSocketを扱うことに特化したフレームワークです。

WAMP
http://wamp.ws/
* WebSocketのサブプロトコルです。詳しくは、後述の記事をご覧ください。



以下、いろいろと調べていく中で作成したソース等です。

fuel-packages-ratchet
https://github.com/mp-php/fuel-packages-ratchet
* FuelPHPでRatchetを扱うためのFuelPHP用パッケージです。

FuelPHP x Ratchet Demo
http://fuelratchet.madroom.org/
* デモサイトです。

fuel-ratchet-samples
https://github.com/mp-php/fuel-ratchet-samples
* デモサイトの基になっているソースです。



以下、当ブログの各記事です。書いた順に並べています。飽くまで、PHPでWebSocketを扱うための一例。としてご覧ください。

PHPでWebSocketを用いたチャットサンプル
http://madroom-project.blogspot.jp/2013/04/phpwebsocket.html
* Ratchetを一番最初に触った時の記事です。

FuelPHPでWebSocketを扱うパッケージを作りました
http://madroom-project.blogspot.jp/2013/04/fuelphpwebsocket.html
* Ratchet内でFuelPHPの機能を使えるようしてみました。

FuelPHP x Ratchetでulimit -nを指定して複数タブで開いてみる
http://madroom-project.blogspot.jp/2013/04/fuelphp-ratchetulimit-n.html
* Ratchetのドキュメントの実運用マニュアル的なページに記載されている内容を確認してみました。

UbuntuにLibeventをインストールしてみる
http://madroom-project.blogspot.jp/2013/04/ubuntulibevent.html
* Ratchetのドキュメントの実運用マニュアル的なページに記載されている内容を確認してみました。

FuelPHP x RatchetをNginx + Apacheで動かす
http://madroom-project.blogspot.jp/2013/04/fuelphp-x-ratchetnginx-apache.html
* ポート周りの調整をNginxでやってみました。

FuelPHP x RatchetをSupervisorで永続的に起動する
http://madroom-project.blogspot.jp/2013/04/fuelphp-x-ratchetsupervisor.html
* Ratchetのドキュメントの実運用マニュアル的なページに記載されている内容を確認してみました。

FuelPHP x Ratchetのサンプルを公開しました
http://madroom-project.blogspot.jp/2013/04/fuelphp-x-ratchet.html
* 前述のデモサイトについてです。

FuelPHP x Ratchet x Nginxでコネクションが勝手に切れる
http://madroom-project.blogspot.jp/2013/04/fuelphp-x-ratchet-x-nginx.html
* 記事にも書いていますが、Ratchetと言うよりはNginx側の話な気がしています。

WebSocketとWAMPとRatchetに関するメモ
http://madroom-project.blogspot.jp/2013/05/websocketwampratchet.html
* 前述のWAMPについてです。

FuelPHP x RatchetでWAMPのPubSubとRPCを試してみた
http://madroom-project.blogspot.jp/2013/05/fuelphp-x-ratchetwamppubsubrpc.html
* 実際にWAMPを確認してみました。

FuelPHP x RatchetのWAMPにタスクからメッセージを配信してみた
http://madroom-project.blogspot.jp/2013/05/fuelphp-x-ratchetwamp.html
* 実際にWAMPを確認してみました。

FuelPHP x RatchetでWAMPの機能確認サンプルを公開しました
http://madroom-project.blogspot.jp/2013/05/fuelphp-x-ratchetwamp_6.html
* 前述のデモサイトにWAMPネタを追加しました。

Ratchetのユニットテストを実行してみる(とりあえずPHPUnit側)
http://madroom-project.blogspot.jp/2013/05/ratchetphpunit.html
* Ratchetのサーバサイドに対するユニットテストを実行してみました。

Ratchetのユニットテストを実行してみる(AutobahnTestsuite側)
http://madroom-project.blogspot.jp/2013/05/ratchetautobahntestsuite.html
* Ratchetのクライアントサイドに対するユニットテストを実行してみました。



以下、FuelPHPやRatchetと直接な関係はありません。Androidネタです。

AndroidでWebSocket(WAMP)クライアントを作ってみた
* サーバサイドをFuelPHP x Ratchetで実装して、Androidアプリと連携。とかも出来るかもしれません。



P.S.
未解決な内容や、残件的な話も残っていますが、とりあえず、ここまでのまとめ(リンク集)記事ということで。

ざっと調べた中で、PHPでも結構、WebSocketなWEBアプリが出来るのかなーという印象を持ちました。WebSocketの範囲に限定すれば、Node.js + Socket.IOの情報が最も多く、Ratchetの情報は(少なくとも国内では)少ないです(たぶん)。ですが、WebSocketの為だけに慣れた言語を捨てるリスクはそれなりに大きいでしょうから、どっちもどっちなのかな。というのが今のところの感想です。

June 10, 2013

jquery-pjaxでリダイレクト

以前書いたタイトルの変更方法を改良して、リダイレクト処理を付け足してみます。

jquery-pjax後にHTMLのタイトルを変更する
http://madroom-project.blogspot.jp/2013/05/pjaxhtml.html

以下のように、'pjax:complete'イベント時に'x-pjax-redirect'を確認します。
$(document).on('pjax:complete', function(event, xhr) {
    if (xhr.getResponseHeader('x-pjax-redirect')) {
        $.pjax({url: xhr.getResponseHeader('x-pjax-redirect'), container: '#pjax'});
    } else if (xhr.getResponseHeader('x-pjax-title')) {
        $('title').text(xhr.getResponseHeader('x-pjax-title'));
    }
});
'x-pjax-redirect'は、PHPだったら
header('x-pjax-redirect: http://example.com');
exit(' ');
で出力します。exit()だとcontentのlengthが0になりますが、その場合、どうも失敗とみなされるようで、通常遷移してしまいました。なので、上記の形にしています。尚、'x-pjax-title'はリダイレクト先で出力される想定です。

June 7, 2013

FuelPHPで画像を選択、表示、範囲選択、アップロード、切り取った画像の表示を画面遷移なしでやる

そのままの流れで以下の続きを書いちゃいます。
http://madroom-project.blogspot.jp/2013/06/fuelphp.html

尚、動かすのに最低限な内容なので、アップロードされるファイルは画像が大前提だったり、トークンやアップロードされたファイルのチェック等は割愛していますm(_ _)m
(それでも結構長くなってしまいますね。。。)

--

Jcropをダウンロードします。
http://deepliquid.com/content/Jcrop.html

解凍したディレクトリを
public/assets/jcrop
として配置します。

コントローラは以下のようになります。

classes/controller/file.php
<?php

class Controller_File extends Controller
{
 
    public function action_index()
    {
        Asset::add_path('assets/jcrop/css/', 'css');
        Asset::add_path('assets/jcrop/js/', 'js');

        return Response::forge(View::forge('file/index'));
    }
 
    public function action_upload()
    {
        Upload::process(array('path' => APPPATH.'tmp'));
        Upload::save(0);

        $file = Upload::get_files(0);

        $path = APPPATH.'tmp/'.$file['saved_as'];

        $x = Input::post('x');
        $x2 = Input::post('x2');
        $y = Input::post('y');
        $y2 = Input::post('y2');

        Image::load($path)->crop($x, $y, $x2, $y2)->save($path);
        
        return $file['saved_as'];
    }

    public function action_image($file = null)
    {
        Image::load(APPPATH.'tmp/'.$file.'.'.Input::extension())->output();
    }

}
ビューは以下のようになります。

views/file/index.php
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<?php echo Asset::css('jquery.Jcrop.min.css'); ?>
<?php echo Asset::js('jquery.Jcrop.min.js'); ?>
</head>
<body>
     
<input id="file" type="file" />
<button id="upload" disabled="disabled">Upload</button>
<img id="selected_img" />
<img id="uploaded_img" />

<script>
var file;
var img = $('#selected_img');
var coordinate;

$('#file').change(function(e) {
    file = e.target.files[0];

    var fileReader = new FileReader();

    fileReader.readAsDataURL(file);

    fileReader.onload = function(e) {
        img.attr('src', e.target.result);

        img.Jcrop({
            onSelect: function(c) {
                coordinate = c;
                $('#upload').attr('disabled', false);
            }
        });
    };
});
$("#upload").click(function() {
    $(this).attr('disabled', true);
 
    var formData = new FormData();
    formData.append('file', file);
    formData.append('x', coordinate.x);
    formData.append('x2', coordinate.x2);
    formData.append('y', coordinate.y);
    formData.append('y2', coordinate.y2);

    $.ajax({
        url: '<?php echo Uri::create('/file/upload'); ?>',
        type: 'post',
        data: formData,
        processData: false,
        contentType: false,
        success: function(file) {
            $('#uploaded_img').attr('src', '<?php echo Uri::create('file/image/'); ?>' + file);
        }
    });
});
</script>
 
</body>
</html>

* JS: 画像を選択後、選択した画像が表示されます。
* JS: 画像の範囲選択をすると、アップロードボタンが押せるようになります。
* JS: アップロードボタンを押すと、非同期で画像をアップロードします。
* PHP: FuelPHP側で切り取って保存、ファイル名を返します。
* JS: 返されたファイル名から画像を表示します。

P.S.
IE9では動かないらしいです。(確認はしてないです。)その他、ブラウザによって動かない可能性は否定出来ません。(Chromeで確認しています。)

あと、input type fileにはBootstrapのデザインは当たりません。デザインするなら、以下のように、input type fileは非表示にしつつ、別のボタンでclickイベントを発生させる必要があります。
<input id="file" type="file" name="xxx" style="display: none;" />
<button class="btn" onclick="$('#file').click();" type="button">Change image</button>

June 6, 2013

FuelPHPで非同期ファイルアップロード

追記:
続き書きました。
FuelPHPで画像を選択、表示、範囲選択、アップロード、切り取った画像の表示を画面遷移なしでやる
http://madroom-project.blogspot.jp/2013/06/httpmadroom-project.html

--

今回はFuelPHPはあまり関係ありませんが、続きとして書く(予定)の記事で関係するので。。。

コントローラとビューを用意します。

classes/controller/file.php
<?php

class Controller_File extends Controller
{

    public function action_index()
    {
        return Response::forge(View::forge('file/index'));
    }

    public function action_upload()
    {
        // TODO: 実際にはtokenも送信してチェックすべき
        return print_r($_FILES, true);
    }
}
views/file/index.php
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
    
<input id="file" type="file" />
<button id="upload" disabled="disabled">Upload</button>

<script>
var file;
$('#file').change(function(e) {
    file = e.target.files[0];
    $('#upload').attr('disabled', false);
});
$("#upload").click(function() {
    $(this).attr('disabled', true);

    var formData = new FormData();
    formData.append('file', file);

    $.ajax({
        url: '<?php echo Uri::create('/file/upload'); ?>',
        type: 'post',
        data: formData,
        processData: false,
        contentType: false,
        success: function(res) {
            console.log(res);
        }
    });
});
</script>

</body>
</html>
試しにファイルを選択してアップロードボタンを押してコンソールを確認すると
非同期にアップロードされているのがわかります。

冒頭で書いた"続き"は
* 選択したファイル(画像)を表示
* 切り取る(範囲選択する)
* アップロードボタンを押す
* FuelPHP側で選択範囲で切り取って表示
みたいな内容(のはず)です。


P.S.
上記の内容はWin/MacのChromeで確認しています。IE9では動かないっぽいです。