信頼はずっと、挑戦はもっと。

お問い合わせ
TEL:03-3496-3888

BLOG コアテックの社員ブログ (毎週月曜~金曜更新中)

LIST OF ARTICLES

記事一覧

  • テクログ

    Laravel4 で特定のIPアドレスからのアクセスを許可するメンテナンスモードパッケージを作りました。

    Laravel4 には標準でメンテナンスモードが用意されています。 $ php artisan down # メンテナンスモードに入ります $ php artisan up # メンテナンスモードを解除します このメンテナンスモードは、storage/meta/down という空ファイルの存在のみが基準なので、メンテナンスモード中は社内からのアクセスも出来なくなります。メンテナンスモードでソースの更新やDBのマイグレーションを行い、社内からアクセスして確認後、メンテナンスモードを解除。というフローは、現バージョン(4.0.5)では無理です。 今回、Laravel4 のパッケージ作成方法の調査がてら、特定のIPアドレスからのアクセスを許すメンテナンスモードパッケージを作成しました。 https://github.com/core-tech/laravel-packages-exdown https://packagist.org/packages/core-tech/exdown 以下、パッケージの作成方法と、作成したパッケージのインストール方法です。 パッケージの作成方法 作成したパッケージを使いたいだけであれば、読み飛ばして頂いて構いません。 以下、Laravel4 のプロジェクトルートに居ることとします。 composer コマンドにパスが通っていなければ、通します。実行権限も与えておきます。以下はMacでの例です。OS毎の差異等は調整して下さい。 $ sudo cp composer.phar /usr/bin/composer $ sudo chmod +x /usr/bin/composer app/config/workbench.php の name と email を変更しておきます。name は必須です。この値はパッケージ用に自動生成される composer.json で使われます。 artisan workbench でパッケージの雛形を生成します。 $ php artisan workbench core-tech/exdown --resources Package workbench created! resources オプションをつけることで、以下も併せて作成されます。 public src/config src/lang src/migrations src/views app/config/app.php の providers に CoreTechExdownExdownServiceProvider を追加します。 ブラウザから適当にアクセスして何のエラーも出なければOKです。 ExdownServiceProvider に対する not found のエラーが出たならどこかで失敗しています。 ExdownServiceProvider に到達しているか確認してみます。 /**  * Register the service provider.  *  * @return void  */ public function register() { dd('test'); } ブラウザからアクセスすると、到達していました。 作成したパッケージのインストール方法 composer.json の require に 以下を追加して update します。 "core-tech/exdown": "dev-master" app/config/app.php の providers に CoreTechExdownExdownServiceProvider を追加します。メンテナンスモード判定パッケージなので、先頭に追加するのが良いと思います。 以下のコマンドで config ファイルを app 下にコピーします。 $ php artisan config:publish core-tech/exdown config ファイルの "allowed_ips" は許可するIPアドレス一覧です。 config ファイルの "view" は使用する view ファイル名です。 パッケージの config を環境毎に設定したい場合は、ヤマジュンの記事 を参考にして下さい。 以下でメンテナンスモードになります。 $ php artisan exdown 以下でメンテナンスモードが解除されます。 $ php artisan exup
  • テクログ

    Laravel4のパッケージ調査

    前回は、FuelPHP の Sentry パッケージを作りましたが、 今回は、Laravel4 のパッケージについて調査してみました。 なお、以下の調査内容については、不備があるかもしれませんので 参考程度にして頂ければと思います。 パッケージの環境毎の設定ファイル 通常、環境毎の設定ファイルは app/config/【環境】に配置しますが、 パッケージの場合は、下記のコマンドにより app/config/packages/【vendor名】/【package名】 に配置されます。 php artisan config:publish 【vendor名】/【package名】 環境毎にパッケージの設定ファイルを配置する場合は、 app/config/packages/【vendor名】/【package名】 /【環境】に配置します。 プロファイラパッケージ 先月末にリリースされた Laravel4 ですが、 Laravel3 にありましたプロファイラがインストール時にありませんでした。 Packagist にいくつか登録されている Laravel4 でも使用できるプロファイラについて記載します。 ■1.loic-sharma/profiler Laravel3 で使用していたプロファイルの Laravel4 版になります。そのためか、 パッケージの命名規則で vendor名の箇所が、「Profiler」になっています。 デザインは綺麗ですが、Bladeテンプレートを使用していると影響がありました。 ■2.kr4Y/laravel-profiler シンプルで使いやすく、Bladeテンプレートの影響はありませんでした。 ■3.onigoetz/profiler Session や Cookie 情報も表示されるプロファイラです。 設定変更は、vendor 以下の設定ファイルを変更しなければなりません。 (ただし、環境が「production」であれば無効になります) (設定ファイル名が、config.php ではなく profiler.php でした) また、Bladeテンプレートを使用していると影響がありました。
  • テクログ

    プレビュー画面を作ったよ

    今、fuelphpというフレームワークを使ってブログ機能みたいなのを作っているのですが、独自で作っているからもう何がなにやら分かりません。 で、ブログをアップする前にプレビュー画面の表示をさせたいということで、Jqueryを使ってデータの受け渡しに挑戦! 参考にさせていただいたのはコチラ! ありがとうございます。 テキストや既存の画像は上のJqueryプラグインをちょちょいと修正すれば、さくっと表示できる。 実際作ったpreview.jsはこんな感じ。 (function($){ $.fn.previewButton = function(config){ var button = this; var defaults = { //プレビューのurl 'url' : null, //キーとタイプのハッシュ {key:type, …} 'post' : {} }; var config = $.extend(defaults, config); if (config.url){ button.live('click', function(){ var form = $(this).parents('form'); var newform = $(''); $('body').append(newform); $.each(config.post, function(i, val){ switch(val){ case 'title': var _val02 = $('#edit_news_title').val(); newform.append( form.find('input[name = ' + i + ']').clone().val(_val02)); break; case 'textarea': var _val = $('iframe:first').contents().find('.cke_editable').html(); newform.append( form.find('textarea[name = ' + i + ']').clone().val(_val)); break; case 'category': var _val03 = $('#edit_news_category').find(':selected').text() newform.append( form.find('[name = ' + i + ']').clone().val(_val03)); break; case 'new_category': var _val04 = $('#edit_news_newcategory').val(); newform.append( form.find('input[name = ' + i + ']').clone().val(_val04)); break; case 'tag': var _val05 = $('#edit_news_tag').val(); newform.append( form.find('input[name = ' + i + ']').clone().val(_val05)); break; case 'topimg_main': var _val06 = $('#edit_news_topimg').val(); newform.append( form.find('[name = ' + i + ']').clone().val(_val06)); break; case 'writer': var _val07 = $('#edit_news_writer').val(); if(_val07 ==""){ _val07 = $('#edit_news_topimg').find(':selected').text(); } newform.append( form.find('input[name = ' + i + ']').clone().val(_val07)); break; default : break; } }); window.open(this.href, "preview"); newform.attr("target", "preview"); newform.attr("action", config.url); newform.attr("method", "post"); newform.submit(); newform.remove(); return false; }); } }; })(jQuery); (function($){ if(1){     $('input#form_preview').previewButton({ 'url'  : 'preview', 'post' : { 'text'         : 'textarea', 'title'        : 'title', 'category'     : 'category', 'new_category' : 'new_category', 'tag'          : 'tag', 'topimg_main'  : 'topimg_main', 'writer'       : 'writer', }     }); } })(jQuery); ちゃんと表示されてるかなぁ? POSTを受け取るコントローラーはこんな感じ。 public function action_preview() { $data = ""; //POSTの値を変数に格納 if(!empty($_POST['title'])){ $data['title'] = $_POST['title']; }else{ $data['title'] = ""; } if(!empty($_POST['text'])){ $data['text'] = $_POST['text']; }else{ $data['text'] = ""; } if(!empty($_POST['category'])){ $data['category'] = $_POST['category']; }else{ $data['category'] = ""; } if(!empty($_POST['new_category'])){ $data['new_category'] = $_POST['new_category']; }else{ $data['new_category'] = ""; } if(!empty($_POST['topimg_main'])){ $data['topimg_main'] = $_POST['topimg_main']; }else{ $data['topimg_main'] = ""; } if(!empty($_POST['writer'])){ $data['writer'] = $_POST['writer']; }else{ $data['writer'] = ""; } if(!empty($_POST['tag'])){ $data['tag'] = $_POST['tag']; }else{ $data['tag'] = ""; } //セッション関数 Session::set_flash('pre_title', $data['title']); Session::set_flash('pre_text', stripcslashes($data['text'])); Session::set_flash('pre_category', $data['category']); Session::set_flash('pre_new_category', $data['new_category']); Session::set_flash('pre_topimg_main', $data['topimg_main']); Session::set_flash('pre_writer', $data['writer']); Session::set_flash('pre_tag', $data['tag']); return View::forge('ビューファイルの場所が入るよ!', false); } POSTで得た情報をセッションでviewに渡すだけの簡単な作りです。 で、困ったのが、 Jquery.upload.jsを使って、『画像を一時的にuploadしたものをプレビューに表示する』というもの。 そもそも、初心者の僕はいろんな処理が絡むような、また、ファイルの受け渡しが複雑になるような部分が根本的に苦手なようで、このふたつの処理をうまく理解することが出来なかった。 はじめに、上のプレビューのコードにfileを追加したら、アップロードしようとしている画像ファイル名は取得できたけれど、上記のようにプレビュー画面に反映することは勿論出来なかった。 それはアップロードが出来ていなかったからだ!(当たり前) そこで、まずはJquery.uploadのコードを見てみる。 $(function(){ $('#edit_news_uploadimg').change(function(){ $(this).upload('demo.php', function(res){ alert(res); },'html'); }); }); これ、合ってそうじゃない!?合ってそうだよね!? そして、アップロード先のurlであるdemo.phpを試しに作っておいてみる。(アップロードが出来れば僕らの勝利なのだから。) コードは色々と端折ってますがこちら。 // ※$_FILES["file"]["tmp_name"]がテンポラリにあるファイル名 // ※$_FILES["file"]["name"]がアップロード元のファイル名 //tmpからファイルをコピー $tmpimg_file = date('U').".jpg"; //※便宜上jpgにしているだけだよ! move_uploaded_file($_FILES["file"]["tmp_name"],$tmpimg_file); //セッションに格納 Session::set_flash('pre_file', $tmpimg_file); return '一時アップロードしました'; 合ってそう!合ってそうだよ!! でも、どうしても取れない。 ちゃんとそのdemo.phpを見ているかの確認もしたし、alert(res) の部分をalert('死んで俺に詫び続けろオルステッド') とかにするとちゃんと出てくるのに、resが取れないし、ファイルもアップロードされない。 僕らは、一言「一時アップロードしました」って言って欲しいだけなのに......。 で、この解決の鍵は『MVC構造、及びフレームワーク』に隠されていました。 「MVC構造、及びフレームワーク」の特徴として、必ず「コントローラー」を経由して「ビュー」に受け渡しするのは当たり前ですよね。 そう、その当たり前が抜けていた。 コントローラー.......? public function action_demo() 作ってない!!! そうさ、上記のdemo.phpをviewファイルに作ってもコントローラー作ってなきゃ受け渡しされるはずが無いのでした。 そうなると、別にアップロード先にviewなんて要らないから、コントローラーでアップロードの処理をしてしまえば良い。 おまけにここで画像ファイルかどうかの判定も入れてしまおうかと。 editer機能のコントローラーに以下を追加。 public function action_demo() { // ※$_FILES["file"]["tmp_name"]がテンポラリにあるファイル名 // ※$_FILES["file"]["name"]がアップロード元のファイル名 //拡張子取り出し $preview_extension = explode('.', $_FILES["file"]["name"]); //画像ファイル拡張子タイプを配列に $extension_type = Config::get('app.img_extension'); //画像ファイルかどうか判定 if(array_search($preview_extension[1],$extension_type) === false){ return '画像ファイルを選択してください'; } //tmpからファイルをコピー $tmpimg_file = "????????????????".date('U').".".$preview_extension[1]; move_uploaded_file($_FILES["file"]["tmp_name"],$tmpimg_file); //セッションに格納 Session::set_flash('pre_file', $tmpimg_file); return '一時アップロードしました'; } これで画像ファイル判別+リネーム+tmpファイルへのアップロードが完了。 上記コードの「Session::set_flash('pre_file', $tmpimg_file)」でセッションにSET。 ※これはfuelphpの便利なメソッドだよ! プレビュー画面のviewで、 「Session::get_flash('pre_file')」でファイル情報をGETして表示完了! ※セッションで表示させるのとか合ってるのかなぁ、正直謎だ........ ハハッ!ここで勘の良いお方はお気付きのはずだ! これ、jquery.uploadでアップロードした画像のみ、一番上のコードのpreviewのJquery使ってないんです..... preview.js も public function action_preview() も、どっちも全くコード弄っていない。 ここわかんねー!!! Js間で絡むと思ってましたよ。。いや、絡ませる方法もあるんだろうな。 いやはや、これでなんとかプレビュー画面完成です。 最後に、tmpファイルに溜まっていく画像データをcronで一定時間したら消す処理を忘れないように!パンパンになるよ!! 終わり
  • テクログ

    error_log

    こんにちは。みなさんはerror_logってどんな使い方してますか? 私はバッチプログラムや、ブラウザに出力したらまずい時(echoやprintが使えない)などによく使ってます。 error_log — 定義されたエラー処理ルーチンにエラーメッセージを送信する 書き方は error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] ) 私はよく以下のようにしてます。 error_log(出力したいデータ,3,出力先ファイルのパス); あとはターミナルエミュレーターでサーバにログインして tail -f 出力先ファイルのパス みたくしてやると、リアルタイムで起動時の出力を確認できます。 詳しい説明はこちらhttp://php.net/manual/ja/function.error-log.php
  • テクログ

    レコードセット

    技術ブログ2回目の投稿です。 今回はデータベースへのアクセス操作を行うADOについて書きたいと思います。 ADOの使い方によって、処理速度が結構変わります。 で、そこでポイントなのがレコードをオープンするときのカーソルタイプ(CursorType)です。   ■カーソルタイプの種類と説明 ・adOpenForwardOnly:前方カーソル (デフォルト値)  レコード移動は前方方向への参照のみ・adOpenKeyset:キーセットカーソル  レコード移動は前後可能。ただし、他ユーザーが更新したレコードは参照できるが、追加削除したレコードは参照できない。。・adOpenDynamic:動的カーソル  レコード移動は前後可能。ただし、他ユーザーが追加・更新したレコードも参照できる。・adOpenStatic:静的カーソル  レコード移動は前後可能。ただし、他ユーザーが更新したレコードも参照できない。   総レコード数を取りたい場合、adOpenForwardOnly以外を指定するとRecordCountで取得することができたり、AddNewなどで容易にレコードの追加などが可能になるのですが、処理速度がかなり落ちてしまう原因になったりします。 データ参照だけを行う場合には、adOpenForwardOnlyのほうが早いです。 データ件数が多くなるほど、処理速度の差を実感できます。 このレコード操作はAccessやVBAでも使えるので、覚えておくと便利かも?
  • テクログ

    HTTPリクエストとリアルタイムWEB、最近つまずいたこと

    こんにちは、けーすけです。   最初に。Node.jsがどうとか、そういう話は書いていません。もっと基本的なところです。JSでリクエスト送ってサーバで処理するって言うajaxみたいなところです。   XMLHttpRequest非同期なデータの通信を実現するための便利なAPIです。HTTPリクエストとリアルタイムWEBとか関係するであろうところです。   先日、JSのモーダルダイアログで3択のダイアログを作りました。このモーダルダイアログの入力から処理を分岐して、サーバにコマンドを送る処理です。コマンドといってもHTTPリクエストにPOSTをくっつけて送るだけのものです。ローカルで動かしたときはうまくいきましたが、問題は下記です。   URLはhttp://cloud.hoge.jp/index.phpです。モーダルダイアログとか受け取り側のPHPとか書いてませんがご了承ください。   //modal.htmlの戻り値は1,2,3のいずれかです。 window.onload = function(){ var action = showModalDialog("http://hoge.jp/modal.html",window,"dialogWidth:300px;dialogHeight:200px");   if(action==1){    function_hoge(action);    ・・・(中略)・・・    alert('hoge1');  } else if(action==2){    function_hoge(action);    var xhr= new XMLHttpRequest();    xhr.open("POST","http://sub.hoge.jp/modal_cmd.php",TRUE);    str_post = 'hoge1='+action+'&hoge2='+str_msg;    xhr.send(str_post);    alert('hoge2');  } else {    alert('hoge3');  } } この場合、必ずalert('hoge3');が表示されます。   オリジンがそれぞれ違う点が問題となります。http://cloud.hoge.jp/index.phphttp://hoge.jp/modal.htmlhttp://sub.hoge.jp/modal_cmd.php   http://sub.hoge.jp/modal_cmd.phpにポストでhoge1hoge2という値を送ると何かしてくれるプログラムです。cloudもsubもhoge.jpのサブドメインだから大丈夫だろうという考えの元でやっていました。1.モーダルダイアログは表示できますが、戻り値は取れません。2.xhr.send(str_post);はできません。   よって、同一ドメインのローカルだと問題なく動作して、複数ドメインをまたいだ検証環境だと動作しないということでした。