Component」カテゴリーアーカイブ

CakePHP1.3 prefixで携帯の処理を行っている場合の文字コードの注意

App.encodingの設定で文字化け発生

CakePHPの1.3の途中からFormHelperRequestHandlerのコードにcore.phpのConfigure::write(‘App.encoding’, ‘encoding’);
で設定された値を使う箇所が出てきています。

prefixで携帯の表示を処理している場合、設定された文字コードによって文字化けの影響を受けるおそれがあります。

例えば、UTF-8で作成していて、携帯の出力時に全てShift_JISに変換している場合です。

最初はbeforeRender()内で
Configure::write(‘App.encoding’, ‘Shift_JIS’);
ってやればいいんじゃないの??って思ったけど、
やってみると微妙に文字化けが発生orz

grepしてみると、他にはmultibyte.phpの中などに、App.encodingの値を設定している箇所がある。

どこかで影響を受けているのだろうが、ちゃんとは調べていない;;

とりあえず、RequestHandlerとFormの部分だけ対処すれば文字化けはしない。

以下に対処の方法をメモ。

RequestHandlerComponent

症状

debug値 < 2 の場合にstartup()内で、HTTPのヘッダでtext/htmlのcharsetにApp.encodingが設定される。
したがって、App.encodingの値で表示しようとするため文字化けする。

対処

startup()はbeforeRender()の前に呼ばれるので、

beforeRender(){
    if($this->Ktai->is_ktai()){
        $this->RequestHandler->respondAs('html', array('charset' => 'Shift_JIS'));
    }
}

を追記。

FormHelper

症状

FormHelper::create()内で’encoding’オプションにApp.encodingが設定される。
このencodingオプションはaccept-charset属性の値を設定する。
したがって、携帯の機種によっては、accept-charsetに設定された文字コードでフォームの値が送信されてくる可能性がある。
送られてきた値をサーバー側で変換すると文字化けが発生する。

対処

対処は3つほど考えられる。

1.create()のencodingオプションを全てに追加する。

$this->Form->create('Hoge', array('encoding' => 'shift-jis'));

2.強引に置換。
app_controller.phpのafterFilter内に

if($this->Ktai->is_ktai()){
    $this->output = str_replace('accept-charset="utf-8"', 'accept-charset="shift-jis"', $this->output);
}

3.FormHelperを継承してKtaiFormHelperを作る。
名前は何でもいいと思うけど、ここではKtaiFormHelperを作る。
さらに、HackPluginを使って、View側のコードをいじらないで済むようにする。
Hack Pluginは@hiromi2424さんが作成された、コンポーネントやヘルパーのエイリアスの設定を行ってくれるとても便利なプラグインです。
Hack Pluginの設置
githubからダウンロードしたものを次のように配置する。
app/plugins/hack

/app/views/helpers/ktai_form.php

class KtaiFormHelper extends FormHelper{
     public $helpers = array('Ktai', 'Html');
     public $settings = array(
          'encoding' => 'shift-jis',
     );
     
     function __construct($settings){
          $this->settings = am($this->settings, $settings);
     }
     function create($model = null, $options = array()){
          // e.g.携帯の判定を行って値を変更する
          if($this->Ktai->is_ktai()){
               $options = am($this->settings, $options);
          }
          return parent::create($model, $options)
     }
}

app/controllers/app_controller.php

//e.g.AppControllerにHelperを読み込む場合
class AppController extends Controller{
     public $helpers = array('KtaiForm', 'Hack.Alias' => array('Form' => 'KtaiForm'));
}

これで、View内で$this->KtaiForm->create()ってしなくても
$this->Form->create()で呼び出せます。

つまりは既存のView側のコードのヘルパー名を変更しなくて済みます。

CakePHP + ZendFramework (Gdata)でYouTubeアプリ作成

ZendFramework (Gdata)を使ってYouTubeのデータを操作

ZendFrameworkのGdataを使用して、YouTubeのデータ処理を行ってみました。

概要

YouTubeのAPIには
動画のデータ操作を行うData API
プレイヤーの操作を行うPlayer APIがあります。
この2つのAPIを利用して以下を行います。

  • YouTubeのApiを使って、ほしいデータを検索(Data API)
  • HP上に動画プレイヤーを設置する(Player API)
  • 検索した動画を設置した動画プレイヤーで再生する

他にも動画のアップロード等ができますが、そちらは、参考資料を参考にしてください。
クライアントライブラリはPHPとjavascriptだけではなく、Javaなどのほかの言語でも提供されています。

完成イメージ

環境

参考資料

Zend Gdataの設定

  • 上記のリンクからGdataの圧縮ファイルをDL&展開しておく
  • 展開したなかのlibraryディレクトリの中のZendディレクトリをvendorsまたはapp/vendorsに設置する。i.e.vendors/Zend or app/vendors/Zend
  • ここからZendFrameworkLoader Componentを作成する。i.e. app/contorollers/components/zend.phpを作成

app/contorollers/components/zend.php

<?php
class ZendComponent extends Object {

	/**
	 * Controller Startup Initialisation 
	 * Add APP/vendor to include path 
	 *  
	 * @throws Exception 
	 */
	public function startup() {
		$include = get_include_path();
		// Zendディレクトリをapp/vendorsに設置した場合
//		$include.= PATH_SEPARATOR . APP . 'vendors' . DS;
		// Zendディレクトリをvendorsに設置した場合
		$include.= PATH_SEPARATOR . VENDORS;
		$successful = set_include_path($include);

...........

}
?>

Controllerの作成

app/controllers/youtube_controller.php

<?php
class YoutubeController extends AppController{
	public $name = 'Youtube';
	public $uses = '';
	public $layout = 'default';
	public $components = array('Zend');
	
	public function index(){
		// YouTubeクラスのロード
		$this->Zend->loadClass('Zend_Gdata_YouTube');
		$yt = new Zend_Gdata_YouTube();
		// Queryの作成
		$query = $yt->newVideoQuery();
		$query->videoQuery = '世界卓球 -パチンコ -AKB';
		$query->startIndex = 1; // 開始番号
		$query->maxResults = 10; // 検索取得数
		$query->orderBy = 'viewCount'; // 閲覧数順
		
		// Feedの取得
		$videoFeed = $yt->getVideoFeed($query);
//		$videoFeed = $yt->getUserFavorites('username'); // ユーザのお気に入りの動画を取得
		// 取得したFeedをView変数に設定する
		$this->set('videoFeed', $videoFeed);
	}
}
?>

ZendFrameworkは使ったことがなかったので、知らなかったのですが、
クラス名はディレクトリの階層をアンダーバー”_”で区切ってつけられています。
たとえば。。
Zend_Gdata_YouTubeクラスは
Zend/Gdata/YouTube.phpにあります。
この命名規約のため階層が深くなれば、newするときのメソッド名が長くなります。
短くするために、上のコードのように
$query = $yt->newVideoQuery();
でnewできるようになっています。
VideoQueryは実際は、
Zend/Gdata/YouTube/VideoQuery.php
にあります。

さらに、$query->startIndexとメンバ変数のように設定している箇所があります。
しかし、クラス、継承しているクラスを見てみると、そのようなメンバ変数はありません。
ここの実際のメソッドはsetStartIndex()です。
setter&getterはメンバ変数のように扱える仕組みになっているようです。

Viewの作成

app/views/layouts/default.ctp

.....
<head>
	<?php echo $this->Html->charset(); ?>
	<title>
		<?php __('CakePHP: the rapid development php framework:'); ?>
		<?php echo $title_for_layout; ?>
	</title>
	<?php
		echo $this->Html->meta('icon');

		// ==============================================
		// CSS
		// ==============================================
		echo $this->Html->css('cake.generic');
		
		// ==============================================
		// javascript
		// ==============================================
		echo $this->Html->script('swfobject');
		echo $this->Html->script('jquery-1.4.3.min');
		echo $scripts_for_layout;
	?>
</head>
.......

app/views/youtube/index.ctp

<!-- TEST作成のため、CSSは直接書いている-->
<h1>test</h1>
<div id="yt" style="width: 800px;margin: auto;">
	<div style="float: left;">
		<div id="ytapiplayer">
		You need Flash player 8+ and JavaScript enabled to view this video.
		</div>
	</div>
	<div style="margin-left: 5px; float: left;width:260px; height:375px; overflow: scroll;">
		<?php
		foreach ($videoFeed as $videoEntry) {
			// サムネイルの取得
			$videoThumbnails = $videoEntry->getVideoThumbnails();
			// サムネイルは4つ取得できる(ここでは1つだけ表示した)
			foreach ($videoThumbnails as $thumbnail) {
				echo $this->Html->image($thumbnail['url'], array('height' => 90, 'width' => 120, 'id' => $videoEntry->getVideoId(), 'class' => 'youtube', 'title' => $videoEntry->getVideoTitle(), 'alt' => $videoEntry->getVideoTitle()));
				break;
			}
		}
		?>
	</div>
</div>
<script type="text/javascript">
	var ytplayer = null;
	// playerの準備が完了後に呼び出されるコールバック
	// playerを制御するには必ず実装が必要
	function onYouTubePlayerReady(playerid){
		// プレイヤーを取得(swfobjectで指定したidを指定する)
		ytplayer = document.getElementById("myytplayer");
//		ytplayer.cueVideoById();
	}
	
	var params = { allowScriptAccess: "always" };
	var atts = { id: "myytplayer" };
	swfobject.embedSWF("http://www.youtube.com/v/u1zgFlCw8Aw?enablejsapi=1&playerapiid=ytplayer", 
	"ytapiplayer", "500", "375", "8", null, null, params, atts);
	$(function(){
		$("img.youtube").click(function(){
			ytplayer.loadVideoById($(this).attr("id"));
		});
		$("img.youtube").hover(function(){
			$(this).css("cursor", "pointer")
				.fadeTo("fast", 0.5);
		},function(){
			$(this).fadeTo("fast", 1);
		})
	});
	
</script>

imgタグのid属性に動画のidを設定しています。
サムネイルがクリックされたときに、その動画が再生されます。

CakePHP キリ番判定Component

一般的なキリ番を判定するComponentを作成してみました。

使いどころはあまりないかも知れませんが、
カウントを判定して、Twitterでつぶやくなどですかね。。。

使い方

  1. Controllerに追加
  2. Controllerの$kiribanでオプションの変更
  3. $this->Kiriban->isKiriban($number);戻り値は判定したキリ番の種類or false

判定の種類

2桁以上の数字を判定します。

  • ゾロ目
  • ミラー
  • 単位
  • カウントアップ
  • カウントダウン

コード

【修正 : 2011/04/19】
eregの部分をpreg_matchに変更しました。