2011年12月27日火曜日

HTML5 - Canvas 円同士の衝突アニメーション

<canvas id="hoge" width="400" height="400"></canvas>

<script type="text/javascript">
var canvas = document.getElementById("hoge");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

var g = 0.1;
var circles = [];
var time = 0;
var colorList = ['0','1','2','3','4','5','6','7',
                 '8','9','a','b','c','d','e','f'];

var tm;
tm = setInterval(main,10);

function main(){
 ctx.clearRect(0,0,cw,ch);
 if(time>100 || time==0){
  time = 0;
  circles.push(new Circle());
  circles[circles.length-1].init(circles.length%2);
 }
 for(i=0;i<circles.length;i++){
  for(j=i+1;j<circles.length;j++){
   collisionCircleCircle(circles[i],circles[j]);
  }
 }
 for(i=0;i<circles.length;i++){
  circles[i].move();
  circles[i].collisionWall();
  circles[i].view();
 }
 time++;
}

function Circle(){
 this.h = 0.9; this.x = 0; this.y = 100;
 this.vx = 0; this.vy = 0; this.r = 0;
 this.color = '#';
 
 this.init = function(vec){
  this.vx = Math.random()*9+1;
  this.r = Math.random()*25+5;
  if(vec){
   this.x = cw+100;
   this.vx *= -1;
  }else{
   this.x = -100;
  }
  this.color += colorList[Math.floor(Math.random()*3)+3];
  this.color += colorList[Math.floor(Math.random()*5)+5];
  this.color += colorList[Math.floor(Math.random()*7)+9];
 }
 
 this.move = function(){
  this.x += this.vx;
  this.y += this.vy;
  this.vy += g;
 }
 
 this.view = function(){
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.r, 0, 360,false);
  ctx.fill();
 }
 
 this.collisionWall = function(){
  if(this.x+this.r > cw && this.vx > 0 || 
    this.x-this.r < 0 && this.vx < 0){
   this.vx *= -this.h;
  }else if(this.y+this.r > ch && this.vy > 0 || 
    this.y-this.r < 0 && this.vy < 0){
   this.vy *= -this.h;
  }
 }
}

function collisionCircleCircle(a,b){
 if((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y) < (a.r+b.r)*(a.r+b.r)){
  var vx = a.x-b.x;
  var vy = a.y-b.y;
  var len = Math.sqrt(vx*vx+vy*vy);
  var d = a.r+b.r-len;
  if(len>0) len =1/len;
  
  vx *= len;
  vy *= len;
  
  d /= 2.0;
  a.x += vx*d;
  a.y += vy*d;
  b.x -= vx*d;
  b.y -= vy*d;
  
  var t;
  t = -(vx*a.vx+vy*a.vy)/(vx*vx+vy*vy);
  var arx = a.vx+vx*t;
  var ary = a.vy+vy*t;

  t = -(-vy*a.vx+vx*a.vy)/(vy*vy+vx*vx);
  var amx = a.vx-vy*t;
  var amy = a.vy+vx*t;

  t = -(vx*b.vx+vy*b.vy)/(vx*vx+vy*vy);
  var brx = b.vx+vx*t;
  var bry = b.vy+vy*t;

  t = -(-vy*b.vx+vx*b.vy)/(vy*vy+vx*vx);
  var bmx = b.vx-vy*t;
  var bmy = b.vy+vx*t;
  
  var e = 0.8;
  var adx = (a.r*amx+b.r*bmx+bmx*e*b.r-amx*e*b.r)/(a.r+b.r);
  var bdx = -e*(bmx-amx)+adx;
  var ady = (a.r*amy+b.r*bmy+bmy*e*b.r-amy*e*b.r)/(a.r+b.r);
  var bdy = -e*(bmy-amy)+ady;
  
  a.vx = adx+arx;
  a.vy = ady+ary;
  b.vx = bdx+brx;
  b.vy = bdy+bry;
 }
}
</script>

2011年12月26日月曜日

一人レーベル

津田さんの音楽業界の本を読んだのでだらだらまとめておきます。読み返してないので間違ってるところもあると思います。

音楽業界は、レコード会社が牛耳っていたが、最近はそうもいかなくなってきています。それも結構前からそうもいかなくなっております。昔はカセットテープでしたしもっと前はレコードでした。エジソンが発明したレコード再生機は非常に高価で宝石商などが扱う高級品でした。カセットテープになり、再生機のコモディティ化に伴い音楽産業が拡大しました。

その後CDが出来まして、カラオケも流行りまして、CMタイアップも流行りまして、小室的な画一的なサビさえよけりゃどうでもいい的音楽が繁栄しました。音楽業界に絡む事業主体が増え、音楽を追求するというより儲かる音楽ありきのビジネスに音楽業界全体が突き進んだ時期です。このときレコード会社を主軸とする音楽業界の最盛期を迎えました。

しかし今は、変わりました。CDからMP3に代わり、より簡単にコピーができるようになりました。インターネットの発展に伴い、グローバルに瞬時に音楽共有ができるようになりました。ナップスターの登場以降その交換は当たり前のものになり、CDの価値は低下し続けました。またエンターテインメントの種類や媒体も多様化され、DVDがあらゆるエンターテインメントを安価で提供することとなり、これらもCD消費を減退させる一因になりました。CD消費は急激に減退する中で、ライブの売り上げはフジロックなどのフェアの成功もあり増加傾向になっています。

さて、レコード会社の機能は、音楽家の発掘、音楽の作成(CD化)、プロモーションの3機能がメインになりますが、MP3にせよCDーRにせよ非常に安価に作成出来る時代に今は来ています。またメジャーデビューして多大なプロモーションをうったとしても意外と儲からない時代になっています。また音楽家の発掘についても、そもそも儲からず、会社の成長が下降傾向にあるレコード会社は発掘するモチベーションも低下しています。そこで提案されているのが、一人レーベルというものです。

発掘は主体的にインターネットのソーシャルメディアを活用することでファンと直接的コミュニケーションをとりながら、レコード会社という巨人一名に発掘してもらうのではなく、多数の一般ピープルから発掘してもらう方向にシフトすればいいのではということです。音楽作成はローコストで出来るし、プロモーションも発掘同様にソーシャルメディアの一員となりましょうということでした。ライブも重要な収入源としなければならないし、ライブ参加者限定のCD発売などメジャーからマイナーに指向をシフトしてファンクラブ的概念を音楽活動の主軸にしていこうぜということでした。

ちなみに、音楽のレンタルは立教大学の3人の学生が始めたのですが、はやりました。瞬間的に全国でレンタルショップが出来上がり、レコード会社など既存の音楽産業既得権益者が裁判を起こしましたが、既存レンタルショップがすでに非常に多くの数になっていたこともあり、レンタルショップを潰さない妥協案が判決となりました。iTunseは全世界で流行ってますが、日本はレンタルショップの存在も大きく、メジャーレコードがiTuneseに存在しないといった状況もあることから、他国に比べるとiTunseの成功は控えめでした。

この一人レーベルは当然ながら音楽だけにしか適用できない話ではなく、全てのUGCに適用できます。個人が表現し、そのアウトプットを商材にするような業界は全て当てはまります。電子書籍は上記の音楽の発展の経緯と類似しているといわれており、今比較しながら議論されるケースが多いです。自炊の裁判は、音楽レンタルと照らし合わせて、むやみに禁止しては行けないのでは?発展を阻害するのでは?といった議論があるのかなと思います。そしてその一人レーベル化を促すプラットフォームづくりがあらゆる分野で取り組まれている状況です。

2011年12月25日日曜日

PHP - 集合に関する関数

PHPで集合に関する操作をしたいので、関連する関数を調べます。今cakePHPでプログラムしているのでcakePHPを使います。

参考:PHP Arrays as Stacks, Queues and Set(スタック・待ち行列・和集合)

Controller

public function test(){
 $a = '1,2,3,4,5,6,7';
 $a = split(',',$a);
 $b = array(1,3,5,7,9,11,13);
  
 $merge = array_merge($a,$b);
 $set = array_unique($merge);
 $diff = array_diff($a,$b);
 $diff_assoc = array_diff_assoc($a,$b);
 $intersect = array_intersect($a,$b);
  
 $data = array(
  'merge' => $merge,
  'set' => $set,
  'diff' => $diff,
  'diff_assoc' => $diff_assoc,
  'intersect' => $intersect
 );
  
 $this->set('data',$data);
}

View

<?php 
 echo 'merge: ';
 foreach($data['merge'] as $a){
  echo $a. ' , ';
 }
 echo '<br /><br />';
 
 echo 'set: ';
 foreach($data['set'] as $a){
  echo $a. ' , ';
 }
 echo '<br /><br />';
 
 echo 'diff: ';
 foreach($data['diff'] as $a){
  echo $a. ' , ';
 }
 echo '<br /><br />';
 
 echo 'diff_assoc: ';
 foreach($data['diff_assoc'] as $a){
  echo $a. ' , ';
 }
 echo '<br /><br />';
 
 echo 'intersect: ';
 foreach($data['intersect'] as $a){
  echo $a. ' , ';
 }
 echo '<br /><br />';
?>

結果

merge: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 3 , 5 , 7 , 9 , 11 , 13 , 

set: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 9 , 11 , 13 , 

diff: 2 , 4 , 6 , 

diff_assoc: 2 , 3 , 4 , 5 , 6 , 7 , 

intersect: 1 , 3 , 5 , 7 , 

まとめ

array_merge($a,$b)単純に配列$aの後ろに配列$bをつなげて出力する
array_unique($merge)配列の要素から重複を取り除いて出力する
array_diff($a,$b)配列$aにあって、配列$bにない要素のみ出力する
array_diff_assoc($a,$b)array_diffと基本的に同じだが、配列$aと配列$bを比較する際に、キーの一致も確認する。今回の場合、キーと値のペアが一致するのは、1のみである為、配列$aの1以外の数字が出力された。
array_intersect($a,$b)配列$aにも配列$bにもある要素のみ出力する。

cakePHP - RequestHandlerとJSONレスポンス

RequestHandler

★RequestHandlerコンポーネント★

RequestHandlerコンポーネントを使うと、クライアントの状態をチェックできる。GETによるアクセスなのか、POSTによるアクセスなのか、Ajaxによるアクセスなのか、などが分かる。

RequestHandlerを使うには、コントローラの$componentsにRequestHandlerを追加する必要がある。

public $components = array('RequestHandler');
$this->RequestHandler->isGet → GETによるアクセスかどうか
$this->RequestHandler->isPost → POSTによるアクセスかどうか
$this->RequestHandler->isSSL → SSL(HTTPS)アクセスかどうか
$this->RequestHandler->isAjax → Ajaxによるアクセスかどうか
$this->RequestHandler->isXml → XMLレスポンスを受け付けるかどうか
$this->RequestHandler->isRss → RSSレスポンスを受け付けるかどうか
$this->RequestHandler->isAtom → Atomレスポンスを受け付けるかどうか
$this->RequestHandler->isMobile → モバイルからのアクセスかどうか

クライアントの状態チェック以外にも使える。例えば、cakePHPのアクションがHTMLではなくJson形式でレスポンスしたいといった場合に、コンテンツの形式を変更できる。


Ajax処理のJSON出力

[CakePHP]Ajax処理のJSON出力を共通化する

というページで、cakePHPでJSON出力する際の便利なコードが書いてある。これを使えば、Ajaxの仕組みを作る度にctpファイルを作るというめんどうな作業がなくなる。ちなみにこのページのコードでは下記でRequestHandlerを使っている。

$this->RequestHandler->setContent('json');
$this->RequestHandler->respondAs('application/json; charset=UTF-8');

このページのコードを使えば、$this->set($data);を使う代わりに、$this->_renderJson($data);を使うだけで、JSON形式で出力できる。あとは、viewでjavascriptのコードを書いて、Ajaxでコントローラーのアクションにアクセスし、ゲットしたJSONを使えばいい。

下記はjavascriptのコード例。jQueryを使っている。#bookSearchをクリックしたらbooksearch()が起動して、#bookSearchTextの内容を./book_searchアクションに渡している。アクションのJSONレスポンスをもとに、#book_infosに本の情報やページ情報を記載している様。

$(function(){
    $('#bookSearch').click(function(){booksearch();});
});

function booksearch_ajax(keyword,page){
 $.ajax({
  type: "POST",
  dataType: "json",
  data: {"keyword":keyword,'page':page},
  url: "./book_search",
  success: function(data){
   if(data != '') {
         $('#book_infos').empty();
          writeBookInfo(data);
          writePage(data);
   }
  }
 });
}

function booksearch(){
 var keyword = $('#bookSearchText').val();
 var page = 1;
 booksearch_ajax(keyword,page);
}

2011年12月13日火曜日

cakePHP - twitterAPIを使う

cakePHPでtwitterAPIを使う。超分かり易くて簡単なライブラリがあった。

Consuming OAuth-enabled APIs with CakePHP

このページからライブラリをダウンロードして、vendorsに、OAuthフォルダをそのまま格納する。
そして、controllerとviewにそれぞれ下記のようなコードを書く。
※コールバック用URLとコンシューマーキー、コンシューマーシークレットは状況に合わせて入力する必要がある


hoge_controller.php
<?php 
App::import('Vendor', 'oauth', array('file' => 'OAuth'.DS.'oauth_consumer.php'));

class HogeController extends AppController{
    public $name = 'Hoge';
    public $uses = Null;
 
    function index(){
        //セッションからアクセストークンの取得
        $accessToken = $this->Session->read('twitter_access_token');
        if(!empty($accessToken)){
            $consumer = $this->createConsumer();
            //認証情報の確認
            $user_data = $consumer->get($accessToken->key, $accessToken->secret,
                'http://api.twitter.com/1/account/verify_credentials.json');
            $user_data = json_decode($user_data);
            if(!$user_data->id){
                $this->redirect('./login');
            }
            $this->set('user_data',$user_data);
        }else{
            $this->redirect('./login');
        }
    }

    public function login(){
  
    }
 
    public function logout(){
        $this->Session->delete('twitter_access_token');
        $this->redirect('./login');
    }
 
    public function twitter() {
        $consumer = $this->createConsumer();
        $requestToken = $consumer->getRequestToken('https://api.twitter.com/oauth/request_token', 'http://コールバックURL');
        $this->Session->write('twitter_request_token', $requestToken);
        $this->redirect('https://api.twitter.com/oauth/authorize?oauth_token=' . $requestToken->key);
    }

    public function twitter_callback() {
        $requestToken = $this->Session->read('twitter_request_token');
        $consumer = $this->createConsumer();
        $accessToken = $consumer->getAccessToken('https://api.twitter.com/oauth/access_token', $requestToken);
        $this->Session->write('twitter_access_token', $accessToken);
        $this->redirect('./');
    }

    private function createConsumer() {
        return new OAuth_Consumer('コンシューマーキー', 'コンシューマーシークレット');
    }
}
?>


index.ctp(index用のview)
<h1>Hoge!</h1>
<img src="<?php echo $user_data->profile_image_url;?>" width="24" height="24" />
<?php echo $user_data->screen_name; ?>
 ( <a href="./logout">Logout?</a> )


login.ctp(login用のview)
<h1>Hoge!</h1>
<h2><a href="./twitter">Please Login!</a></h2>


これで、下記のようにtwitterAPIを使ってログインできるようになり、ログインすると、twitterアカウントのアイコンとscreen_nameが表示される。


ログインしていないと、下記のログイン画面が表示される。


ログインした後のindex画面

2011年12月12日月曜日

cakePHP セッション

cakePHPでのセッションの取り扱いも超簡単だ。

『CakePHP』を使ってみる ~11~ セッションの使い方確認 に書いてある。以下引用。
// Write
$this->Session->write('myname', 'Yossy');
echo 'Write: '.$this->Session->read('myname');

// Delete
$this->Session->delete('username');
echo 'Delete: '.$this->Session->read('myname');

cakePHP JSONデコード

cakePHPでJSONデータをPHPで使えるようにデコードするには、下記で簡単にできる。
json_decode('JSON形式のデータ');

2011年12月11日日曜日

cakePHP - データ更新

データ更新は、saveメソッドで実施できる。プライマリーキーが引数で与えられたデータに含まれない場合は、データを新規追加し、含まれる場合は与えられたデータ内容で更新する。

特定のフィールドのみ更新する場合は下記のようになる。
$this->Board->id = $this->data['Board']['id'];
$this->Board->saveField('content',$this->data['Board']['content']);

cakePHP - データの削除

データの削除はidをもとに削除する場合は単純である。

$this->Board->delete($this->data['Board']['id']);
delete('idの数字')だけで削除できる。 上記は、Boardモデルのdeleteメソッドを使って、idフィールドが$this->data['Board']['id']であるデータを、boardsテーブルから削除している。

delete(id)以外の方法は下記である。

$this->Board->deleteAll(array('Board.name'=>
 $this->data['Board']['name']));
これは、Board.nameが、$this->data['Board']['name']と等しいデータが全て削除される。

$this->Board->deleteAll(array('Board.name like ?'=>
 "%{$this->data['Board']['name']}%"));
これは、データ検索(2)で記載されているfindメソッドの「?」と同じことが行われている。cakePHPでは、内部でSQL構文を構築するにあたり、「?」に、その後与えられている配列の値が順に当てはめられる。すなわち上記は、Board.nameに、$this->data['Board']['name']の値が含まれるデータが全て削除される。

cakePHP - データ検索(2)

cakePHP - データ検索(1)
上記でfindの概要がわかったが、もっと色々findの使い方がある。主にオプションであるconditionsの設定の仕方である。これを色々試す。

$data = $this->Board->find('all',array('conditions'=>
 array('Board.id'=>$this->data['Board']['id'])));
これは(1)で試したコードで、Board.idが、$this->data['Board']['id']の値と等しいものを取得する。

$data = $this->Board->find('all',array('conditions'=>
 array('Board.name like'=>"%{$this->data['Board']['name']}%")));
これは、Board.nameに、%演算子で囲まれたテキストが含まれるものを取得する。

$data = $this->Board->find('all',array('conditions'=>
 array('Board.name like ?'=>array(
 "%{$this->data['Board']['name']}%"))));
これは、一つ上のコードと全く同じことが行われる。findメソッドは、キー名に含まれる「?」部分に、値として指定されている配列から順に要素を取り出しはめ込んでいく。SQL構文とこの?の仕組みを理解していれば、SQLのWHERE句で実施される全てが行えるようだ。

$data = $this->Board->find('all',array('conditions'=>
 array('Board.id between ? and ?'=>array(2,5))));
これは、最初の?に2を入れて、次の?に5を入れている。Board.idが2〜5の間のものを取得する。

$data = $this->Board->findAllById(1);
これは、○○=××であるといったシンプルな条件指定の際に利用できる、非常に簡便なメソッドである。findAllByの後にフィールド名をキャメル記法でつなげればよい。findAllById(1)というのは、idフィールドが1であるものを全て取得することになる。

$data = $this->Board->findById(1);
これは、findAllByと仕組みは同じだが、条件に合致する最初の一つを取得する。(1)記載のallとfirstの関係と同じであり出力されるデータ構造もそれとおなじである。

cakePHP - データ検索

データの検索はこれでできる。
$data = $this->Board->find('all',array('conditions'=>
 array('Board.id'=>$this->data['Board']['id'])));
Boardモデルのfindメソッドを使って、テーブルboardsを検索している。 find('検索仕様','オプション');のように引数を二つ要する。 第一引数は、検索仕様の設定であり、all、first、list、countのいずれかを入力する。 第二引数は、オプションの設定であり、conditions,fields,recursive,order,limit,pageを連想配列として入力する。

第一引数(検索仕様)

all

allは検索条件に合致する全てを返す。データ構造は下記のとおり。
Array
(
    [0] => Array
        (
            [Board] => Array
                (
                    [id] => 1
                    [name] => taro
                    [title] => test
                    [content] => hello every one. how are you today?
                )

        )

)

first

firstは検索条件に合致する最初の一つを返す。データ構造は下記のとおり。
Array
(
    [Board] => Array
        (
            [id] => 1
            [name] => taro
            [title] => test
            [content] => hello every one. how are you today?
        )

)

list

listは条件に合致する全てのデータの、キーとその次のフィールドを返す。データ構造は下記のとおり。
Array
(
    [1] => test
)

count

countは条件に合致するデータの個数を返す。

第二引数(オプション)

conditions

条件の設定。条件をつけるフィールド名をキーに、検索する値を値とする連想配列として用意する

fields

取得するフィールド名を配列として用意する

recursive

再帰的に取得する深度

order

取得順。順序を示す数字または名前を配列として用意する

limit

取得するレコード数

page

取得するページ数

MySQL 照合順序 - 日本語を使えるようにする

照合順序を「utf8_unicode_ci」にすると、日本語使えるようになった。

cakePHP - テーブルへのデータ追加

この一行でデータ追加ができる。
$this->Board->save($this->data);
これは、Boardモデルのsaveメソッドによって$this->dataを登録している様だ。Boardモデルは、テーブルboardsの単数形をファイル名、クラス名に適用している。$this->dataも、テーブルboardsの構造に合致した配列構造になっている。

例えば、テーブルboardsが、id,name,title,contentという4つのデータフィールドを持つとする。idはauto_incrementであるとすると、$this->dataに格納する必要があるのは、name,title,contentである。フォームからこれらのデータをユーザがインプットする場合、フォームに適用させるnameはそれぞれ、Board.name,Board.title,Board.contentである。つまり「テーブル名.データフィールド名」という形態にする必要がある。

cakePHP - リダイレクト(redirect)

cakePHPのリダイレクトは超お手軽だ。
$this->redirect('.');

cakePHP - scaffoldの使い方

テーブルを用意して、コントローラーに下記のように書くだけ。
<?php 
class BoardsController extends AppController{
 public $name = 'Boards';
 public $scaffold;
}
?>
  • テーブル名:boards
  • コントローラファイル名:boards_controller.php
  • コントローラークラス名:BoardsController

CtpファイルをEclipseでPHPファイルとして表示する(CakePHP)

CtpファイルをEclipseでPHPファイルとして表示する(CakePHP)にやり方がのっているが、Eclipseの設定変更でctpファイルもPHPファイルとして表示されるようにした。
Eclipseのメニューから Windows -> Preferences をクリックし、 General -> ContentTypesを選択します。
※macだと、メニューのEclipse->環境設定(Preferences)・・・になる。

cakePHP モデルの規約

データベースのテーブル名を、usersにして、モデルファイルを、user.phpにして、モデルクラスをUserにすれば、コントローラーからUserモデルクラスにアクセスするだけで、テーブルusersにアクセスできる。 つまりテーブル名は複数形、モデルファイル及びモデルクラス名は単数形で徹底する必要がある。複数形、単数形を管理している辞書がある。

2011年12月10日土曜日

cakePHP - Appフォルダの構造

CakePHPのフォルダ構造

config CakePHP が使用する(数個の)設定ファイルが入る場所です。データベース接続の詳細、ブートストラップ、コアの設定ファイルなどがここに入ります。
controllers アプリケーションのコントローラとコンポーネントが入ります。
libs サードパーティ、外部ベンダからのライブラリではなく、ファーストパーティのライブラリが入ります。これはベンダライブラリと内部ライブラリの構成を分割することを可能にします。
locale 国際化のための文字ファイルが入ります。
models アプリケーションのモデル、ビヘイビア、データソースが入ります。
plugins プラグインパッケージが入ります。
tmp

CakePHP が一時的なデータを保管する場所です。保管される実際のデータは、CakePHP の設定しだいですが、このフォルダは通常、モデルの内容デ ータや、ログの保管に使用されます。時にはセッション情報も入ります。

確実にこのフォルダが存在し、書き込み可能であるようにしてください。そうしないと、アプリケーションのパフォーマンスは激しく影響をうけることになります。デバッグモードでは、CakePHPがそうなっているかどうかを警告してくれます。

vendors 外部(サードパーティ)で作成されたクラスやライブラリは、ここに置いてください。そうすることで、App::import('vendor', 'name') で簡単にアクセス できるようになります。注意して観察している人は、これは重複しているのではないか、と言うかもしれません。ディレクトリ構造のいちばん上にも vendors フォルダがあるからです。この二つのフォルダの違いは、複数のアプリケーションを動作させて、より複雑なシステムセットアップをする場合のことを考える際 に扱いましょう。
views 表示用のファイルはここに置きます。エレメント、エラーページ、ヘルパー、レイアウト、ビューのファイルなどです。
webroot 運用時(production)用のセットアップでは、このフォルダがアプリケーションのドキュメントルートになります。CSS スタイルシートや画像、JavaScript を入れるためのフォルダもあります。

2011年12月8日木曜日

cakePHPの「・・・is not writable」エラー

xamppでcakePHPを使ってみているのですが、Warning (512): /var/www/html/cakephp/app/tmp/cache/ is not writable のようなエラーがでておりました。これまた権限の問題で、Finder上で権限変更しても直らず、念のためxamppのapatchを再起動してもダメでした。 CakePHPフレームワークで行こうにも同じエラーに関する記載があり、このブログのようにターミナル上で権限変更したら何故かオッケーでした。
chmod -R 707 /Applications/XAMPP/xamppfiles/htdocs/cake/caketest/app/tmp

xamppでcakePHPを使うときの設定

xamppでcakePHP1.3を使う場合、プロジェクトを格納しているフォルダに、サーバ設定の上書きを許可する為に、 /Applications/XAMPP/xamppfiles/etc/httpd.conf に下記を追記する必要がある。
<Directory "/Applications/XAMPP/xamppfiles/htdocs/cake/">
 Allow from all
</Directory>
上記パスはプロジェクトを格納しているフォルダのパスとなる。上記はxamppのhtdocsフォルダの配下にcakeというフォルダをつくり、そこにcakePHPプロジェクトを入れることを想定したパス。

macでxampp使う

macでxampp使うときは、最初xamppのhtdocsフォルダが読みのみOKという権限になっていて書き込めなかった。色々試したが、結局、/Applications/XAMPP/xamppfiles/htdocsフォルダのアクセス権限を読み/書き可に設定して、htdocsフォルダにサイトを置くのが一番分かり易かった。eclipseであれば、htdocsフォルダをワークスペースにして、localhost/プロジェクトフォルダという風にアクセスする。

権限の変更は変更したいフォルダに、Finderで移動して、右クリックで情報をみるをクリックする。情報の一番したにアクセス権に関する内容が掲載されている。鍵マークをクリックして鍵を解除したら権限を変更できる。

2011年12月4日日曜日

MySQL 数字データをINSERTしたら別の数字になっている件

SQL初心者です。PHPでMySQLを本日使い始めました。初めてのINSERTで衝撃を受けています。というのも、数字データをINSERTしたら、全く別の数字データがINSERTされているからです。原因不明なので調べていきます。

現象はこうです。INSERTした数値データは、409312097であるにも関わらず、INSERTされた結果を確認すると、8388607になっている。

すぐに原因が分かりました。。数値型(データ型)のまとめに記載されていますが、数値データのデータ型を何も考えずにMEDIUMINTにしていました。しかし、これの最大値が8388607なのでした。最大値より大きい数値を登録しようとすると最大値になるんですね。勉強になりました。INTにしたら解決されました。

PHP 文字列内での変数展開について

ダブルクオーテンションで囲った文字列内に変数が入っている場合、それは展開されます。しかし注意点があります。変数の後に半角スペースがない場合、その後の文字列まで変数名として扱われてしまいます。これを回避するには、シングルクオーテンションで囲った場合のように"."で文字列連結をするか、あるいは変数を{}で囲み変数名を明示するかのいずれかの方法があります。コード作成上は{}で囲む方が楽な気がしますが、文字列連結の方が若干高速であるらしいです。
$a = 'aiueo';
echo "これは、{$a}です。";
参考:文字列内での変数展開

xamppのMySQLのrootのパスワード設定が記載されているファイル

phpMyAdmin上でrootのパスワード設定をしたところ、phpMyAdminにアクセスできなくなり少しビビった。当然解決策は設定されているファイルを探して書き換えればよいとかそういうことなはずなので探した。たまたまphpMyAdmin上でパスワード生成したときのパスワードをコピーしていたのでそれをしかるべき箇所にペーストすれば復活するのではないかと思っている。

どのようにMySQL"root"ユーザのパスワードを設定するのですか?(方法2)

上記のページに、下記のような記載がある。
次の手順で、phpMyAdmin設定を調整します。
"\xampp\phpMyAdmin\config.inc.php"ファイル内にある以下の行を変更します:
変更前:
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '';
変更後:
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = 'secret';
早速上記のconfig.inc.phpファイルを探したところ確かに存在し、$cfg['Servers'][$i]['password']にコピーしておいたパスワードをペーストし保存したところ、phpMyAdminにアクセスできるようになった。しかしphpMyAdminのホームページでは依然としてエラーになる。。支障はないが。

XAMPPでpearコマンドを使う on mac

参照:XAMPPでpearコマンドを使う
XAMPPディレクトリに移動して、pear install パッケージ名

僕のPCはmacです。XAMPPは最新版をインストールしたばかり。今2011年12月4日です。phpinfo()で、pearで検索すると、pear=/Applications/XAMPP/xamppfiles/lib/php/pearと書いてありました。ターミナルを起動して、cdで/Applications/XAMPP/xamppfiles/lib/php/に移動しました。

今回はDB.phpを使えるようにしたいのです。
PEAR::DBの利用というページがDB.phpに詳しいようです。これを見ながらセットアップしていきます。

pear install DBを実行したところ、下記のエラーになりました。
Warning: touch(): Unable to create file /usr/lib/php/.lock because Permission denied in PEAR/Registry.php on line 835

Warning: touch(): Unable to create file /usr/lib/php/.lock because Permission denied in /usr/lib/php/PEAR/Registry.php on line 835
could not create lock file: fopen(/usr/lib/php/.lock): failed to open stream: No such file or directory
権限がないエラーのようです。同じ状況が『snow leopardでPEARを使う』に書いてあります。sudo pear install DBを実行すると、インストールが完了しました。このDBをどうやってPHPファイル上でrequire出来るのでしょうか?単純にrequire 'DB.php';とやると存在しないとのエラーになります。どうもpearでインストールしたファイルは、/usr/lib/php/にいるようです。xamppのphp.iniのinclude_pathにこのパスを追加したところ、require 'DB.php'で起動するようになりました!ちなみに、xamppのphp.iniは/Applications/XAMPP/xamppfiles/etcにあります。