CakePHP SecurityコンポーネントとPOST

PHP

CakePHP Securityコンポーネントを利用するとPOST時にFormのトークンと照合するようになります。
通常はセキュリティ上望ましい仕様ですが、Web APIに後付けでBASIC認証を追加したところHTTP GETは正常に動作しますが、
HTTP POSTが動かなくなってしまいました。

  • POST時のValidateを無効にするには以下のようにSecuriytコンポーネントを設定します。
 $this->Security->validatePost = false;
  • BASIC認証してPOST時のValidateを無効にするAppControllerの例です。
 class AppController extends Controller {
 
         var $components = array('Security', 'RequestHandler');
 
         function beforeFilter() {
                 parent :: beforeFilter();
                         $this->Security->loginOptions = array('type' => 'basic');
                         $this->Security->loginUsers = array('user' => 'password');
                         $this->Security->requireLogin('*');
                         $this->Security->validatePost = false;
                 }
         }

CakePHP Paginateが遅い

PHP

CakePHP Paginateが遅い

CakePHP 1.3.6

CakePHPの難点は、動作が遅いことです。機能が豊富な分、仕方ないかもしれませんが。

調べてみると、Paginateの処理でも若干時間がかかっているようなので、これをカスタムして早くする方法です。

デフォルトのまま利用すると、まず件数を取得するために、Paginateは関連するテーブルのすべてのデータを取ってきて、カウントします。
しかし、アプリの作りから、これが不要な場合もありますよね。

そういう場合は、モデルに次のように書き込みましょう。

 //Studentモデルのファイル student.php
 function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
 
         	$sql="SELECT DISTINCT student_id FROM students";
         	$results=$this->query($sql);
         	$number=count($results);
             return $number;
             
         } 
 

returnで戻す値が整数になるように気をつけましょう。

すると、全件の件数はこれで数えるようになるので、少しだけ速度が速くなります。
私の場合は、10万件のデータを関連テーブルなど含めてカウントしていたので164msかかっていたのが、14msに縮められました。

CakePHP公式マニュアル 4.9.4 カスタムしたクエリによるページ付け

下記には、recursiveを-1に設定することで、早くしようという例も載っています。

http://cakephp.1045679.n5.nabble.com/pagination-SELECT-COUNT-query-slow-td3321847.html

CakePHP Paginate Sort の使い方

PHP

Cake PHP Paginate sort について

CakePHP 1.2.3.8166

CakePHPのPagination機能とは、たとえば100件あるようなデータを1ページに100件見せるのではなく、20件ごとぐらいに分割してページにしてくれる便利機能です。

また、項目をソートしてくれる機能もあります。

ここでは、このソート機能  $paginator->sort について書いておきます。

1.そもそもpagination機能を使うために、コントローラーで準備をしておきます。
pagination機能は、取得するデータを指定してそのまま使えます。
モデルのfindと同じように、使えるんですね。
(ついfindしてからpaginationを使うのかと思ってしまいますが、違います。)

 //コントローラー
 function test_view(){
 
 $this->paginate=array(
 
  'モデル名' => array('conditions'=>array(
              'project_id'=>$project_id
                                           ),
                         'order'=>array(
              'PaperFormat.type_number'=>'desc'
 		                       )
                       )					
                     );
 $project_datas=$this->paginate();
 $this->set('ProjectDatas', $project_datas);		
 }

上記はコントローラー内のアクション test_viewで使用する際の書き方です。
$this->paginateはfind(‘all’)と同じ役割をしてくれるので、わざわざ’all’はつける必要はありません。

2.次にビューファイルです。

ビューファイルでpaginagion のソート機能をつけるための編集方法です。
$paginator->sortの引数の設定は次の通りです。

 $paginator->sort(
   '表示したい名称','ソートするキー名称','ページングでも利用する引数'
            )

例は次の通りです。

 <?php echo $paginator->sort('プロジェクト番号','id',array(
                                'url'=>	$this->passedArgs 
                                                        )
 		           );?>

第三の引数

 array( 'url'=>	$this->passedArgs   )

は、今まで保持していた引数を保持するための便利な関数です。
たとえば、URLの

 myapp/projects/test_view/3/62/

の3や62、という値を保持したまま、ソートを行ってくれます。
この例ではキーが’id’になっていますが、他のモデルを利用したい場合、

 'Teacher.id'

みたいに.でつなげて書けばできるようです。

テーブル構造でデータを表示し、テーブルの見出しをソートのキーにしたい時、次のようにします。

 <table>
   <tr>
  	<th><?php echo $paginator->sort('プロジェクト番号','id',array(
                 'url'=>$this->passedArgs 
  )
 );?>
        </th>
 	<th>名称</th>
      </tr>

//データ表示のループ foreach($Projects as $Project){ ?> <tr> <td<?php if ($i % 2 == 0) echo $class;?>> <?php echo $Project['name']; ?> </td> </table>

参考:本家マニュアルサイト(英語)Custom Query Pagination
http://book.cakephp.org/view/249/Custom-Query-Pagination

  • コントローラーのpaginateに渡すパラメータめちゃ助かりました。本に載ってたコントローラ側のpaginateのソートを示すパラメータで”sort”にフィールド渡してもソートされずハマりました。コントローラ側は”order”だったんや!とこのサイト見て解決しました。m(_ _)m — まけどん {2010-09-23 (木) 16:15:30}

CakePHP Pagenateのページ数を取得

PHP

CakePHP1.3

CakePHP Pagenateのページ数を取得

 $this->params['named']['page']

で、2ページ以降のページ数が取得できます。

ところで、Paginateは便利な機能ですが、ちょっと変わったことをすると、応用が利かないですよね。
たとえば、私が今作っているWebアプリケーションでは、100件のデータを、ユーザーには10件ごとに見せるというアプリケーションを作っています。

1ページめでは、100件をPaginateのlimitに設定してOKです。
しかし、2件目以降では、10件ごとしかとってきてくれないんですよね。

検索条件がかなり複雑なのと、出力されたデータをだいぶ整形しなくてはいけませんので、通常のPaginateの機能があまり使えませんでした。

しょうがないので、ページングが2ページ目以降の場合は、セッションから検索条件を読みだして利用するようにしています。

 //ページネートの場合のみ、検索条件を、セッションから読み出し
   if(isset($this->params['named']['page'])){
       $student_ids=$this->Session->read('student_ids');
    }
 //中略
   $this->paginate=array(            
     'Student'=>array(	
             'conditions'=>array('Student.student_id'=>$student_ids)
                                 ,'limit' => 100			
                                 ,'order' =>'Student.student_id'
                    )
     );

CakePHP PHPの文字コードと入出力データの文字コードが異なる場合の対処

PHP
CakePHP

携帯向けサイトを開発する場合や、レンタルサーバーでPHPの文字コードがEUC-JPに設定されてしまっている場合の対処方法です。

  • UTF-8でHTMLを表示したいが、PHPがEUC-JPに固定されてしまっている場合。

headerでHTML出力を指定します。
POSTパラメーターの文字コードはheaderと同じですが、GETパラメーターが文字コード変換されてしまっている場合、UTF-8に変換します。

 class AppController extends Controller {
 	function beforeFilter() {
 		parent::beforeFilter();
 	
 		$this->header("Content-type: text/html; charset=utf-8");
 		if(isset($this->params['url'])) {
 			array_walk_recursive($this->params['url'], 
  					'&$val, $key',

‘$val = mb_convert_encoding($val, “UTF-8”, “auto”);’

 				)
 			);

}

 	}
 }

※CakePHP 1.3.8ではRequestHandler::RespondAsは、Content-Disposition以外のheaderを出力しません。
http://api.cakephp.org/view_source/request-handler-component/#line-702

headerの二重送出を防ぐために、このような状態になってしまっているようです。
http://cakephp.lighthouseapp.com/projects/42648/tickets/842

  • 出力HTMLの文字コードをEUC-JPに変換する例です。

フォームなどでは、上記例のようにbeforeFiterで$this->data等をUTF-8に変換する必要があります。

 class AppController extends Controller {
 

function afterFilter(){

 		parent::afterFilter();
 	
 		$this->output = mb_convert_encoding($this->output, "EUC-JP", "UTF-8");
 	}
 }
  • array_walk_recursive()の情報ありがとうございます。途中、create_function(‘&$val, $key’,の指定が抜けているようです。 — {2011-08-04 (木) 22:17:53}
  • ご指摘、ありがとうございます。 — 管理者 {2011-08-05 (金) 19:04:36}