FuelPHP復習 その6

windowsのxampp環境で開発していて、セッションが使えなかった。
セッションに格納した値を、遷移先で取り出そうとすると
取り出せない。
configでfile指定してる状態なので、この状態だと
セッションがファイルで吐き出されるけど
Session::set(); するとセッションファイルがひとつ生成されて
Session::get(); するとなぜかセッションファイルがまた生成される。

で、ググったらセッションファイルが複数生成されるとかまさにこれだった。
https://curecode.jp/tech/fuelphp-1-8-file-session-does-not-work-on-windows/

公式のTOPで1.8を拾ってきたので現象が発生して、
1.8.0.1で修正済みってことは、公式からダウンロードできるのは1.8.0.0の可能性がある。
…んだけど確認できないんだよね。
fuelphp-1.8\fuel\core\classes\fuel.phpの中身を見ると
> const VERSION = '1.8';

で、1.8系の最新版の1.8.0.4を拾ってきてcoreフォルダ入れ替えたんだけど
https://github.com/fuel/core/tree/1.8.0.4
fuelphp-1.8\fuel\core\classes\fuel.phpの中身を見ても
> const VERSION = '1.8';

だから、どのバージョンか詳細が確認できないんだよねこれ…。
まあ入れ替えたら直ったから良いけど、
これからFuelPHP1.8系を始める人で(いないと思うけど)
公式から落としたら、すぐにバージョンを1.8.0.1以降に差し替えると良いです。

FuelPHP復習 その5

ここからは躓いたポイントになるなあ…

・DBの接続設定
phpMyAdminでユーザーを作る
app/config/db.phpに共通設定を書く

return array(
    'default' => array(
        'type'           => 'mysqli',
        'connection'     => array(
            'persistent'     => false,
        ),
        'identifier'   => '`',
        'table_prefix'   => '',
        'charset'        => 'utf8',
        'collation'      => false,
        'enable_cache'   => true,
        'profiling'      => false,
        'readonly'       => false,
    ),
);

app/config/development/db.phpに開発環境用の接続設定を書く

return array(
    'default' => array(
        'connection' => array(
            'hostname' => 'localhost',
            'port' => '3306',
            'database' => '【作ったDB名】',
            'username' => '【作ったユーザー名】',
            'password' => '【ユーザーに設定したパスワード】',
        ),
        'profiling' => true,
    ),
);


sql実行するとDBにつながらない
phpMyAdminでユーザ作成時にホストがデフォルトだと%なので
ちゃんとホストをlocalhostに指定して作り直す


・INSERTクエリがエラーになる
さっきの設定にあった「identifier」がクオート文字列らしく、
「`」を使う必要があったのに「'」を使っていたので
正常に認識されていなかった。
(例) ( 'column_name' ) みたいなやつ


MariaDBに登録した全角文字が「?????」とか化ける
phpMyAdminのテーブルとDBの両方の照合順序を、utf8_general_ciにする
デフォルトだとlatin1とか。テーブルだけじゃなく、DBも設定を直す必要あり


・DBから結果の取得方法がバラバラ
selectだと
$result = $query->execute()->as_array();
insertだと
$result = $query->execute();
(as_array()が付いてるとエラーになる)
update,deleteは未確認

FuelPHP復習 その4

・Viewの共通パーツを共通化
ヘッダとかフッタとかCSS定義とかサイドメニューを
今回は以下のようにファイル分け。
views/header.php
views/footer.php
views/style.php
views/sidemenu.php

各画面のViewファイル内では、必要な箇所に以下のように記述することで
いろんなViewに同じコードを書くことを防ぐ。

<?= View::forge('header') ?>
<?= View::forge('footer') ?>
<?= View::forge('style') ?>
<?= View::forge('sidemenu') ?>

そもそもテンプレートの大枠を用意して
コンテンツ部分だけ各ファイルに書ければ一番なんだけど
Smartyでも入れたほうが良いのかなこれは

FuelPHP復習 その3

・新規画面を作成する場合
以下の3つが不足してないか、クラス名は適切に設定しているか確認する
(1)controller
 画面1つ置きに作るわけではないので、既存のを流用する場合は不要。
 URL構造と直結するのでURLこだわるなら名前付けに気をつける。
(2)presenter
 旧viewmodel? 現段階だと勉強不足で用途不明。
 Response::forgeにPresenter::を指定せずView::指定なら不要。
(3)view
 html生成するためのファイル。


・カレンダーの作成
ライブラリだと自動生成してしまい
日毎にイベントの有無を後から仕込む方法を調べるのが大変そうなので
シンプルな以下のサイトのをベースに、改造していく
http://fuweb.info/278
というか関数にしてしまう


・カレンダーのデザイン
前後の月に移動したり、当月に戻ったりするデザインが欲しいので
<>today辺りは以下を参考にする予定
https://fullcalendar.io/


・サイドメニュー
bootstrapにあるのかなと思ったら実はなさそうなので
以下のサイドメニューを参考に作成する。
http://qiita.com/zaburo/items/e5b8c51873b193bb1573
グリッドスタイルのleft-center-rightが3:6:3になっているが
今回はrightは不要なので、right要素を除去して
left:center = 3:9 に割合を変更する

FuelPHP復習 その2

・bootstrapテンプレートを適用
 デフォルトで入ってるので、変えたい場合は
 拾ってきて上書き
 public/assets/css や js や fontsが対象


・サンプルページを用意
 Helloページ辺りの内容をbootstrapテンプレートの
 デモページの内容に差し替えて、想定どおり表示されるか確認


jQueryの導入
 デフォルトで入ってないため、~.min.jsファイルを拾ってきて
 public/assets/js に置く

<?php echo Asset::js('jquery-3.2.1.min.js'); /*jQuery*/ ?>
<?php echo Asset::js('bootstrap.min.js'); /*bootstrap*/ ?>

 のようにbody閉じタグ直前に書いて、特に構文エラーにならないことを確認

FuelPHP復習 その1

公開を視野に入れつつ、とりあえずLocalで動かせたら良い程度の想定。
全然覚えてないので1から学習とほぼ同じ状態。
まずは土台構築。

環境: XAMPP 7.1.8(PHP)
DB : MariaDB 10.1.26
言語: PHP 7.1.8
FW : FuelPHP 1.8
IDE : NetBeans 8.2

・xamppインストール

・xamppコンパネ起動
 ApacheMySQLをstart

FuelPHPを導入
 C:\xampp\fuelphp-1.8 辺りに解凍して手動で導入

Apacheのドキュメントルート変更
 C:\xampp\Apache\conf\httpd.confの C:\xampp\htdocs 2箇所を
 C:\xampp\fuelphp-1.8\public に変更

・動作確認
 http://localhost/ にアクセスして、FuelPHPのTOPページが出ればとりあえず成功

・mySqlAdminの起動
 xamppコンパネのMySQLのAdminを押すとブラウザで開く

・DB、テーブル作成
 mySqlAdmin上でDB作成
 テーブル作成

IDEからFuelPHPのプロジェクトを開く
 C:\xampp\fuelphp-1.8 を指定

FuelPHPにてcurlでAPIにXML形式などで投げる方法

使い方を勘違いしてドハマりしたので、備忘録として残します。


今回動きを確認した環境



まずはXML形式ではなく、通常のパラメータで渡すやり方から。


curlを用いてPOSTでパラメータを普通にAPI等に渡す方法



(1) 通常のPHPの関数のみで実現するパターン
参考にしたサイト: http://php.net/manual/ja/book.curl.php#116122

<?php
$ch   = curl_init('http://localhost/request/api');
$params = array('userid' => 12,
                'data'   => 'sample');
curl_setopt($ch, CURLOPT_POSTFIELDS,     http_build_query($params));
curl_setopt($ch, CURLOPT_POST,           true);
curl_setopt($ch, CURLOPT_TIMEOUT,        30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    // responseのstring化
$response = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
    $array_body = get_object_vars(simplexml_load_string($response));
    var_dump($array_body);
}
curl_close($ch);



(2) FuelPHPの関数を利用して実現するパターン
参考にしたサイト: http://qiita.com/uchiko/items/3cec115db0b99a25d089

<?php
$curl   = Request::forge('http://localhost/request/api', 'curl');
$params = array('userid' => 12,
                'data'   => 'sample');
$curl->set_params($params);
$curl->set_method('post');
$curl->set_option(CURLOPT_TIMEOUT, 30);
$response = $curl->execute()->response();
if ($response->status == 200) {
    $array_body = Format::forge($response->body(), 'xml')->to_array();
    var_dump($array_body);
}



ここまではまあ普通の方法なので、頑張ってぐぐればいけるはず。
で、本題は次の、パラメータをXML形式とかにして渡すやり方。


curlを用いてPOSTでパラメータをXML形式でAPI等に渡す方法



(3) 通常のPHPの関数のみで実現するパターン
参考にしたサイト: http://hydrocul.github.io/wiki/blog/2013/1111-php-post-curl.html

<?php
$ch = curl_init('http://localhost/request/api');
$xml  = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL
      . '<base_node><userid>12</userid><data>sample</data></base_node>';
curl_setopt($ch, CURLOPT_POSTFIELDS,     $xml);
curl_setopt($ch, CURLOPT_POST,           true);
curl_setopt($ch, CURLOPT_TIMEOUT,        30);
curl_setopt($ch, CURLOPT_HTTPHEADER,     array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    // responseのstring化
$response = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
    $array_body = get_object_vars(simplexml_load_string($response));
    var_dump($array_body);
}
curl_close($ch);



(4) FuelPHPの関数を利用して実現するパターン
参考にしたサイト: http://fuelphp.jp/docs/1.7/classes/request/curl.html

<?php
$curl   = Request::forge('http://localhost/request/api', 'curl');
$params = array('userid' => 12,
                'data'   => 'sample');
$params = array('base_node' => $params);    // XMLの大外の要素を用意
$curl->set_params($params);
$curl->set_method('post');
$curl->set_option(CURLOPT_TIMEOUT, 30);
$curl->set_header('Content-Type', 'text/xml');   // 第一引数の文字の大小はこれを厳守
$response = $curl->execute()->response();
if ($response->status == 200) {
    $array_body = Format::forge($response->body(), 'xml')->to_array();
    var_dump($array_body);
}



こんな感じでした。
FuelPHPのcoreクラスの関数を使う場合の注意点は以下の2点です。

  • POSTで投げる場合、set_paramsにXMLの内容を配列で渡す
  • set_headerにContent-Typeとして'text/xml'や'application/xml'を指定



あとこの記事ではXML形式で送信することをメインに書いていますが、コンテンツタイプの指定によってはxmlの他にjsoncsvやserialize(?)での送信にも対応しているようです。(動かして確認まではしてないが、$auto_detect_formatsにそれらのフォーマットの用意もあるので、詳しくはRequest_Driverクラス参照)


余談1:パラメータをXMLで送ろうとしてドハマりした際の手順(失敗例)

(5) FuelPHPの関数を利用したがXMLの中身が消えているNGパターン

<?php
$curl   = Request::forge('http://localhost/request/api', 'curl');
$params = array('userid' => 12,
                'data'   => 'sample');
$xml = Format::forge($params)->to_xml(null, null, 'base_node');
// $curl->set_params($params);
$curl->set_method('post');
$curl->set_options(array(CURLOPT_TIMEOUT    => 30,
                         CURLOPT_POSTFIELDS => $xml));
$curl->set_header('Content-Type', 'text/xml');
$response = $curl->execute()->response();
if ($response->status == 200) {
    $array_body = Format::forge($response->body(), 'xml')->to_array();
    var_dump($array_body);
}



このパターンが何がいけなかったかというと、以下の点です。

  • POSTメソッドで送信しようとしている
  • set_paramsではなく、curlのoptionとしてCURLOPT_POSTFIELDSにxml文字列を渡していた
  • set_paramsは未設定の状態

この条件が重なると、送信直前に空のパラメータでCURLOPT_POSTFIELDSの要素が上書きされます。
そのため、送信されるXMLは想定していた

<?xml version="1.0" encoding="utf-8"?>
<base_node><userid>12</userid><data>sample</data></base_node>

ではなく、2行目が空になった状態の

<?xml version="1.0" encoding="utf-8"?>
<xml/>

になります。


なぜ2行目の情報が消えるかは、FuelPHPのcoreクラスの使い方が間違っていたからです。
FuelPHPのcoreフォルダ内にあるcoreクラスのうち、Request_Curlクラスのexecuteメソッドを見ると、送信methodの指定がある場合は

<?php
if ( ! empty($this->method))
{
	$this->options[CURLOPT_CUSTOMREQUEST] = $this->method;
	$this->{'method_'.strtolower($this->method)}();
}

により、Request_Curlクラスの method_xxxメソッドが呼び出されます。
POST指定時はmethod_postメソッドが呼ばれるため、以下の内容になります。

<?php
protected function method_post()
{
	$params = is_array($this->params) ? $this->encode($this->params) : $this->params;

	$this->set_option(CURLOPT_POST, true);
	$this->set_option(CURLOPT_POSTFIELDS, $params);
}

最初の行で、headerのContent-Typeに応じた形式にパラメータをエンコードしていますが、set_params未実施の場合はパラメータは空の配列のため、$params内には2行のXMLの文字列で用意され、そのうち2行目の内容は既に以下のようになっています。

<xml/>

method_postメソッドの最後の行ではset_optionにてCURLOPT_POSTFIELDSにparamsの内容をセット(上書き)しています。
set_optionsにてCURLOPT_POSTFIELDSに入れていたパラメータは、ここで消えていることになります。
さらに処理を追いかけると、method_postを実施後かつcurl_execを実行する前に

curl_setopt_array($connection, $this->options);

にてoptionsの内容がcurlハンドラに実際にセットされますが、既に空の配列を元にした内容でCURLOPT_POSTFIELDSの内容は上書き済みのため、最初にセットしたxmlの情報が消えていました、というオチです。


この辺りはFuelPHP側がこのように使うことを想定した作りになっているため、想定通りに関数を正しく利用すれば問題にはなりません。
ただ、公式ドキュメントにもあまりこういう詳細な使い方は載っていなかったのと、ぐぐってもその辺りの情報に巡り合えなかったので、記事として残しておきます。(このパターンに嵌る人もあまりいないとは思いますが…)
まあ良く分からなかったらFuelPHPのcoreクラスのソースを読めば何とかなるでしょう。たぶん。

(6) 送信内容の確認用ソース
上記のサンプルソースのリクエスト先URLの「http://localhost/request/api」は、Windows環境のLocalに入れたXAMPPとFuelPHPのcontrollerの組み合わせで、apacheのドキュメントルートにFuelPHPのソースのpublicを指定し、XMLで送られた内容とパラメータで送られた内容をデバッグでログ出力するのと、レスポンスに適当なXMLを返しているだけの以下のようなザックリとした内容を用意して確認してました。

<?php
class Controller_Request extends Controller {
    function action_api() {
        Log::debug(file_get_contents('php://input'));
        Log::debug(print_r($_POST, true));

        $response = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL
                  . '<base_node>'
                  .   '<foo>bar</foo>'
                  .   '<hoge>piyo</hoge>'
                  . '</base_node>';
        echo $response;
    }
}



余談2:はてなブログシンタックスハイライトについて


なんかPHPを指定しても、はてなブログ上でハイライトされなくて悲しすぎた。
この記事のPHPソースはjavascriptを指定して無理やりハイライトしてます。
調べたら他の言語は対応してるけどPHPはダメみたい。
(参考: http://mpon.hatenablog.com/entry/2014/12/10/000712 )
公式ヘルプ見るとphp載ってるんだけど、
(参考: http://help.hatenablog.com/entry/markup/syntaxhighlight )
使い方が間違ってるとか? でも他の言語指定する場合は動くので理屈が通らん。
はてなの中の人はPHPだけ超絶嫌いなんかな…。



2/12 追記:
コメントにて情報いただきました、ありがとうございます。
PHPの場合は、

<?php

のようにPHP開始タグがコードブロックに含まれていればハイライトが反映されるそうです。
本記事の上の方もその形式でコード部分を修正しました。