CakePHP

CakePHPでデモを作成する機会があったので、その時の内容をまとめてみました。

開発環境の構築2日、開発5日、サーバー公開1日程かかりました。

システム環境

開発環境

OS : Windows Xp SP3
PHP : 5.4.11
CakePHP : 2.3.0
Apache : 2.4.3 win32
DB : MySQL 5.5
IDE : Eclipse 4.2.1 Juno
Eclipse Plugin : PDT : PHP Development Tools

公開環境

公開環境はこのサーバーにインストールされているシステムになります。
OS : CentOS release 6.3 (Final)
PHP : 5.3.3
CakePHP : 開発で使用したものをUploadするので開発と同じものです。
Apache : 2.2.15
DB : MySQL 5.1.67

公開環境(Linux)へのインストール方法

Linux(このサイト)上に開発後のモジュールをインストールした時のメモです。

サイトの環境

  • ApacheのDocumentRoot :
    /etc/httpd/conf/httpd.confの中の設定は以下のようになっています。
    DocumentRoot "/var/www/html"
    

設定

  • Apacheの設定
    #vi /etc/httpd/conf/httpd.conf
    
    <Directory />
        Options FollowSymLinks
        AllowOverride None   => All
    </Directory>
    

  • PHPの設定
    #vi /etc/php.ini
    
    ;date.timezone =
     ↓
    date.timezone = Asia/Tokyo
    
    ;default_charset = "iso-8859-1"
     ↓
    default_charset = "UTF-8"
    
    ;mbstring.language = Japanese
     ↓
    mbstring.language = Japanese
    
    ;mbstring.internal_encoding = EUC-JP
     ↓
    mbstring.internal_encoding = UTF-8
    
    short_open_tag = Off
     ↓
    short_open_tag = On
    ※ short_open_tagの設定はこれがOnになっていないと<?= ?>の記述が使えません。
    
    Apacheの設定の変更またはPHPの設定を変更後にApacheの設定の再読み込みを行います。
    # /etc/rc.d/init.d/httpd reload ← 設定の再読み込み
    
  • MySQL
    • MySQLを使用するので、サーバーの環境にあった設定をします。
    • DB、ユーザーとテーブルを作成します。
  • アプリケーション(CakePHPを含む)のインストール
    CakePHPのライブラリーおよび開発したモジュールをWebから直接アクセスできないように配置します。またこうすることによりCakePHPのアプリケーションを複数インストールした場合CakePHPのライブラリーを重複してインストールする必要がなくなります。
     
    以下のようにようにします。
    開発環境の配置
     1.CakePHPのコアライブラリは、 /lib/Cakeの中にあります。
     2.アプリケーションコードは、/appの中です。
     3.アプリケーションのウェブルートは、通常、/app/webrootにあります。
     
     
    公開環境の配置
     1.CakePHPのコアライブラリーは/var/www/cakephp/lib/Cakeに配置します。
     2.アプリケーション・コード・ディレクトリーは/var/www/cakephp/appに配置します。
     3.アプリケーションのwebrootディレクトリーはApacheのDocumentRoot下の/var/www/html/bbsに配置します。
    1のコアライブラリーと2のアプリケーションコードは同じ/var/www/cakephpでなくてもよく別々の場所でも可能ですが、ここでは同じ場所としました。
     
    開発環境のファイル構成は以下のようになっています。
    ......\Eclipse\workspace\cakephp\lib\Cake\
                                    \plugins\
                                    \vendors\
                                    \app\Config\
                                        \Console\
                                        \Controller\
                                        \Lib\
                                        \Locale\
                                        \Model\
                                        \Plugin\
                                        \Test\
                                        \tmp\
                                        \Vendor\
                                        \View\
                                        \webroot\css\
                                                \files\
                                                \img\bbs\
                                                \js\
    
    インストール後のディレクトリーの構成が以下のようになるようにインストールします。つまりcakephp下のファイルを一旦/var/www/cakephp下にコピーしwebroot下のファイルを/var/www/html/bbs/下に移動します。ここでwebrootディレクトリーがなくなってbbsに変わっていることに注意して下さい。またplugins、Test、Vendorなど不要なディレクトリーや不要なファイルがあるかもしれませんが、ここでは何も考慮せずに開発環境のファイルをすべてコピーしました。
    /var/www/cakephp/lib/Cake/
                    /plugins/
                    /vendors/
                    /app/Config/
                        /Console/
                        /Controller/
                        /Lib/
                        /Locale/
                        /Model/
                        /Plugin/
                        /Test/
                        /tmp/
                        /Vendor/
                        /View/
    /var/www/html/bbs/css/
                     /files/
                     /img/bbs/       <= 書込みのパーミッションを与える
                     /js/
    
    cakephpのディレクトリーはApacheのDocumentRootとは別のところにあるのでWebから直接アクセスできません。
    bbsディレクトリーにあるindex.php(元webroot下のindex.php)を以下のように変更します。変更する変数はROOT、APP_DIR、CAKE_CORE_INCLUDE_PATHの3つです。
    ※CakePHPの応用インストール参照。
            :
    if (!defined('ROOT')) {
    /*      define('ROOT', dirname(dirname(dirname(__FILE__))));*/
            define('ROOT', DS . 'var' . DS . 'www' . DS . 'cakephp' );
    }
            :
            :
    if (!defined('APP_DIR')) {
    /*      define('APP_DIR', basename(dirname(dirname(__FILE__)))); */
            define('APP_DIR', 'app' );
    }
            :
            :
    if (!defined('CAKE_CORE_INCLUDE_PATH')) {
            define('CAKE_CORE_INCLUDE_PATH', DS . 'var' . DS . 'www' . DS . 'cakephp' . DS . 'lib' );
    
            if (function_exists('ini_set')) {
                ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR .ini_get('include_path'));
            }
            if (!include ('Cake' . DS . 'bootstrap.php')) {
                    $failed = true;
            }
    } else {
            if (!include (CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS .bootstrap.php')) {
                    $failed = true;
            }
    }
            :
    
    これでDocumentRoot下にあるindex.phpからCakePHPのライブラリーとアプリケーションにアクセスすることができるようになります。
    また、新しいアプリケーションを追加した場合、それをmyappとすると以下のように配置して追加します。
    /var/www/cakephp/lib
                    /app
                    /myapp
    /var/www/html/bbs
                 /myapp
    
    • ファイルのアップロード
      ファイルをアップロードする場合は、ファイルがアップロードされるディレクトリーと保存しておくディレクトリーに書込みのパーミッションを与える必要があります。ここでは、/var/www/html/bbs/img/と/var/www/html/bbs/img/bbs/です。

Hint & Tips

開発中で発生した問題や工夫した内容です。

トラブル(Trouble)

  • PHP(php.ini)の設定変更後はApacheの再起動が必要です。
    再起動しない場合php.iniの変更が反映されません。
  • MySQLにテーブルを作成する時のフィールド名はすべて小文字にする必要があります。Scaffoldsの例ではidで以下のエラーが発生します。その他created,modifiedなども適切に処理されなくなります。
    All field name of table must be lower case. If not, following error occurs for example for id at scaffolds.
     
    Undefined index: id
      ...\cake\lib\Cake\View\Scaffolds\\index.ctp,line 48
    Undefined_index.jpg
     
    エラーメッセージではidと小文字になっていますが、表示ではIDと大文字になっているので分かります。
    因みにテーブル情報を取得している部分はMySQLでは
    ……\cake\lib\Cake\Model\Datasource\Database\Mysql.phpfunction describeで、
    while ($column = $cols->fetch(PDO::FETCH_OBJ)) {のところで取得しています。 今回問題となったフィールド名は$column->Fieldにあたります。
  • Firefoxでインプットのpassword欄に未入力にもかかわらず勝手に●●●●●●が入ってしまう。
    inputタグでautocomplete="off"をセットすることにより解決しました。
    <?php
        echo $this->Form->input('password', array( 'label' => 'パスワード : ', 'autocomplete' => 'off'));
    ?>
    

Tips

  • 2つのテーブルを結合した場合のpaginate
    今回は以下の2つのテーブルがあり、img_filesテーブルのuser_idがusersテーブルのidです。img_filesテーブルからデータを読取る時にusersテーブルのnameも表示するために同時に読取ります。usersテーブルのidは表示には必要ありません。
    CREATE TABLE IF NOT EXISTS users (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      userid CHAR(20) NOT NULL UNIQUE,
      name CHAR(20) NOT NULL,
      password CHAR(50) NOT NULL,
      created DATETIME DEFAULT NULL,
      modified DATETIME DEFAULT NULL
    )
    
    CREATE TABLE IF NOT EXISTS img_files (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      filename VARCHAR(255) NOT NULL DEFAULT '',
      filepath VARCHAR(255) DEFAULT NULL,
      mimetype VARCHAR(20) DEFAULT NULL,
      info TEXT DEFAULT NULL,
      size INT UNSIGNED DEFAULT NULL,
      content MEDIUMBLOB DEFAULT NULL,
      user_id INT UNSIGNED DEFAULT NULL,
      comment VARCHAR(255) DEFAULT NULL,
      created DATETIME DEFAULT NULL
    ) 
    
    Modelは次のように設定します。ここで重要なのはImgFile.phpの中の" public $belongsTo = 'User';"です。これはテーブルimgfilesのあるフィールドがテーブルusersのidに依存していることを意味していて、そのフィールドはデフォルトでクラス名_idで、今回の場合user_idのフィールドとなります。また、usersのidはユニークでなければなりません。
    User.php
    <?php
    App::uses('AppModel', 'Model');
    
    class User extends AppModel {
     public $name = 'User';
     public $validate = Array(
      :
     );
    	
     public function beforeSave($options = array() ) {
      :
     }
    }
    
    ImgFile.php
    <?php
    App::uses('AppModel', 'Model');
    
    class ImgFile extends AppModel {
     public $name = 'ImgFile';
     public $belongsTo = 'User';
    
     public $validate = array(
      :
     );
    }
    
    ImgFilesController.php
    Controllerでの$paginateの設定は以下のようになっています。fieldsで読取るフィールドを設定していますが'User.name'とusersテーブルフィールド名に対してクラス名Userを付けるのミソです。
     public $paginate = array ('ImgFile' =>
      array(
       'fields' => array('filepath', 'user_id', 'comment','created','User.name'),	
       'limit' => 10,
       'order' => array('ImgFile.created' => 'desc'),
      )
     );
    
    
    使用する場合は通常通り以下のようにしてデータを取得します。
    $conditions = null;
    $this->set('filelist', $this->paginate($conditions));
    
    display.ctp
    Viewで読取ったデータを表示する場合、以下のようにクラス別にデータを取り出します。
    <?php
     foreach ($filelist as $file){
    	echo '<img width="600" alt="" border="1" src="';
    	echo Configure::read('myurl');
    	echo 'img/' . $file['ImgFile']['filepath'] .'"><br>';
    	echo '<a>' . $file['ImgFile']['created'] . '</a> : <a>' . h($file['User']['name']) . '</a><br>';
    	echo '<a>' . h($file['ImgFile']['comment']) . '</a><br><br>';
    	}
    ?>
    
    因みにh()関数はCakePHPのエスケープ処理をする関数でこの中でhtmlspecialchars()を実行しています。
  • 日付選択リストの作成
    以下をView(.ctp)に記述します。
    <?php
     $selected =array(       ← オプションを配列で設定します。
      'minYear' => 2010,     ← 最小表示年数の設定。
      'maxYear' => date('Y'),   ← 最大表示年数の設定。date('Y')は現在の年
      'separator' => '-',     ← 年月日の間の区切り文字の設定。
      'monthNames' => false,   ← 月の表示を名前ではなく数字表示。
      'empty' => true);      ← 初期表示をブランクにする。
     echo $this->Form->create();  
     echo $this->Form->dateTime('show_dt', 'YMD', null, $selected );
          ← show_dt:変数名、YMD:年月日の順番に表示、
            null:時間のフォーマットで今回使用しないのでnullを設定。
            $selected:オプションの配列変数
    ?>
    
  • ログイン時のユーザー名の表示
    ControllerでユーザーのデータをAuthからセットします。
    $user_data = $this->Auth->user();
    if(!is_null($user_data)){
     $this->set('user_data',$user_data);
    }
    
    View(.ctp)では以下のようにしてユーザー名を表示します。
    <?php 
     if(isset($user_data)){      
      echo $user_data['name']; 
     }
    ?>
    
  • 定数の設定
    システムで使用する定数をbootstrap.phpの中で設定しました。今回はベースとなるURLの値が環境により変更できるように値を設定しました。以下を一番最後に追加します。
    bootstrap.php
    Configure::write('myurl', '/bbs/');
    
    定数を読込む場合は以下のようにreadを使用します。
    View\ImgFiles\index.ctp
    onClick="location.href='http://<?php echo env('HTTP_HOST');echo Configure::read('myurl');?>users/login'"  target="_self">
    
    因みにenv('HTTP_HOST')はCakePHPの関数でホスト名(ドメイン名)を取得します。
  • Global変数の書込み・読出し(セッションを使用)
    Controller間でデータを受け渡しする方法としてセッションを使用する方法があります。今回は日付指定でのデータ検索を、paginationで使用するため他にいい方法が思いつかなかったので使用することにしました。使用方法は簡単です。
    書込みの方法
    $this->Session->write( '名前', 値);
    
    読出し方法
    $work = $this->Session->read( '名前');
    
     

参考リンク


添付ファイル: fileUndefined_index.jpg 1451件 [詳細]

最終更新のRSS
Last-modified: 2014-03-16 (日) 14:26:58 (3695d)