読者です 読者をやめる 読者になる 読者になる

CakePHPとUploadifyとセッション情報へのアクセス

Uploadify本家

Uploadifyとは?

Ajax風にファイルをアップロードするjQueryプラグイン「Uploadify」の使い方 | かたつむりくんのWWW
マルチファイルのアップロードを可能にするクールなjQueryプラグイン「uploadify」:phpspot開発日誌

  • 複数ファイルの一括送信が可能
  • 画面遷移なし
  • 進捗プログレスバーの表示が可能
  • 送信処理中断が可能
  • FlashPlayerを使用したjQueryプラグインとして動作

以下、CakePHPでUploadifyを使うにあたって必要だった設定をメモ。
ここでのバックエンドスクリプトとは、Uploadifyの'script'パラメータで呼び出されるファイル転送後に所定の場所にファイルをコピーする処理を記述するスクリプト(メソッド)のことを指す。

UploadifyをCakePHPのAuthコンポーネントが有効な状態で使用する

デフォルトだとUploadifyのバックエンドスクリプトがAuthコンポーネントで弾かれてしまう。
そこでappもしくは各ユーザーコントローラのbeforeFilterに以下のような記述を追加する。

if ($this->RequestHandler->isFlash()) {
  $this->Auth->allow('backend_script');
}

Uploadifyのバックエンドスクリプト(backend_script)からCakePHPのモデルにアクセスする

ユーザーコントローラクラスのメンバ関数としてバックエンドスクリプトを実装する。
これによりバックエンドスクリプトからモデルへのアクセスが可能となりDBへの読み書きができるようになる。

controller
//バックエンドスクリプトメソッド(アプリケーションコントローラクラスのメンバ関数として作成)
function backend_script(){
    if (!empty($_FILES)) {
      if( $_FILES['Filedata']['error'] == 0 ){
            $targetFile = $dir.DS.$_FILES['Filedata']['name'];  //コピー先
            $tempFile = $_FILES['Filedata']['tmp_name']; //コピー元
            //ファイルコピー
            if(move_uploaded_file($tempFile, $ta)){
              //DBにファイルのパスを保存
              $this->AppModel->id = (保存レコードid);
              $this->AppModel->saveField('ファイルパス', $targetFile);
            }
          }
        }
      }
    }
}
view

uploadifyのscriptパラメータには以下のように記述。APPはDOCUMENT_ROOTからの相対パス

$(document).ready(function() {
$('#XXX').uploadify({
	:
'script': '/APP/(controller)/backend_script/',
	:
});

Uploadifyのバックエンドスクリプト(backend_script)から呼び出し元のセッションIDにアクセスする。

上記のようにアプリケーションのcontrollerクラスのメンバ関数としてバックエンドスクリプトを記述するとmodelにアクセスできるようになりDBへのアクセスが可能となる。
ところが、debugやsetFlashを使い画面上にデータを表示させようとしてもうんともすんともいわない。Uploadifyから呼び出されたバックエンドスクリプトのセッションIDは呼び出し元のセッションIDとは異なるからである。UploadifyのバックエンドスクリプトはFlashプレイヤーが起動するものだから当たり前といえば当たり前なのである。故に、セッションに保存されているデータを読み書きしようとおもってもできない。さて困った。

そこで、バックエンドスクリプト内で呼び出し元と同じIDを使うようにセッションを起動しなおす。

バックエンドスクリプトに呼び出し元のセッションIDを送信

バックエンドスクリプト内でsession_idをコールしても得られるのはバックエンドスクリプトのセッションIDなので無意味。呼び出し元のセッションIDをバックエンドスクリプトに送信する手順が必要となる。
Uploadify - Uploadify
scriptDataにJSON形式で任意のパラメータを設定してバックエンドスクリプトに送信することができる。

$(document).ready(function() {
$('#XXX').uploadify({
	:
//JSON形式で任意のパラメータを送信することが可能
'scriptData': {'session_id': '(呼び出し元のセッションID)'},
	:
});
<<

*** バックエンドスクリプトでパラメータ(セッションID)取得
scriptDataにJSON形式でセットされたパラメータは環境変数$_REQUESTで取得することができる。
>|php|
function backend_script(){
	:
	$session_id = $_REQUEST['session_id'];
}
既に開始されているセッション情報を破棄しIDを指定して新たにセッションを開始する

バックエンドスクリプト(backend_script)の冒頭に以下のコードを追加する。

function backend_script(){
	$session_id = $_REQUEST['session_id'];
	if(session_id() != $_REQUEST['session_id']){  // add
	    session_destroy();                        // add
	    session_id($session_id);                  // add
	    session_start();                          // add
	}                                             // add
		:
}
checkAgentの無効化

Authコンポーネントによるユーザー認証が有効な状態(ログオン状態)で上記処理を行うと処理が終了した時点でセッション情報が破棄されログアウト状態になってしまう(ログイン画面に遷移)。
これはCakePHPのSession.checkAgentが有効になっているためである。バックエンドスクリプトはFlashPlayerから呼び出されているためブラウザとは異なるUserAgentを使用している。checkAgentが有効な状態だと同じIDのセッションに異なるUserAgentからのアクセスがあると(不正アクセスとみなして?)これを破棄する仕様になっているらしい。
とりあえずこれを無効にする(一時的に無効にするだけでいける方法を調査する)。

  • /APP/config/core.php
/**
 * When set to false, HTTP_USER_AGENT will not be checked
 * in the session. You might want to set the value to false, when dealing with
 * older versions of IE, Chrome Frame or certain web-browsing devices and AJAX
 */
  Configure::write('Session.checkAgent', false); // true => false


以上!