[Site] 音声機能 その1

タグ :

作成サイト「koweboo」についてまとめるシリーズです。
今回はユーザーがアップロードする「音声」の処理についてまとめます。
かなり長くなるので何回かに分けて書きます。
今回は「音声アップロード」についてです。

作成サイト内の関連箇所 — 「こうぇ一覧

ファイルアップロードについて

音声をサイトへアップロードするには、大きく分けて二つの方法があります。

  1. ファイルをサーバの専用フォルダへコピーして保存する
  2. ファイルを文字データとしてデータベースへ保存する

1 のファイルをコピーする方は、データベースには保存したファイル名を格納しておきます。
また、専用のフォルダを設ける必要があるのと、コピーするので多少の時間が掛かってしまいます。
さらには、HTMLソースから音声ファイルを探すことが出来てしまうため、ダウンロードされてしまいます。
(勝手にダウンロードするのは違法ですのでやめましょう。)

2 のデータベースに保存する方は、アップロードするのも早く、フォルダを設ける必要も無いのですが、ページを表示する度に文字列化された多量の音データを取得してくる必要があるので、処理が重くなりがちです。
さらに、致命的なのが取得した音データを扱うのが難しいという点です。
ぶっちゃけよく分かりません。

他にもあるのかもしれませんが、代表的にはこの二つだと思われます。
二つとも多少のデメリットがありますが、今回は 1 のファイルをコピーする方でやりたいと思います。
理由は、2 の方はよく分からないからです。
1 の方のデメリットの解決策は後に考えるとして、とりあえず出来るようにしたいと思います。

基本仕様

音声をアップロードできるのは「お題」に対してのみとします。
つまり、お題が無ければ音声はアップロードできないことになります。

音声もお題と同じでログインしているユーザーが自由にアップロードできるものとします。
できるだけお題に関係しないものはアップロードしないようにしましょう。

音声アップロードに必要な情報は以下になります。

  • 音声タイトル
  • お題ID
  • アップロードユーザーID
  • ファイル名

テーブル作成

音声テーブルには以下のフィールドを設けます。

[voices]
フィールド名 名称 説明
id 音声ID 主キー
user_id ユーザーID アップロードするユーザーID
request_id お題ID アップロードするお題ID
title 音声タイトル 音声の題目(一覧表示用・ひとこと用)
filename ファイル名 音声ファイル名
created アップロード日 アップロードした日付

基本ファイル生成

いつも通りに Bake で済ませます。
voices は MVC 全てを Bake します。
以下のファイルが生成されます。

[Model]
 - Voice.php
[View]
 - [Voices]
   - add.ctp
   - edit.ctp
   - index.ctp
   - view.ctp
[Controller]
 - VoicesController.php

モデルの「Voice.php」には前回までに作成した「User」や「Request」の ID が含まれるため、自動でアソシエーションが行われます。

public $belongsTo = array(
	'User' => array(
		'className' => 'User',
		'foreignKey' => 'user_id',
		'conditions' => '',
		'fields' => '',
		'order' => ''
	),
	'Request' => array(
		'className' => 'Request',
		'foreignKey' => 'request_id',
		'conditions' => '',
		'fields' => '',
		'order' => ''
	)
);

アソシエーションの詳しい説明は過去記事「[CakePHP] 基礎(モデル)」を参照してください。

アップロードフォームの作成

まずは、音声をアップロードできるフォームを作成します。
アップロードフォームは音声を追加する部分である「add.ctp」を編集します。
ソースコードは以下になります。

<div class="voices form">
<h2><?php echo __('New Voice'); ?></h2>
<?php
	echo $this->Form->create('Voice', array(
		'type' => 'file'
	));
	echo $this->Form->hidden('user_id', array(
		'value' => $user_id
	));
	echo $this->Form->input('request_title', array(
		'label' => __('request_title'),
		'value' => $req_title,
		'disabled' => 'disabled'
	));
	echo $this->Form->hidden('request_id', array(
		'value' => $req_id
	));
	echo $this->Form->input('title');
	echo $this->Form->file('voice_data');
	echo $this->Form->end(__('Add Voice!'));
?>
</div>

5行目typefile にすることでファイルを取り扱うフォームに変更できます。
お題タイトルの入力フォームを設けていますが、変更できないように「disabled」としています。
いらない気もしますが、どのお題に対してアップロードを行うかを分かりやすくするために、あえて表示させてみました。

登録処理作成

続いてはコントローラにて登録処理を作成します。
コントローラ(VoicesController.php)のファンクション「add()」を編集します。

public function add($id = null) {
	// ログインユーザー情報
	$user = $this->Auth->user();
	// 追加処理
	if ($this->request->is('post')) {
		// 音声情報チェック
		if ($this->request->data['Voice']['voice_data']['name']
			&& $this->request->data['Voice']['title']) {
			// 音声情報取得
			$voice = $this->request->data['Voice']['voice_data'];
			// 音声種別チェック
			if ($voice['type'] == VOICE_FILETYPE) {
				// ファイル名編集
				$voiceName = md5(microtime());
				$fileName = VOICE_UPLOAD.$voiceName.VOICE_FILEEXT;
				// 音声アップロード
				if(move_uploaded_file($voice['tmp_name'], $fileName)) {
					$this->request->data['Voice']['filename'] = $voiceName;
					$this->Voice->create();
					if ($this->Voice->save($this->request->data)) {
						$this->Session->setFlash(__('The voice has been saved.'));
						$this->redirect(array('controller' => 'requests', 'action' => 'view', $id));
					} else {
						// 登録失敗時
						$this->Session->setFlash(__('The voice could not be saved. Please, try again.'));
					}
				} else {
					// 音声アップロード失敗時
					$this->Session->setFlash(__('The voice could not be saved. Please, try again.'));
				}
			} else {
				// 音声種別が違う場合
				$this->Session->setFlash(__('Only mp3-file it can register.'));
			}
		} else {
			// 登録内容が未入力時
			$this->Session->setFlash(__('The file is not selected, or, title is not input.'));
		}
	}
	// 投稿情報
	$requests = $this->Voice->Request->find('first', array(
		'conditions' => array('Request.id' => $id)
	));
	// ビューへ値渡し
	$this->set('user_id', $user['id']);
	$this->set('req_id', $requests['Request']['id']);
	$this->set('req_title', $requests['Request']['title']);
}

かなり分岐処理の多いソースになってしまいましたが、以下に説明を書きます。

5行目の分岐にて、POST送信されているかを確認します。
POST送信でなければ、41行目〜 のアップロード画面に必要なデータを取得する処理を実行します。

7,8行目の分岐にて、「ファイルの選択されているか」と「音声タイトルの記入があるか」を確認しています。
無ければエラーメッセージと共にアップロード画面へ戻ります。

12行目の分岐にて、「選択された音声ファイルの種別は適切か」を判定しています。
今回使用する音声種別は「audio/.mp3」です。それ以外だとエラーです。

14行目の処理にて、ファイル名として使用する乱数値を取得しています。
この関数(microtime())は、32桁の16進数をランダムで生成するので、まず名前が被ることは無いと思います。

15行目では、生成したファイル名を用いて「コピー先のパス & ファイル名 & 拡張子」をまとめています。

17行目の処理にて、ファイルのアップロードを行っています。
アップロードに失敗するとエラーとなります。
成功するとサーバの指定フォルダ内へ生成した乱数値のファイル名が追加されます。

後は、登録処理になります。
分岐処理が多すぎる気がしますが、もっとスマートに出来ればなと思っております。
後々変更したいです。。。

長くなりましたが、表示させてみると以下のようになります。

site_voice_add

ファイル選択箇所の文字が切れてしまっていますが、そこは CSS を修正してください。

次は一覧表示についてですが、続きは次回に。。。

Share

  • このエントリーをはてなブックマークに追加

Comment

コメントを残す

*がついている欄は必須項目です。

  • Twitter
  • Facebook
  • Google Plus
  • RSS Feed