世界中の共有動画を横断検索。youku.com,youtube,tudou.com,Dailymotionに対応。・・・そんなサービスの開発者ブログ。

みんなの動画サーチ

個人メニュー
最近見た動画

サービス:みんなの動画サーチ   利用できる動画共有サイト : youku.com , youtube , tudou.com , Dailymotion

Ads by Google

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
--------(--)

PHPの良いところ、駄目なところ

 こんな記事があったのでちょっと考えてみました。

PHPは駄目な言語なのか?

 ちなみにこの記事、中身自体はPHPを使った開発を行うときに順守(もしくは注意)したほうが良い事項について書かれたなかなかためになるもの。読んでおいて損はないです。
 これなら「PHPで開発をするときに気をつけたいこと」くらいのタイトルでもよさそうですが、注目を集めるためにあえてセンセーショナルなタイトルにしたのでしょう。私もまんまと釣られました(ちょっと悔しい)

続きを読む

2008-03-22(Sat)

クッキーの最大長は4096バイトまで。

 共有動画サーチでは「最近見た動画」をクッキーに保存しています。
 「最近見た動画」の処理は処理量が増える可能性が高く、データベースを使うと負荷の問題が発生する危険があるためです。クッキーなら保存をJAVASCRIPTで行うことで処理やデータの保存もクライアントサイドに任せられるため、負荷を軽減することができます。

 さてそのクッキーなのですが、最大長がきまっていて、しかもそれが小さいので、利用するときはオーバーしないように工夫しないといけないのですね。設定できる変数は20個まで、各変数は4096バイトまでです。(この件についてはこちらがよくまとまっています)
 この制限がけっこう苦労のもとになります。

 共有動画サーチで「最近見た動画」を保存する処理の場合は、最初、すべての変数が4096バイトを超えないようにしつつ設計しました。保存データを動画IDとタイムスタンプだけに絞り、数を20までにすることで乗り切ったのです。

【データの例】
[[52,20080306094559],[1348,20080306094554]]

 ところがこの設計を前提とした仕様は使い勝手が悪かったのです。
 そこでもう一つの仕様に変更することにしたのですが、そうすると今度は4096バイトに収まりそうにありません。変数1つに20件の動画を保存したいなら、動画1つを約200バイト(200文字)に収めないといけないわけですが、そのもう一つの仕様はサムネイル画像のURL、タイトル、再生時間、タイムスタンプ、タグをクッキーに保存するというものなのです。まず200バイトにはおさまりません。

 仕方がないので変数1つに20個すべて納めるのではなく、変数1に動画1を納める形にすることにしました。ただセッションIDを持たせる必要が生じる可能性を踏まえ、発展余裕として変数2つは予備にまわす必要があるので、使える変数の数は18までです。そのため動画18個の保存に仕様を変更しました。20が18になってもそれほど不便はないので大丈夫でしょう。

 クッキーにセッションIDだけを格納しておき、データ自体はサーバー側に持っておけばこの制限はそれほど問題にはならないのですが、あえて苦難の道を歩みます(笑)

続きを読む

tag : php クッキー 共有動画サーチ

2008-03-06(Thu)

PEARのXML_UnserializerでXMLがうまく読み込めない時があるときは

 XMLをパースしてくれるXML_Unserializerなのですが、本日パースした結果がうまく取得できず、PEAR_ERRORが表示されるという現象に出会いました。

 PEARからのエラーメッセージを見てみると、

No unserialized data available. Use XML_Unserializer::unserialize() first.

 と表示されているのですが、unserialize()ならすでに使っているので、そういうことではなく、別の原因であるようです。

 ではその別の原因とは何か、Googleでそれっぽいキーワードで検索をかけて探っていくと、想定していない文字コードがXMLの中にあるためではないかという仮定を得られました。

 そこで、XMLのテキストデータを渡す前にひと工夫。mb_convert_encoding()を使ってUTF-8に強制的に変換することにしました。
 こんな感じです。

$Xml = mb_convert_encoding($Xml, "UTF-8", "auto");

$unserializer = & new XML_Unserializer();
$unserializer->setOption('parseAttributes',true);
$unserializer->unserialize($Xml);
$result = $unserializer->getUnserializedData();

 結果、うまく通るようになりました。
2008-02-23(Sat)

windowsにLAMPをインストール

 近頃自分のパソコンがどうにも動きが遅くなっていたので、いろんなソフトをインストールしすぎたためであろうと考え、思い切って再インストールしました。

 その結果開発環境のLAMP(いえ、ただしくはWAMPですが)も再インストールの運びとなりました。
 たいていインストーラに従っておこなえば済むものなのですが、今回は少々苦労しました。

 まずAPACHEのhttpd.conf。

 どういうわけか強制終了になってしまうので、どういうわけかと思ってみてみたら、phpが持つ各バージョンに合わせたのDLLをすべて読んでいました。それは誤作動も起ころうというものです。

 次にphp.ini。
 これもなぜかモジュールをうまく読まず、
Unable to load dynamic library ほにゃらら
 と表示されます。こんな感じですね。
Unable to load dynamic library 'C:\\PHP\\ext\\php_mysql.dll'
 DLLが格納してあるextension_dirも間違っていませんし、書式に特にミスもみあたらず、困り果てていたのですが、とあるサイトで「パスが入っていなかったがためにこのエラーが出た」旨を見てひらめきました。

 インストールしてから再起動してなかったのです。ということは、更新されたパスも読んでいないということになります。

 というわけで再起動してみたら、あっけなく動作しました。

 ちょっとしたところに落とし穴があるものです。
2008-02-21(Thu)

MVCモデルに沿った簡単な自作フレームワーク

私がよく利用するのはPHPなのですが、いかに簡単な言語と言われるPHPとはいえそれなりの規模の開発を行うときはフレームワークがないと不便が多いです。
そんなわけで以前はやったMOJAVIによく似た自作のフレームワークを使っているのですが、今回はその基本となる部分をご紹介します。レンダリングエンジンはSmartyです。


class Controller {

//コンストラクタ。
function Controller()
{
}

function Execute($module_name=DEFMODULE,$action_name=DEFACTION)
{
/*
* 判定のためも兼ねてGET,POSTのデータを取得し統合。重複する場合はPOSTのデータが優先。
*/
$Data=array_merge($_GET,$_POST); //GETのデータにPOSTを追加。GETとPOSTの両方に同じキーの変数がある場合、POST優先。
if (get_magic_quotes_gpc()) $Data=stripslashes_deep($Data);

/*
* module,actionを念のためサニタイズしつつ指定。無いならデフォルト値を入力。
*/
$Data['module'] = isset($Data['module']) ? basename($Data['module']) : $module_name;
$Data['action'] = isset($Data['action']) ? basename($Data['action']) : $action_name;
$module_name = $Data['module'];
$action_name = $Data['action'];


/*
* モジュールの場所の指定
*/
$ModuleDir=MODULE_DIR.$module_name.'/';

//モジュールはここで無いと決まらないのでConfigに置けない
define('MODULE_CLASS_DIR',$ModuleDir."class/");


/*
* モジュール共通の事前処理があるならばそれを実行
* ファイルの有無で処理の有無を判断する。
* 1モジュールに対して1フィルタ。
* クラス名はprefileterのみ。
*/
$FilterFileName=$ModuleDir.'filter/premodule.php';
if(is_file($FilterFileName)){
require $FilterFileName;
$Filter = new premodule;
$Filter->setVal($Data); //GETPOSTのデータ
$Filter->Execute();
}


/*
*モデル(Action)の実行
*/
$ActionFileName=$ModuleDir."actions/".$action_name.".php";
if(is_file($ActionFileName)){
require $ActionFileName;
$Action = new $action_name;
$Action->setVal($Filter->Vals,$Data); //PreのデータとGETPOSTのデータ
$Action->Execute(); //指定Action実行。
}else{
$error="Error 該当ページなし [".$module_name."]:[".$action_name."]";
trigger_error($error, E_USER_ERROR);
}
/*
*ビュークラスの宣言&実行。ただしテンプレートの指定が無い場合は実行せず。
*/
if(!empty($Action->tpl)){
$View = new View(new Renderer_Smarty); //このnew Renderer_Smartyを変えるとレンダリングエンジンを変更できる。そのレンダリングエンジン操作クラスを追加実装する必要はあるが。
$View->display($Action->tpl,$Action->Vals,$module_name);
}
}
}

function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);

return $value;
}

class Filter {
var $GPVal;
var $Vals;

//コンストラクタ
function Filter()
{
}

function setVal($GPVal)
{
$this->GPVal=$GPVal;
}

//ここはオーバーライドするところ。
function Execute()
{
}

function sendVal($Key,$Val)
{
$this->Vals[$Key] = $Val;
}
}

class Action {
var $Vals;
var $PreVal;
var $GPVal;
var $tpl;
var $Validator;

//コンストラクタ
function Action()
{
}

function setVal(&$PreVal,&$GPVal)
{
$this->PreVal=$PreVal;
$this->GPVal=$GPVal;

$this->Vals["module"] = $GPVal["module"];
$this->Vals["action"] = $GPVal["action"];

}

function Execute()
{
$Val=$this->GPVal["module"].":".$this->GPVal["Action"]."はオーバーライドが済んでいません";
$this->designateTpl('test.tpl');
}

function sendVal($Key,$Val)
{
$this->Vals[$Key] = $Val;
}

function designateTpl($tpl)
{
$this->tpl = $tpl; //もっともこの指定が無い場合はコントローラがViewが起動させないので重要。
}

function startToken()
{
if(!session_id()) session_start();
$_SESSION["OneTimeToken"] = sha1(session_id().mt_rand().microtime()); //セッションIDを絡めたランダムな文字列。
$this->sendVal("OneTimeToken",$_SESSION["OneTimeToken"]); //TPL側での対応も必要なことに注意されたし。
}

function finishToken()
{
if(!session_id()) session_start();
if($this->GPVal["OneTimeToken"] == $_SESSION["OneTimeToken"]){ //ここが認証。
unset($_SESSION["OneTimeToken"]); //ここがミソ
return true;
}else{
return false;
}
}

function callOther_Action($ActionName,$ModuleName="")
{
if(!class_exists($ActionName)){
if(empty($ModuleName)){
$ModuleName=$this->GPVal["module"]."/";
}
$ModuleDir=MODULE_DIR.$ModuleName.'/';
$ActionFileName=$ModuleDir."actions/".$ActionName.".php";
require $ActionFileName;
}

return new $ActionName;
}

function Validate($GPVal="")
{
//どうしてもオリジナルでかけないといけないものはこんな感じで。
//if($int==15){
// $this->errormessage="15だから駄目";
// return false
//}
return $this->execformalValidate($GPVal);
}

//普段はここをいじる。
function & setValidate($GPVal=""){
$Validator = new Validator();
//$Validator->setRule_Numeric($this->int);//例
return $Validator;
}

//ここはいじらないでも済むように。
function execformalValidate($GPVal=""){
$this->Validator = $this->setValidate($GPVal);
$Iterator = $this->Validator->Iterator(); //Iteratorの取得。
$Check=true;
while(list($key,$Rule)=$Iterator->hasnext()){ //each()を使うのでlistで受けている。
//なんか密度高いなー。Iteratorにした意味が無い気がしてきた。
if($Rule->checkRule()){
unset($this->Validator->Message[$key]);
}else{
$Check=false;
}
}
return $Check;
}

function redirect($URL)
{
if(NOWTESTING==1){
print get_class($this)."にて[ $URL ]へリダイレクトがかかりました
";
return;
}

redirect($URL);
}

}

class View {
var $Renderer;
function View($Renderer)
{
$this->Renderer = $Renderer;
}

//レンダリングクラスに表示させるだけ。
function display($templatename,&$RetData,$module_name)
{
$this->Renderer->setConfig($module_name);
$this->Renderer->display($templatename,$RetData);
}
}

class Renderer_Smarty {
var $Smarty;
function setConfig($module=DEFMODULE) //初期設定。Smartyの宣言と設定だけを行う。configの定数群をちゃんとしないとエラーになる。
{
require_once(SMARTY_DIR.'Smarty.class.php');

//モジュールごとにフォルダを作らないと別のModuleに同名のActionがあったときにキャッシュが誤動作を引き起こす。
if(!is_dir(SMARTY_DATA_DIR.$module."/")) mkdir (SMARTY_DATA_DIR.$module."/");
if(!is_dir(SMARTY_DATA_DIR.$module."/templates_c/")) mkdir (SMARTY_DATA_DIR.$module."/templates_c/");
#chmod(SMARTY_DATA_DIR.$module."/templates_c/", 0777);
if(!is_dir(SMARTY_DATA_DIR.$module."/configs/")) mkdir (SMARTY_DATA_DIR.$module."/configs/");
#chmod(SMARTY_DATA_DIR.$module."/configs/", 0777);
if(!is_dir(SMARTY_DATA_DIR.$module."/cache/")) mkdir (SMARTY_DATA_DIR.$module."/cache/");
#chmod(SMARTY_DATA_DIR.$module."/cache/",0777);

$this->Smarty = new Smarty;
$this->Smarty->register_modifier("make_links_blank", "make_links_blank");
$this->Smarty->register_modifier("number_format","number_format");
$this->Smarty->template_dir = MODULE_DIR.$module."/templates/";
$this->Smarty->compile_dir = SMARTY_DATA_DIR.$module.'/templates_c/';
$this->Smarty->config_dir = SMARTY_DATA_DIR.$module.'/configs/';
$this->Smarty->cache_dir = SMARTY_DATA_DIR.$module.'/cache/';
$this->Smarty->clear_compiled_tpl(); //キャッシュの誤動作が有る場合はここを動作させる。
}

//HTMLだけを返す。
function & fetch($templatename,&$RetData)
{
if(empty($templatename)) return false;
if(is_array($RetData)){
foreach($RetData as $key => $value){
$this->Smarty->assign($key,$value);
}
}

$Html = $this->Smarty->fetch($templatename);

return $Html;
}

//fetchで取ったデータをprintで表示するだけ。
function display($templatename,&$RetData)
{
print $this->fetch($templatename,$RetData);
}

}
2008-02-16(Sat)

 みんなの動画サーチ 現在の人気動画

RSSフィード
最近の記事
月別アーカイブ
カテゴリー
逆アクセスランキング
プロフィール

Author:ナカタツ
 共有動画サーチの開発をやっているフリーランサーです。プログラム歴は趣味で使っていた頃も合わせるとちょうど今年で10年目。最近はPHPばかり使ってます。
 私に興味を持ってくださる方はお気軽にご連絡ください。Skypeでお話できる人歓迎。メールフォームはこちら

カレンダー
10 | 2009/11 | 12
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 - - - - -

みんなの動画サーチへ戻る

カテゴリ:芸能・テレビ | 音楽 | アニメ | おもしろ | 神・衝撃 | ゲーム | 動物 | スポーツ | 時事ニュース | 自然・歴史 | 車・バイク | セクシー


アクセス解析 アクセスランキング
  • seo

Powered by FC2 Blog

FC2Ad

FC2ブログ

Copyright © みんなの動画サーチ開発者ブログ All Rights Reserved.