CakePHPで検索機能の実装を少し楽する

4月 22nd, 2008 admin

  • 検索
  • ページング
  • ソート

この3つさえなければ僕はWebアプリが大好きです。

CakePHP1.2での簡単なやり方

CakePHP1.2ならLIKE文なんかをある程度作ってくれるのでWHER 1=1 AND...とか書かなくてOKで少しうれしいです。

コード

usernameとpasswordが入ったUserモデルとuser_idとかnameとかname_ruby,tel_mobileとかが入ったProfileモデルに対してAND検索をする例。

/admin_index.ctp

PHP:
  1. <h2>ユーザの検索</h2>
  2. <form action="<?php echo $html->url('/admin/users/index'); ?>" method="get">
  3. <table>
  4.     <tr>
  5.         <th width="20%">ログインID</th>
  6.         <td>
  7.             <?php echo $form->input('Words/username', array('size' => '20','label'=>false));?>
  8.         </td>
  9.     </tr>
  10.     <tr>
  11.         <th>名前</th>
  12.         <td>
  13.             <?php echo $form->input('Words/name', array('size' => '30','label'=>false));?>
  14.         </td>
  15.     </tr>
  16.     <tr>
  17.         <th>フリガナ</th>
  18.         <td>
  19.             <?php echo $form->input('Words/name_ruby', array('size' => '30','label'=>false));?>
  20.         </td>
  21.     </tr>
  22.     <tr>
  23.         <th>携帯電話番号</th>
  24.         <td>
  25.             <?php echo $form->input('Words/tel_mobile', array('size' => '15','label'=>false));?>
  26.         </td>
  27.     </tr>
  28. </table>
  29. <?php echo $form->submit('検索');?>

/users_controller.php

PHP:
  1. function admin_index() {
  2.         //検索ワードがあるかどうか
  3.         $conditions = null;
  4.         if(isset($this->params['url']['data']['Words'])){
  5.             $this->data['Words'] = $this->params['url']['data']['Words'];
  6.             $like = $this->_create_like_conditions($this->params['url']['data']['Words']);
  7.             $conditions = array('and' => $like);
  8.         }
  9.         $this->User->recursive = 0;
  10.         $this->set('users', $this->paginate($conditions));
  11.     }
  12.  
  13.     function _create_like_conditions($data){
  14.         $like = array();
  15.         foreach($data as $k=>$v){
  16.             $like[$k] = 'like %'.$v.'%';
  17.         }
  18.         return $like;
  19.     }

まとめ

likeのところは、or,not,in,between,regexp,<>にも対応しています。また今回はand検索でしたがもちろんorでもいけます。

みんなには嫌われているけど現場では他に選択肢がないため大活躍なジャックバウワーのような存在「PHP+CakePHP」、今日も助かったよ!

ロリポップをPHPとGmailでお手軽バックアップする

4月 19th, 2008 admin

ロリポップのファイルをバックアップするために任意のディレクトリをzipで圧縮してメールでGmailに送るスクリプトを書いた。
別にGmailでなくてもいいのだけどGmailなら6Gぐらい容量があるし、ゴミ箱に自動で入るように設定しておけば30日ごとに勝手に消してくれるので非常にお手軽なのです。

コード

メールの送信にphpmailerというのを使っています

PHP:
  1. <?php
  2.  
  3. //ライブラリ読み込み
  4. require("./PHPMailer/class.phpmailer.php");
  5.  
  6. //バックアップするディレクトリを指定
  7. $backup_dir = "../photo"; //この場合はphotoディレクトリ以下をバックアップ
  8. //ファイル名を指定
  9. $new_file = "domain.com.zip";
  10.  
  11. //送り先
  12. $to = "任意のメールアドレス@gmail.com";
  13. $subject = "domain.com backup";
  14. $body = "";
  15. $from = "任意のメールアドレス@gmail.com";
  16. $fromname = "domain.com";
  17. $attachfile = "./domain.com.zip";
  18.  
  19.  
  20. mb_language("japanese");
  21.  
  22. system("zip -r $new_file $backup_dir");
  23.  
  24.  
  25.  
  26. $mail = new PHPMailer();
  27. $mail->CharSet = "iso-2022-jp";
  28. $mail->Encoding = "7bit";
  29.  
  30. $mail->AddAddress($to);
  31. $mail->From = $from;
  32. $mail->FromName = mb_encode_mimeheader(mb_convert_encoding($fromname,"JIS","EUC-JP"));
  33. $mail->Subject = mb_encode_mimeheader(mb_convert_encoding($subject,"JIS","EUC-JP"));
  34. $mail->Body  = mb_convert_encoding($subject,"JIS","EUC-JP");
  35.  
  36.  
  37. $mail->AddAttachment($attachfile);
  38.  
  39. if (!$mail->Send()){
  40.     echo("メールが送信できませんでした。エラー:".$mail->ErrorInfo);
  41. }
  42.  
  43. unlink($new_file);
  44. ?>

まとめ

  • ロリポップは安いのにsystem関数使えて凄い、PHPのzip用のライブラリも入ってます
  • rmコマンドは使わせてもらえないらしい、unlink関数でファイルは消す
  • 現在Zipで送ってるだけなのでセキュリティ的にアウト、暗号化するのが望ましい
  • 定期的に実行するためにwebcronのようなサイトを使う(もしくは他サーバから、もしくは1日の最初の訪問者とかに踏ませる)
  • Gmailのほうでここからのメールはゴミ箱に直行の設定をしよう
  • Gmailで転送設定しておけば簡単に二重化ができる!
  • Gmailの規約は要確認

参考サイト

phpmailer
http://phpmailer.codeworxtech.com/
PHPで日本語メールを送る - 応用編 (添付ファイル、HTMLメール) - EC studio 技術ブログ
http://techblog.ecstudio.jp/tech-tips/mail-japanese-advance.html

リスト

4月 17th, 2008 admin

久しぶりの「アルゴリズムとデータ構造シリーズ」です。今回はリスト構造についてです。

C言語では配列を使うときは配列のサイズを宣言する必要があります。しかし配列のサイズがあらかじめわかる場合はいいのですが、いくつ入力があるかわからないときは困ったことになります。そこでリストというデータ構造を使って無限に要素数を増やせる配列のようなものを作ります。

C言語でも一つ増やすときに今よりひとつ大きいサイズの配列を確保してそちらに引っ越すという方法がありますが、あまり効率とは言えません。

データ構造

リストの要素(ノードとかいう)を「データ・次のノードへのポインタ・前のノードへのポインタ」という形式で用意して、ノード同士がそれぞれの前後のデータの場所を記憶しておくというデータ構造。

誰が前の人で、誰が後ろの人かは知っている。だけど全体は(そのサイズすら)しらない。
町内の回覧板みたいなシステムですね。

次の人だけを知っているリストを「単方向リスト」、前後の人を知っているリストを「双方向リスト」と言います。

コード

Rubyなのでデータをオブジェクト、ポインタは参照で表現しました。

RUBY:
  1. class Node
  2.   attr_accessor :prev,:next,:data
  3.  
  4.   def initialize(data)
  5.     @data = data
  6.   end
  7. end
  8.  
  9. firstnode = lastnode = nil
  10.  
  11.  
  12. datas = [1,2,3,4,5,6,7,8,9]
  13. datas.each do |x|
  14.   node = Node.new(x)
  15.   node.next = nil
  16.  
  17.   unless lastnode.nil?
  18.     lastnode.next = node
  19.     node.prev = lastnode
  20.     lastnode = node
  21.   else
  22.     firstnode = lastnode = node
  23.     node.prev = nil
  24.   end
  25. end
  26.  
  27.  
  28. p firstnode.next.next.prev.data

出力

2

まとめ

配列というと僕の場合は入門書とかにでてくる分別できるゴミ箱みたいなのが頭に浮かぶ。2次元配列になったとしても思い浮かぶのは玉子のパックだ。だけどリストを思い浮かべてみるとかなりカッコいい!頭に浮かぶのはイタリアのマフィア。自分の部下とボスは知っているがボスのボスは知らないし(知れない)、自分の部下がどんな部下を使っているのかも知らない(知る必要がない)。組織のサイズも知らないし関係ない。とにかくボスの命令を遂行するだけ・・・単にJOJO脳になってるだけですね。はい。

ちなみに僕の家の回覧板の場合は、誰が持ってくるか知らないので単方向リストです。いつも勝手にポストにはいってます。

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

CakePHP::ユニークな値かどうかチェック(重複チェック)

4月 15th, 2008 admin

ユーザIDなど重複したら困る時のチェック。よく使うのでメモ
MySQLの場合は、DBのuniqueを使ったスマートな方法もあります。

コード

/model/user.php

PHP:
  1. function unique($field){
  2.        foreach( $field as $key => $value ){
  3.            $this->recursive = -1;
  4.            $found = $this->find(array("{$this->name}.$key" => $value));
  5.         }
  6.            return !$found;
  7.     }

/controller/user_controller.php

PHP:
  1. //省略 addメソッドとか
  2.             if($this->data['User']['username'] && !$this->User->unique(array("username" => $this->data['User']['username']))){
  3.                 $this->User->invalidate("unique");
  4.             }
  5.  
  6.             if ($this->User->save($this->data)) {
  7. //・・・以下省略

/view/user/add.ctp

PHP:
  1. <td width="65%">
  2.         <?php echo $form->input('User/username', array('label' => false)); ?>
  3.         <?php echo $form->error ('User/unique', 'このIDはすでに使用されています。');?>
  4.     </td>

CakePHP1.2での管理者用レイアウト設定

4月 14th, 2008 admin

admin routingを使っていて、adminの時だけ別のレイアウトを設定したい場合。
こうやってみればいいんじゃないかという例

コード

PHP:
  1. <?php
  2. //app/app_controller.php
  3. class AppController extends Controller {
  4.     function beforeRender() {
  5.         echo $this->action;
  6.         if (preg_match("/^" . Configure::read('Routing.admin')  . "_/i", $this->action)) {
  7.                 $this->layout = 'admin_default';
  8.         }
  9.     }
  10. }
  11. ?>

まとめ

他のやり方ってあるのかな?知りたいです。
あと、管理者用とユーザ用のコントローラを分けたいときにRailsのようにcontrollers/admin/user_controller.phpみたいにディレクトリを切りたいんだけど、それもやり方を知りたい。今はadmin_user_controller.phpとかを作っているけどカッコ悪い