<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
   <title>WEBプログラム覚書</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/" />
   <link rel="self" type="application/atom+xml" href="http://www.kantenna.com/pg/atom.xml" />
   <id>tag:www.kantenna.com,2010:/pg//2</id>
   <updated>2010-03-05T06:13:19Z</updated>
   <subtitle>PHP、MySQL、JavaScript、XML</subtitle>
   <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.33-ja</generator>

<entry>
   <title>PHP+jQuery+Fotolia APIでつくるちょいエロ カルーセル</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/03/phpjqueryfotolia_api.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.529</id>
   
   <published>2010-03-04T19:45:49Z</published>
   <updated>2010-03-05T06:13:19Z</updated>
   
   <summary>PHP+jQuery+Fotolia APIでつくるちょいエロ カルーセル。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="JavaScript" scheme="http://www.sixapart.com/ns/types#category" />
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="385" label="Zend Framework" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="310" label="jQuery" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="440" label="アニメーション" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
アニメーションががSexyとかじゃなく写真がちょいエロなだけなので
選ぶ写真によっては爽やかにもなりますw
</p>]]>
      <![CDATA[<ul>
<li><a href="http://www.kantenna.com/dev/fotolia/gallery.php">FotoliaAPI ギャラリーデモ</a></li>
<li><a href="http://www.kantenna.com/dev/fotolia/index.php">利用方法</a></li>
<li><a href="http://www.kantenna.com/tools/fotolia.zip">ダウンロード</a></li>
</ul>

<p>動かすには下記環境が必要になります。</p>

<ul>
<li>PHP5以上</li>
<li>jquery-1.3.1以上</li>
</ul>


<h3>Fotolia</h3>

<p>
<a href="http://jp.fotolia.com/partner/201417048">Fotolia</a>はAPIが公開されてて、アフィリエイトもできる写真素材のダウンロードサイト。
ディスカウントもあり個人でも利用できる手頃な値段がうれしい。
</p>

<p>
まずはユーザ登録してAPIキーを取得しましょう。審査があるので取得まで時間がかかります。
</p>


<h3>jQueryでカルーセル</h3>
<p>
とりあえず作ったって感じなので、いろいろと問題があるかと思います。
愛用のプラグインなどあればそちらを利用した方がよいかとおもいますw
</p>

<h3>キャッシュ</h3>

<p>
キャッシュはデフォルトでOFFですが利用した方が良いです。
<a href="http://framework.zend.com/manual/ja/zend.cache.html">Zend Framework: Documentation: Zend_Cache - Zend Framework Manual</a>
を同梱してあるので利用する場合はconfig.phpで設定。そしてキャッシュディレクトリを書き込み可能に。
</p>



<h3>XML-RPCメモ</h3>

<p>
XML-RPCとは簡単に言うとXMLをPOSTするとXMLが返ってくるというもの。
最近のWEBサービスで公開されてるAPIはRESTが多く、よく知らなかったんですが
よく利用されているみたいです。
</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://studyinghttp.net/intro#SOAP">[Studying HTTP] Introduction of HTTP</a></li>
</ul>
</div>

<p>
で、メソッドとヘッダとコンテンツを送る仕様のはずなんだけど、
メソッドとヘッダを入れるとエラー。
</p>

<?php $KT->viewSource('
$opts = array(\'http\'=>array(
   /* エラー
   \'method\' => \'POST /Xmlrpc/rpc HTTP/1.0\',
   \'header\' => \'Host: api.fotolia.com\' . "\r\n" .
               \'Connection: close\' . "\r\n" .
               \'Content-Type: text/xml\' . "\r\n" .
               \'Content-Length: \' . strlen($this->_query). "\r\n",
    */
    \'content\' => $this->_query
));

$context = stream_context_create($opts);
$result = file_get_contents(FotoliaAPI::URL_REQUEST, false, $context);
'); ?>

<p>
どの辺がエラーなのかさっぱりです。そしてなんでmethod、header無しでOKなのかもさっぱり不明。そもそもPHPからどんなヘッダが送られてるのかどうやって確認すればいいんだろ？
</p>

<p>ブラウザでパラメータ編集して結果が確認できるRESTの便利さがよく分かりました。</p>

<h4>リクエスト</h4>
<p>
n個のメディア情報を取得する場合、n回リクエストしてる状況なので重い。
1回のリクエストでparamsは1個かと思ってたんですが、レスポンスはとしか書いてない。
</p>

<p>もしかしてリクエスト時は複数のparamsを組み込めるのだろうか？</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://lowlife.jp/yasusii/stories/9.html">XML-RPC 仕様書</a></li>
</ul>
</div>

<?php
$KT->am->viewBookGroup('php');
$KT->am->viewBookGroup('jquery'); 
?>
]]>
   </content>
</entry>
<entry>
   <title>ActionScript3.0 [基礎] Tweenとeasing</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/02/actionscript30_tweeneasing.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.527</id>
   
   <published>2010-02-23T19:55:46Z</published>
   <updated>2010-02-23T20:02:59Z</updated>
   
   <summary>ActionScript3.0で最も簡単にアニメーションをさせることができるTweenと加速と減速が簡単に設定できるeasingを使ってみる。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="ActionScript" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="440" label="アニメーション" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
ActionScript3.0で最も簡単にアニメーションをさせることができる
Tweenと加速と減速が簡単に設定できるeasingを使ってみる。
</p>

<p>
結果は<a href="/pg/as3/animate/Main.php">これ</a>。
</p>]]>
      <![CDATA[<h3>Main.as</h3>
<?php $KT->viewSource('
package
{
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.text.TextField;
    import flash.events.MouseEvent;
    import flash.display.StageAlign;

    import fl.transitions.Tween;
    import fl.transitions.easing.*;
    
    import com.kantenna.display.DispalyBox;
    import com.kantenna.effect.EffectBox;
    import com.kantenna.display.ExecButton;
    
    public class Main extends Sprite
    {

        private var _eff_box:EffectBox = new EffectBox();
        private var _disp_box:DispalyBox = new DispalyBox();
        
        public function Main():void
        {
            stage.align = StageAlign.TOP_LEFT;
            
            var sp:Shape = new Shape();
            sp.graphics.beginFill(0xE5E5E5);
            sp.graphics.drawRect(0, 0, 1024, 800);
            sp.graphics.endFill();
            addChild(sp);
            
            // エフェクト用のオブジェクト作成
            createEffectObject();
            _eff_box.x = 200;
            _eff_box.y = 100;
            _eff_box.build();
            addChild(_eff_box);
            
            // ボタン作成
            createButtons();
            _disp_box.row = DispalyBox.VERTICAL;
            _disp_box.build();
            addChild(_disp_box);
        }
        
        public function createEffectObject():void
        {
            var str:String = \'kantenna.com\';
            
            for (var i:int = 0; i < str.length; i++ ) {
                var txt:TextField = new TextField();
                txt.width = 20;
                txt.text = str.charAt(i);
                _eff_box.add(txt);
            }
        }
        
        public function createButtons():void
        {
            _disp_box.add(new ExecButton(\'現在位置から上\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.moveToTop( { } );
            }));
            
            _disp_box.add(new ExecButton(\'現在位置から下\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.moveToBottom( { } );
            }));
            
            _disp_box.add(new ExecButton(\'現在位置から右\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.moveToRight( { } );
            }));

            _disp_box.add(new ExecButton(\'現在位置から左\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.moveToLeft( { } );
            }));

            _disp_box.add(new ExecButton(\'拡大\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.zoomIn( { } );
            }));

            _disp_box.add(new ExecButton(\'縮小\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.zoomOut( { } );
            }));
            
            // 設定変更用のボタン
            _disp_box.add(new ExecButton(\'String.easeIn 設定変更\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.defaultParams = {
                easing: Strong.easeIn,
                duration: 0.3,
                duray: 80,
                distance: 100,
                scaleX: 3,
                scaleY: 3,
                alpha: 1
                };
            }));
            
            // 設定変更用のボタン
            _disp_box.add(new ExecButton(\'Elastic.easeOut 設定変更\', MouseEvent.CLICK, function(e:MouseEvent):void {
                _eff_box.defaultParams = {
                easing: Elastic.easeOut,
                duration: 0.3,
                duray: 80,
                distance: 100,
                scaleX: 3,
                scaleY: 3,
                alpha: 1
                };
            }));
        }
    }
}
'); ?>

<h3>EffectBox.as</h3>
<?php $KT->viewSource('
package  com.kantenna.effect
{
    import flash.display.Sprite;
    import flash.display.DisplayObject;
    import fl.transitions.Tween;
    import fl.transitions.easing.*;
    import flash.text.TextField;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    
    public class EffectBox extends Sprite
    {
        public static const LINE:String = \'line\';
        public static const VERTICAL:String = \'vertical\';
        
        /**
         * 縦に配置するか横に配置するかの設定
         * 
         * 縦配置 : line
         * 横配置 : vertical
         */
        private var _row:String;

        /**
         * 並べるアイテム
         * 中身はDisplayObject
         * 
         */
        private var _items:Array;
        
        /**
         * 並べた時の間隔
         */
        private var _margin:int = 0;

        private var _default_params:Object = {
            easing: Regular.easeInOut,
            duration: 0.5,
            duray: 240,
            distance: 100,
            scaleX: 3,
            scaleY: 3,
            alpha: 1
            };
            
        /**
         * コンストラクタ
         * 
         * @param   items Array or DisplayObject
         * @param   row   String line|vertical
         */
        public function EffectBox(items:* = null, row:String = LINE):void 
        {
            _row = row;
            _items = new Array();

            if (items !== null) {
                add(items);
            }
        }
        
        /**
         * _itemsにDisplayObjectを追加
         * 
         * @param   objects DisplayObject or DisplayObject が入ったArray
         */
        public function add(objects:Object):void
        {
            if (objects is Array) {
                objects.forEach(function(object:DisplayObject):void {
                    _items.push(objects);
                });
            } else if (objects is DisplayObject) {
                _items.push(objects);
            } else {
                throw new Error("Display Objectを入れてください。");
            }
        }
        
        /**
         * _itemsにあるDisplayObjectを
         * 自身にaddChild
         * 
         */
        public function build():void
        {
            var position:int = 0;

            _items.forEach(function(item:DisplayObject, index:int, array:Array):void {
                if (_row === LINE) {
                    item.x = position;
                    addChild(item);
                    position += item.width + _margin;
                } else {
                    item.y = position;
                    addChild(item);
                    position += item.height + _margin;
                }
            });
        }
        
        public function get row():String
        {
            return _row;
        }
        
        public function set row(str:String):void
        {
            _row = str;
        }
        
        public function get margin():int
        {
            return _margin;
        }
        
        public function set margin(px:int):void
        {
            _margin = px;
        }

        private function margeParams(params:Object):Object
        {
            var result:Object = { };
            for (var key:String in _default_params)
            {
                // メモ:undefinedはfalse
                result[key] = params[key] ? params[key] : _default_params[key];
            }
            return result;
        }
        
        public function set defaultParams(obj:Object):void
        {
            _default_params = obj;
        }
        

        /**
         * 現在の位置から上に移動させる
         * 
         * @param   params デフォルトの値はmargeParams()を参照
         */
        public function moveToTop(params:Object):void
        {
            params = margeParams(params);

            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current = getChildAt(timer.currentCount - 1);
                new Tween(current, \'y\', params.easing, current.y, current.y - params.distance, params.duration, true);
            });
        }

        /**
         * 現在の位置から上に移動させる
         * 
         * @param   params デフォルトの値はmargeParams()を参照
         */
        public function moveToBottom(params:Object):void
        {
            params = margeParams(params);

            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current = getChildAt(timer.currentCount - 1);
                new Tween(current, \'y\', params.easing, current.y, current.y + params.distance, params.duration, true);
            });
        }

        public function moveToRight(params:Object):void
        {
            params = margeParams(params);
            
            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current = getChildAt(timer.currentCount - 1);
                new Tween(current, \'x\', params.easing, current.x, current.x + params.distance, params.duration, true);
            });
        }

        public function moveToLeft(params:Object):void
        {
            params = margeParams(params);
            
            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current = getChildAt(timer.currentCount - 1);
                new Tween(current, \'x\', params.easing, current.x, current.x - params.distance, params.duration, true);
            });
        }
        
        
        public function zoomIn(params:Object):void
        {
            /*
            var easing:Function = (params._easing == undefined) ? Regular.easeInOut : params._easing;
            var duration:Number = (params._duration == undefined) ? 0.2 : params._duration;
            */
            params = margeParams(params);
            
            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current:DisplayObject = getChildAt(timer.currentCount - 1);
                new Tween(current, \'scaleX\', params.easing, current.scaleX, current.scaleX * params.scaleX, params.duration, true);
                new Tween(current, \'scaleY\', params.easing, current.scaleY, current.scaleY * params.scaleY, params.duration, true);
            });
        }

        public function zoomOut(params:Object):void
        {
            params = margeParams(params);
            
            var timer:Timer = new Timer(params.duray, numChildren);
            timer.start();
            timer.addEventListener(TimerEvent.TIMER, function():void {
                var current:DisplayObject = getChildAt(timer.currentCount - 1);
                new Tween(current, \'scaleX\', params.easing, current.scaleX, current.scaleX / params.scaleX, params.duration, true);
                new Tween(current, \'scaleY\', params.easing, current.scaleY, current.scaleY / params.scaleY, params.duration, true);
            });
        }
    }
}
'); ?>



<h3>DispalyBox.as</h3>
<?php $KT->viewSource('
package  com.kantenna.display
{
    import flash.display.Sprite;
    import flash.display.DisplayObject;
    
    public class DispalyBox extends Sprite
    {
        public static const LINE:String = \'line\';
        public static const VERTICAL:String = \'vertical\';
        
        /**
         * 縦に配置するか横に配置するかの設定
         * 
         * 縦配置 : line
         * 横配置 : vertical
         */
        private var _row:String;

        /**
         * 並べるアイテム
         * 中身はDisplayObject
         * 
         */
        private var _items:Array;
        
        /**
         * 並べた時の間隔
         */
        private var _margin:int = 0;
        
        /**
         * コンストラクタ
         * 
         * @param   items Array or DisplayObject
         * @param   row   String line|vertical
         */
        public function DispalyBox(items:* = null, row:String = LINE):void 
        {
            _row = row;
            _items = new Array();

            if (items !== null) {
                add(items);
            }
        }
        
        public function add(objects:Object):void
        {
            if (objects is Array) {
                objects.forEach(function(object:DisplayObject):void {
                    _items.push(objects);
                });
            } else if (objects is DisplayObject) {
                _items.push(objects);
            } else {
                throw new Error("Display Objectを入れてください。");
            }
        }
        
        public function build():void
        {
            var margin:int = _margin;
            var position:int = 0;

            _items.forEach(function(item:DisplayObject, index:int, array:Array):void {
                if (_row === LINE) {
                    item.x = position;
                    addChild(item);
                    position += item.width + _margin;
                } else {
                    item.y = position;
                    addChild(item);
                    position += item.height + _margin;
                }
            });
        }
        
        public function get row():String {
            return _row;
        }
        
        public function set row(str:String):void {
            _row = str;
        }
        
        public function get margin():int {
            return _margin;
        }
        
        public function set margin(px:int):void {
            _margin = px;
        }   
    }
}
'); ?>

<h3>ExecButton.as</h3>
<?php $KT->viewSource('
package  com.kantenna.display
{
    import fl.controls.Button;
    import flash.events.*;
    
    public class ExecButton extends Button
    {
        // リスナー関数
        private var _lisn:Function = function():void { trace(this.label) };
        
        // Event.CONST
        private var _evt:String = MouseEvent.CLICK;
        
        public function ExecButton(lab:String, e:String, f:Function):void 
        {
            super();
            this.label = lab;
            this.setEventListener(e, f);
        }
        
        public function setEventListener(e:String, f:Function):void
        {
            delEventListener();
            
            addEventListener(e, f, false, 0, true);
            _evt = e;
            _lisn = f;
        }
        
        public function delEventListener():void
        {
            if (hasEventListener(_evt)) {
                removeEventListener(_evt, _lisn);
            }           
        }
    }
}
'); ?>

<p>
動き的にはElasticがおもしろい。
動きが単調だねとか言われたらElastic使えばごまかせそうｗ
</p>

<p>
移動のボタンを連打すると位置がずれる。これを防ぐには、<a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/fl/transitions/Tween.html#event:motionFinish">Tween - motionFinish</a>
とか使えばよさそう。
</p>

<h3>コンパイルについて</h3>

<p>
FlashDevelopっていうかFlexSDKでflパッケージを利用すると動きがおかしくなることがある??
flashでのコンパイル結果とFlexSDKでのコンパイル結果が違ってかなりハマった。
</p>

<p>
おそらく僕の設定方法がおかしいんだろうけど、一応ネットで出てくる情報を元に、
SWC使ったりクラスパス通したりしたんだけどダメだったんで、もし同じような症状の人いたら
flパッケージ使う場合はflashからコンパイルしたほうがいいよと。
</p>

<h3>基準点について</h3>

<p>
拡大縮小がわかりやすいんですが、基準点が左上になっている。
で、ActionScript3.0で作成したオブジェクトの基準点は自動で左上になり、
基準点を変更することはできないらしい。
</p>

<p>
が、偉大なる先駆者たちが変更したように見せかける方法を開発してくれています。
調べてみたところ3つくらいあるようです。次はそれについてテストしてみようかと思います。
</p>


<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/fl/transitions/easing/package-detail.html">fl.transitions.easing パッケージ - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/fl/transitions/Tween.html#event:motionFinish">Tween - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
</ul>
</div>

<?php $KT->am->viewBookGroup('as'); ?>]]>
   </content>
</entry>
<entry>
   <title>ActionScript3.0 [練習] XMLとナビゲーション</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/02/actionscript30_xml.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.524</id>
   
   <published>2010-02-15T18:50:55Z</published>
   <updated>2010-02-15T18:55:21Z</updated>
   
   <summary>ActionScript3.0を利用してXMLを読み込んでダサいナビゲーションを作ってみる</summary>
   <author>
      <name></name>
      
   </author>
         <category term="ActionScript" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>すっかり忘れかかってるActionScript3.0。<a href="http://flashdevelop.jp/">FlashDevelop.jp</a>のおかげでちょっとやる気が復活。</p>
<p>とはいえまた一から本読むのもあれなんで、いろいろ作りながら覚えていこうかと思います。</p>]]>
      <![CDATA[<h3>ナビゲーションとXML</h3>
<p>
まずはナビゲーションを作ってみる。
ActionScript3.0はXMLのパースが簡単という噂なのでXMLから設定読み込んで
やってみたんですがホントXMLが扱いやすい。
</p>

<p>
まぁ取得するまでが、ちと面倒ですが。ってかPHPの<a href="http://php.net/manual/ja/function.file-get-contents.php">file_get_contents()</a>があまりに便利すぎ。
</p>

<h4><a href="/pg/sample/asnavi/">実行結果</a></h4>

<h4>globalnavi.xml</h4>
<?php $KT->viewSource('
<?xml version="1.0" encoding="utf-8" ?>
<data>

    <config>
        <width>120</width>
        <height>50</height>
        <fontColor>0xFFFFFF</fontColor>
        <backgroundColorUp>0x000000</backgroundColorUp>
        <backgroundColorOver>0x660099</backgroundColorOver>
        <backgroundColorDown>0xCC0000</backgroundColorDown>
        <backgroundColorHit>0xCCFF00</backgroundColorHit>
    </config>

    <lists>
        <list>
            <name>HOME</name>
            <url>/</url>
        </list>

        <list>
            <name>pg</name>
            <url>/pg/</url>
        </list>
        
        <list>
            <name>info</name>
            <url>/info/</url>
        </list>
        
        <list>
            <name>アプリ</name>
            <url>/app/</url>
        </list>
        
        <list>
            <name>サービス</name>
            <url>/service/</url>
        </list>
    </lists>
</data>
'); ?>



<h4>Main.as</h4>
<p>
flash.xmlパッケージは互換のためのクラス。
ActionScript3.0ではグローバルXMLってグローバルにXMLクラスXML関数が存在してるのでそちらを利用する。
</p>

<p>
関数とクラスどちらを使えば良いのか迷った。
URLLoader使ってデータ読み込む場合、基本的にどっちでも良さそう。XML関数は
</p>

<?php $KT->viewSource('
public function XML(expression:Object):XML
'); ?>

<p>
となっていてオブジェクトを受け取ってXMLオブジェクトを返すんだけど
URLLoader.dataが返すのってStringオブジェクトなので関数使っても同じ結果になる。
</p>

<p>ただサンプルとか見てもnewしてあるので倣ったほうがいいのかも。</p>

<?php $KT->viewSource('
package com.kantenna.globalnavi
{

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    
    import com.kantenna.display.DispalyBox;
    import com.kantenna.display.LinkButton;

    public class Main extends Sprite
    {
        
        private var conf_file:String = \'globalnavi.xml\';

        /**
         * コンストラクタ
         * @return void
         */
        public function Main():void 
        {
            addChild(function():DispalyBox {
                var gn:DispalyBox = createGlobalnavi();
                gn.x = 0;
                gn.y = 0;
                return gn;
            }());
        }

        /**
         * グローバルナビゲーションを作成
         * 各メニューはグローバルナビゲーション用の
         * SpriteにaddChildされる
         * 
         * @return Sprite
         */
        private function createGlobalnavi():Sprite
        {
            // メニュー格納用
            var global_navi:DispalyBox = new DispalyBox();
            
            // 設定ファイル読み込み
            var loader:URLLoader = new URLLoader();
            var request:URLRequest = new URLRequest(conf_file);
            loader.load(request);
            
            // 読み込み成功時の処理
            loader.addEventListener(Event.COMPLETE, function(e:Event):void {
                
                var xml:XML = new XML(e.target.data);
                
                // メニューの情報
                var navies:XMLList = xml.lists.list;
                
                // ボタンの設定情報
                var conf:XMLList = xml.config;
                
                var button:LinkButton;
                
                for each (var navi:XML in navies) {
                    button = new LinkButton();
                    button.name = navi.name;
                    button.setRequest(navi.url);
                    
                    button.setState(\'up\', navi.name, conf.child(\'fontColor\'), conf.child(\'width\'), conf.child(\'height\'), conf.child(\'backgroundColorUp\'));
                    button.setState(\'over\', navi.name, conf.child(\'fontColor\'), conf.child(\'width\'), conf.child(\'height\'), conf.child(\'backgroundColorOver\'));
                    button.setState(\'down\', navi.name, conf.child(\'fontColor\'), conf.child(\'width\'), conf.child(\'height\'), conf.child(\'backgroundColorDown\'));
                    button.setState(\'hit\', navi.name, conf.child(\'fontColor\'), conf.child(\'width\'), conf.child(\'height\'), conf.child(\'backgroundColorHit\'));
                    
                    button.setEL();
                    global_navi.add(button);
                }
                global_navi.build();
            });
            
            return global_navi;
        }
    }
}
'); ?>

<h4>DispalyBox.as</h4>
<p>
Array.forEachの第二引数にオブジェクトを渡すと、コールバック関数内でthisで参照できる。
のちのち使えそうな気がするので忘れないようにメモ。
</p>

<?php $KT->viewSource('
package  com.kantenna.display
{
    import flash.display.Sprite;
    import flash.display.DisplayObject;
    
    public class DispalyBox extends Sprite
    {
        public static const LINE:String = \'line\';
        public static const VERTICAL:String = \'vertical\';
        
        /**
         * 縦に配置するか横に配置するかの設定
         * 
         * 縦配置 : line
         * 横配置 : vertical
         */
        private var _row:String;

        /**
         * 並べるアイテム
         * 中身はDisplayObject
         * 
         */
        private var _items:Array;
        
        /**
         * 並べた時の間隔
         */
        private var _margin:int = 0;
        
        /**
         * コンストラクタ
         * 
         * @param   items Array or DisplayObject
         * @param   row   String line|vertical
         */
        public function DispalyBox(items:* = null, row:String = LINE):void 
        {
            _row = row;
            _items = new Array();

            if (items !== null) {
                add(items);
            }
        }
        
        public function add(objects:Object):void
        {
            if (objects is Array) {
                objects.forEach(function(object:DisplayObject):void {
                    _items.push(objects);
                });
            } else if (objects is DisplayObject) {
                _items.push(objects);
            } else {
                throw new Error("Display Objectを入れてください。");
            }
        }
        
        public function build():void
        {
            var margin:int = _margin;
            var position:int = 0;
            _items.forEach(function(item:DisplayObject, index:int, array:Array):void {
                if (_row === LINE) {
                    item.x = position;
                    addChild(item);
                    position += item.width + _margin;
                } else {
                    item.y = position;
                    addChild(item);
                    position += item.height + _margin;
                }
            });
        }
        
        public function get row():String {
            return _row;
        }
        
        public function set row(str:String):void {
            _row = str;
        }
        
        public function get margin():int {
            return _margin;
        }
        
        public function set margin(px:int):void {
            _margin = px;
        }   
    }
}
'); ?>

<h4>LinkButton.as</h4>
<?php $KT->viewSource('
package  com.kantenna.display
{
    import flash.display.DisplayObject;
    import flash.display.SimpleButton;
    import flash.net.URLRequest;
    import flash.net.navigateToURL;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    
    public class LinkButton extends SimpleButton
    {
        
        private var _request:URLRequest;
        private var _trigger:String;
        
        /**
         * コンストラクタ
         * 
         * @param   upState       DisplayObject or NULL
         * @param   overState     DisplayObject or NULL
         * @param   downState     DisplayObject or NULL
         * @param   hitTestState  DisplayObject or NULL
         */
        public function LinkButton(upState:DisplayObject = null, overState:DisplayObject = null, downState:DisplayObject = null, hitTestState:DisplayObject = null) 
        {
            _request = new URLRequest();
            _trigger = MouseEvent.CLICK;
            super(upState, overState, downState, hitTestState);
        }
        
        /**
         * ボタンの機能
         * _requestに設定されてあるURLへ移動
         * 
         */
        public function execute():void
        {
            navigateToURL(getRequest());
        }

        /**
         * リンク先の設定
         */
        public function setRequest(url:String):void
        {
            _request.url = url;
        }

        /**
         * リンク先の取得
         */
        public function getRequest():URLRequest
        {
            return _request;
        }
        
        /**
         * ボタンのイベントリスナー設定
         */
        public function setEL():void
        {
            addEventListener(_trigger, handler);
        }
        
        /**
         * ボタンのイベントリスナー削除
         */
        public function removeEL():void
        {
            if (hasEventListener(_trigger)) {
                removeEventListener(_trigger, handler);
            }
        }

        /**
         * イベントハンドラ
         */
        public function handler(e:Event):void
        {
            execute();
        }
        
        public function set trigger(str:String):void
        {
            _trigger = str;
        }
        
        public function get trigger():String
        {
            return _trigger;
        }
        
        /**
         * up|over|down|hit のグラフィックを設定
         *
         * @param   str    String up|over|down|hit
         * @param   text   String
         * @param   color  String
         * @param   width  String
         * @param   height String
         * @param   bg     String
         */
        public function setState(str:String, text:String, color:String, width:String, height:String, bg:String):void {
            
            var tf:TextField = createTextField(text, color, width, height, bg);
            switch (str) {
                case \'up\':
                    upState = tf;
                    break;
                
                case \'over\':
                    overState = tf;
                    break;
                
                case \'down\':
                    downState = tf;
                
                case \'hit\':
                    hitTestState = tf;
                    break;
            }
        }
        
        /**
         * テキストフィールドを作成
         * 
         * @param   text   String
         * @param   color  String
         * @param   width  String
         * @param   height String
         * @param   bg     String
         * @return  TextField
         */
        private function createTextField(text:String, color:String, width:String, height:String, bg:String):TextField
        {
            var txt:TextField = new TextField();
            txt.text = text;
            txt.textColor = uint(color);
            txt.width = int(width);
            txt.height = int(height);
            txt.background = true;
            txt.backgroundColor = uint(bg);
            return txt;
        }       
    }
}
'); ?>

<p>
あとはURL取得してディレクトリ判定して該当のボタンをUP状態にしたいなー。
</p>


<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/">トップレベルの定数と関数 - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/">トップレベルの定数と関数 - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/">URLLoader - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
<li><a href="http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/">URLRequest - ActionScript 3.0 コンポーネントリファレンスガイド</a></li>
</ul>
</div>

<?php $KT->am->viewBookGroup('as'); ?>]]>
   </content>
</entry>
<entry>
   <title>[jQuery]こんな機能があったんだ。jQuery stop()</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/01/jqueryjquery_stop.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.517</id>
   
   <published>2010-01-19T03:10:20Z</published>
   <updated>2010-01-19T03:21:05Z</updated>
   
   <summary>jQuery stop()のいろいろな機能を試してみたよ</summary>
   <author>
      <name></name>
      
   </author>
         <category term="JavaScript" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="310" label="jQuery" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>「<a href="http://www.coders.me/lang/en/web-html-js-css/javascript/mootools/buttons-like-windows-7-with-js-css">Buttons like Windows 7 with JS &amp; CSS</a>」を見てて</p>]]>
      <![CDATA[<? $KT->viewSource('
el.win7BG.stop().animate({\'opacity\':1},300);
'); ?>

<p>
って記述あったので調べてみたらstop()って色々使えるんですね。
全然しらなかったです。
</p>

<h3>stop([clearQueue], [gotoEnd])</h3>

<p>引数は2つ。何も指定しないとfalse</p>
<p>[clearQueue]がtrueの場合、持っているキューが全て削除される。[gotoEnd]はtrueにすると現在のアニメーションの最後のコマへジャンプする。</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://docs.jquery.com/Effects/stop">Effects/stop - jQuery JavaScript Library</a></li>
</ul>
</div>

<p>いまいちわからなかったのでテスト。</p>

<h3>テストコード</h3>

<script>
$(function(){

var li_width = {_min: '50px', _max: '400px'};
var li_height = {_min: '20px', _max: '100px'};
var li_style = {width: li_width._min, height: li_height._min, display: 'block', margin: '0px'};
var li_colors = ['#20B7F2', '#3086A3', '#022037'];


$('#JQStopTest1 li').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

$('#JQStopTest2 li').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop().animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop().animate({width: li_width._min}).animate({height: li_height._min});
    });
});


$('#JQStopTest3 li').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(false, true).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(false, true).animate({width: li_width._min}).animate({height: li_height._min});
    });
});


$('#JQStopTest4 li').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(true, false).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(true, false).animate({width: li_width._min}).animate({height: li_height._min});
    });
});


$('#JQStopTest5 li').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(true, true).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(true, true).animate({width: li_width._min}).animate({height: li_height._min});
    });
});


});
</script>

<p>
マウスオーバーすると横幅が広がり、縦に伸びるアニメーションを作成する。
</p>
<?php $KT->viewSource('
var li_width = {_min: \'50px\', _max: \'400px\'};
var li_height = {_min: \'20px\', _max: \'100px\'};
var li_style = {width: li_width._min, height: \'20px\', display: \'block\', margin: \'0px\'};
var li_colors = [\'#20B7F2\', \'#3086A3\', \'#022037\'];

$(\'#JQStopTest li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

// HTML
<div id="JQStopTest">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>



<h3>stop()なし</h3>
<p>
stop()がない場合、当然ながらキューが削除されないので
イベントが発生した回数分だけ実効される。
</p>

<div id="JQStopTest1">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>

<?php $KT->viewSource('
$(\'#JQStopTest1 li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

<div id="JQStopTest1">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>




<h3>stop(false, false)</h3>

<p>
デフォルトではfalseとなっている。
一瞬だけマウスオーバーした場合、マウスアウトした時点で現在のアニメーション(横の変化)を停止。
[clearQueue]がfalseのためキュー(縦の変化)が存在するので次のキュー(縦の変化)に移行する。
</p>

<div id="JQStopTest2">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>

<?php $KT->viewSource('
$(\'#JQStopTest2 li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop().animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop().animate({width: li_width._min}).animate({height: li_height._min});
    });
});

<div id="JQStopTest2">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>




<h3>stop(false, true)</h3>

<p>
[gotoEnd]がtrueの場合、途中で中断した場合でも現在のアニメーションの最終コマに移動する。
一瞬だけ、マウスオーバーした場合、上記と違い横幅がMAXまで伸びる。
あとは同じく、残っているキュー(縦の変化)が実行される。
</p>

<div id="JQStopTest3">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>

<?php $KT->viewSource('
$(\'#JQStopTest3 li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(false, true).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(false, true).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

<div id="JQStopTest3">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>



<h3>stop(true, false)</h3>

<p>
JQStopTest2と同じで一瞬だけマウスオーバーしてマウスアウトした場合、[gotoEnd]がfalseのため横の変化が途中で止まる。
[clearQueue]がtrueの場合、持っているキュー(縦の変化)も削除されるので縦に変化するアニメーションは実行されない。
</p>

<div id="JQStopTest4">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>

<?php $KT->viewSource('
$(\'#JQStopTest4 li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(true, false).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(true, false).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

<div id="JQStopTest4">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>



<h3>stop(true, true)</h3>

<p>
両方trueの場合。
一瞬だけマウスオーバーしてマウスアウトした場合、現在のアニメーション(横の変化)は最後のコマにジャンプするが、
縦の変化のキューはクリアされてるため実行されない。
</p>

<div id="JQStopTest5">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>

<?php $KT->viewSource('
$(\'#JQStopTest5 li\').each(function(i){
    li_style.backgroundColor = li_colors[i];
    $(this).css(li_style).hover(function(){
        $(this).stop(true, true).animate({width: li_width._max}).animate({height: li_height._max});
    }, function(){
        $(this).stop(true, true).animate({width: li_width._min}).animate({height: li_height._min});
    });
});

<div id="JQStopTest5">
<ul>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
</ul>
</div>
'); ?>

<? $KT->am->viewBookGroup('jquery'); ?>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://css-tricks.com/examples/jQueryStop/">Using jQuery Stop</a></li>
<li><a href="http://allabout.co.jp/internet/javascript/closeup/CU20090228A/">jQueryのCustomエフェクト5 - ［JavaScript］All About</a></li>
</ul>
</div>
]]>
   </content>
</entry>
<entry>
   <title>[PHP]パスの通し方</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/01/php_8.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.516</id>
   
   <published>2010-01-12T16:54:58Z</published>
   <updated>2010-01-13T08:00:07Z</updated>
   
   <summary>ライブラリのパスを定数で設定することが多々あるがCakePHP ではini_setが使える場合、include_pathに追加するって処理になっている。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="398" label="CakePHP" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
ライブラリのパスを定数で設定することが多々あるが
CakePHP ではini_setが使える場合、include_pathに追加するって処理になっている。
</p>]]>
      <![CDATA[<?php $KT->viewSource('
if (function_exists(\'ini_set\') && ini_set(\'include_path\', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS . PATH_SEPARATOR . ini_get(\'include_path\'))) {
    define(\'APP_PATH\', null);
    define(\'CORE_PATH\', null);
} else {
    define(\'APP_PATH\', ROOT . DS . APP_DIR . DS);
    define(\'CORE_PATH\', CAKE_CORE_INCLUDE_PATH . DS);
}
'); ?>

<p>こういう方法もあるのかと思った。</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://www.secondbrain.co.jp/blog/?p=59">Think Twice ・ カテゴリーツリーの表示</a></li>
<li><a href="http://d.hatena.ne.jp/hetima/20060828">CakePHPの処理の流れを追ってみよう - d.hetima</a></li>
</ul>
</div>


<?php $KT->am->viewBookGroup('cake'); ?>]]>
   </content>
</entry>
<entry>
   <title>CakePHP コントローラーからレイアウトへ値を渡す方法</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/01/cakephp.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.514</id>
   
   <published>2010-01-07T17:46:05Z</published>
   <updated>2010-01-07T17:47:57Z</updated>
   
   <summary>CakePHP コントローラーからレイアウトへ値を渡す方法</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="398" label="CakePHP" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
metaのkeywordとdescriptionをセットしようと思ったんですが
コントローラーからレイアウトへ値を渡すいい方法がわからない。
</p>]]>
      <![CDATA[<p>
beforeFilterでset()すればレイアウトでも利用できるんですが
アクションで設定したい場合どうすればいいんだろ？？
</p>


<h3>Controller::pageTitleを配列に</h3>
<p>
手っ取り早そうなのがController::pageTitleに配列を渡す方法。
</p>

<h4>hoge_controller.php</h4>

<?php $KT->viewSource('
function index() {
    $this->pageTitle = array(
                            \'title\'   => \'タイトル\',
                            \'keyword\' => \'キーワード\',
                            \'desc\'    => \'概要\'
                            );
}
'); ?>

<p>とセットしてあげるとレイアウトで</p>

<?php $KT->viewSource('
echo $title_for_layout[\'title\'];  //タイトル
echo $title_for_layout[\'keyword\'];//キーワード
echo $title_for_layout[\'desc\'];   //概要
'); ?>

<p>
とできる・・・。
なんかイマイチですね。
</p>

<?php $KT->am->viewBookGroup('cake'); ?>

]]>
   </content>
</entry>
<entry>
   <title>CakePHPメモ2 モデルのアソシエーションを一時的に解除</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2010/01/cakephp2_1.php" />
   <id>tag:www.kantenna.com,2010:/pg//2.512</id>
   
   <published>2010-01-06T17:11:39Z</published>
   <updated>2010-01-06T17:13:23Z</updated>
   
   <summary>思った以上に使う場面が多いunbindModel()。モデルのアソシエーションを一時的に解除</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="398" label="CakePHP" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>思った以上に使う場面が多い。</p>]]>
      <![CDATA[
<h4>unbindModel(Array Model, boorean)</h4>
<p>第2引数にfalseをセットしないとunbindModel()実行後の1回のみ有効となる</p>

<?php $KT->viewSource('
$this->Model->unbindModel(array(
                   \'belongsTo\' => array(\'Modelname\'),
                   \'hasMany\' => array(\'Modelname\'),
                   \'hasAndBelongsToMany\' => array(\'Modelname\')
                   ));
'); ?>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://book.cakephp.org/ja/view/78/Associations-Linking-Models-Together">関連: モデルを結びつける :: モデル :: CakePHPによる開発 :: マニュアル :: 1.2 Collection :: The Cookbook</a></li>
</ul>
</div>

<?php $KT->am->viewBookGroup('cake'); ?>]]>
   </content>
</entry>
<entry>
   <title>PEAR::Calenderを利用して特定の日付からn日間表示</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/pearcalendern.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.511</id>
   
   <published>2009-12-20T16:50:09Z</published>
   <updated>2010-01-12T16:54:50Z</updated>
   
   <summary>PEAR::Calenderを利用して特定の日付からn日間表示</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="73" label="PEAR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
ループごとにnewしてたんだけどsetTimestamp()を使えばいいことにようやく気がついた。
</p>]]>
      <![CDATA[<h3>サンプルコード</h3>
<? $KT->viewSource('
require_once(\'Calendar/Day.php\');

// forのたびにnewする
$year = 2009; $month = 12; $day = 28;
$xday = new Calendar_Day($year, $month, $day);

for ($i=1; $i<11; $i++) {    
    printf(\'%s/%02d/%02d<br />\', $xday->thisYear(), $xday->thisMonth(), $xday->thisDay());
    $xday = new Calendar_Day($year, $month, $day + $i);
    $xday->adjust();
}

echo \'<hr />\';

// setTimestamp()ですっきり
$year = 2009; $month = 12; $day = 28;
$oneday_minites = 24 * 60 * 60;
$xday = new Calendar_Day($year, $month, $day);

for ($i=0; $i<10; $i++) {
    printf(\'%s/%02d/%02d<br />\', $xday->thisYear(), $xday->thisMonth(), $xday->thisDay());
    $xday->setTimestamp($xday->getTimestamp() + $oneday_minites);
}
'); ?>


<h3>実行結果</h3>
<div class="result">
<?
require_once("Calendar/Day.php");

$year = 2009; $month = 12; $day = 28;
$xday = new Calendar_Day($year, $month, $day);

for ($i=1; $i<11; $i++) {    
    printf('%s/%02d/%02d<br />', $xday->thisYear(), $xday->thisMonth(), $xday->thisDay());
    $xday = new Calendar_Day($year, $month, $day + $i);
    $xday->adjust();
}

echo '<hr />';

$year = 2009; $month = 12; $day = 28;
$oneday_minites = 24 * 60 * 60;
$xday = new Calendar_Day($year, $month, $day);

for ($i=0; $i<10; $i++) {
    printf('%s/%02d/%02d<br />', $xday->thisYear(), $xday->thisMonth(), $xday->thisDay());
    $xday->setTimestamp($xday->getTimestamp() + $oneday_minites);
}
?>
</div>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://pear.php.net/manual/ja/package.datetime.calendar.php">Manual :: Calendar</a></li>
</ul>
</div>

<?php $KT->am->viewBookGroup('pear'); ?>]]>
   </content>
</entry>
<entry>
   <title>[PHP]Google Analytics からデータを取得 part2</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/phpgoogle_analytics_part2.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.510</id>
   
   <published>2009-12-18T15:51:35Z</published>
   <updated>2009-12-18T16:01:00Z</updated>
   
   <summary>「WEBプログラム覚書::[PHP]google Analytics からアクセスの多いページの情報を取得」に引き続きGoogle Analytics API からデータを取得してみる。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="435" label="Google Analytics" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
「<a href="http://www.kantenna.com/pg/2009/12/phpgoogle_analytics.php">WEBプログラム覚書::[PHP]google Analytics からアクセスの多いページの情報を取得</a>」に引き続きGoogle Analytics API からデータを取得してみる。
</p>
]]>
      <![CDATA[<p>
PV数だけの場合、SERPsで上位だと内容無くてすぐお帰りになられてるページでも
ランクインしてしまうのでオススメとして表示するには微妙な感じになってしまいます。
</p>

<p>
なので今回はちゃんと読まれてるページをオススメページとして取ってみようかと思います。
条件としては「ページビューが100以上」かつ「ページの閲覧時間が2時間以上」のページを取得してみます。
</p>

<p>本当は「平均ページ滞在時間」を取りたいのですが、今のところ用意されてないみたいです。</p>

<h3>フィルタ</h3>

<p>
条件を指定するにはフィルタを使います。難しそうな感じがして
前回避けたんですが、実はそれほど難しくもないです。
</p>

<p>
analytics_apiを利用してフィルタを設定するにはanalytics_filtersクラスを利用すると
簡単便利です。
</p>

<p>
利用しなくても必要な処理はエンコードくらいなので
それほど難しくないです。
</p>

<p>フィルタの書式は下記ページを参照ください。</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://code.google.com/intl/ja/apis/analytics/docs/gdata/gdataReferenceDataFeed.html#filterSyntax">Data API - Data Feed - Google Analytics - Google Code</a></li>
</ul>
</div>

<h3>/pg/以下の「ページビューが100以上」かつ「ページの閲覧時間が2時間以上」のページ</h3>
<? $KT->viewSource('
require_once(\'analytics_api.php\');
$api = new analytics_api();

$filters = new analytics_filters(\'ga:pageviews\', \'>=\', \'100\');

/**
 * フィルタの追加はadd_and()とadd_or()を使う。
 */
 
// 2時間を秒に変換
$filters->add_and(\'ga:timeOnPage\', \'>=\', 60*60*2);

// /pg/以下のディレクトリを指定
$filters->add_and(\'ga:pagePath\', \'=~\', \'^/pg/*\');

// 前回引っかかった(not set)を省く
$filters->add_and(\'ga:pageTitle\', \'!=\', \'(not set)\');

if($api->login(GA_ID, GA_PASS)) {
    $result = $api->data(
              \'ga:792415\',                 // id プロファイルのNoを指定
              \'ga:pageTitle,ga:pagePath\',  // dimension ページタイトルとパス
              \'ga:pageviews,ga:timeOnPage\',// metric ページビュー
              \'-ga:timeOnPage\',            // sort
              \'2009-11-01\',                // start
              \'2009-12-15\',                // end 
              \'20\',                        // max_results 取得件数
              1,
              $filters
              );
} else {
    throw new Exception(\'ログインに失敗しました。IDとパス要確認\');
}

echo \'<pre>\';
var_dump($result);
echo \'</pre>\';
'); ?>
<p><a href="/pg/sample/ga2.php">実行結果</a></p>

<p>ん？「平均ページ滞在時間」はデータ取得後にPHPに計算させればいけるんじゃないか？</p>

<h3>1PV辺りの閲覧時間が長いページ</h3>
<? $KT->viewSource('
require_once(\'analytics_api.php\');
$api = new analytics_api();

$filters = new analytics_filters(\'ga:pageviews\', \'>=\', \'100\');
$filters->add_and(\'ga:pageTitle\', \'!=\', \'(not set)\');

if($api->login(GA_ID, GA_PASS)) {
    $result = $api->data(
                          \'ga:792415\',
                          \'ga:pageTitle,ga:pagePath\',
                          \'ga:pageviews,ga:timeOnPage\',
                          false,
                          \'2008-12-16\',
                          \'2009-12-15\',
                          \'50\',
                          1,
                          $filters                        
                          );
} else {
    throw new Exception(\'ログインに失敗しました。IDとパス要確認\');
}

$new_result = array();
$time = array();

foreach ($result as $name => $pagedata) {
    $title = $name;
    $url = key($pagedata);
    $view = $pagedata[$url][\'ga:pageviews\'];
    $top = $pagedata[$url][\'ga:timeOnPage\'];
    $viewtime = (int) $top / (int) $view;
    
    $new_result[] = array(
                         \'time\' => $viewtime,
                         \'view\' => sprintf(\'(%sビュー)\', $view),
                         \'html\' => sprintf(\'<a href="%s">%s</a>\', $url, $title)
                         );
    // ソート用の配列
    $time[] = $viewtime;
}

array_multisort($time, SORT_DESC, SORT_NUMERIC, $new_result);

$html = \'\';
foreach ($new_result as $value) {
    $html .= sprintf(\'<dt>%s 秒: %s</dt><dd>%s</dd>\',
                     $value[\'time\'],
                     $value[\'view\'],
                     $value[\'html\']
                     );
}
echo \'<dl>\' . $html . \'</dl>\';
'); ?>


<h4>実行結果</h4>
<div class="result">
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/system/new_road.php');
require_once('analytics_api.php');
$api = new analytics_api();


$filters = new analytics_filters('ga:pageviews', '>=', '100');
$filters->add_and('ga:pageTitle', '!=', '(not set)');

if($api->login(GA_ID, GA_PASS)) {
    $result = $api->data(
              'ga:792415',                 // id プロファイルのNoを指定
              'ga:pageTitle,ga:pagePath',  // dimension ページタイトルとパス
              'ga:pageviews,ga:timeOnPage',              // metric ページビュー
              false,                       // sort
              '2008-12-16',                // start
              '2009-12-15',                // end 
              '50',//max_results 取得件数
              1,
              $filters                        
              );
} else {
    throw new Exception('ログインに失敗しました。IDとパス要確認');
}



$new_result = array();
$result_html = array();
$result_time = array();
$time = array();
foreach ($result as $name => $pagedata) {
    $title = $name;
    $url = key($pagedata);
    $view = $pagedata[$url]['ga:pageviews'];
    $top = $pagedata[$url]['ga:timeOnPage'];
    $viewtime = (int) $top / (int) $view;
    
    $new_result[] = array(
    'time' => $viewtime,
    'view' => sprintf('(%sビュー)', $view),
    'html' => sprintf('<a href="%s">%s</a>', $url, htmlspecialchars($title, ENT_QUOTES))
    );
    
    $time[] = $viewtime;
}

array_multisort($time, SORT_DESC, SORT_NUMERIC, $new_result);

$html = '';
foreach ($new_result as $value) {
    $html .= sprintf('<dt>%s 秒: %s</dt><dd>%s</dd>', $value['time'], $value['view'], $value['html']);
}
echo '<dl>' . $html . '</dl>';


?>
</div>

<p>んー合ってるかコレ??かなり自信ない。</p>

<p>なにやら↓がかなり評判がよさげ。買おうかな・・・</p>
<?php $KT->am->viewBook('4901823272'); ?>]]>
   </content>
</entry>
<entry>
   <title>[PHP]CakePHPのcheckboxとhasAndBelongsToMany(HABTM)</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/phpcakephpcheckboxhasandbelong_1.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.508</id>
   
   <published>2009-12-17T17:22:16Z</published>
   <updated>2009-12-17T17:35:54Z</updated>
   
   <summary>CakePHPのcheckboxとhasAndBelongsToMany(HABTM)についてのメモ</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="398" label="CakePHP" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="350" label="フレームワーク" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>CakePHPのcheckboxとhasAndBelongsToMany(HABTM)は僕のスペックだと軽くハマれるわ。</p>]]>
      <![CDATA[<h3>チェックボックスを表示</h3>
<p>
Model::find('list', array('Model.id', 'Model.name'))って感じで
取得したデータをチェックボックスで表示したかったんだけど
いまいち情報が不足。
</p>

<p>
真っ先に思いつくForm::checkbox()は、単純に1つだけとかforeachでまわすときに使うものっぽい。
上記のようなリストを引数に自動生成するにはForm::input()を利用する。
マニュアルにはさらって書いてあるから見逃してました。
</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://book.cakephp.org/ja/view/189/Automagic-Form-Elements#options-multiple-193">フォーム要素の自動生成 :: フォーム :: 主要なヘルパー :: マニュアル :: 1.2 Collection :: The Cookbook</a></li>
</ul>
</div>

<blockquote>select を出力するにあたり「multiple」が true にセットしてあった場合、その select の入力は複数選択が許可されます。「multiple」の代わりに「checkbox」を指定することで、関連したチェックボックスのリストを出力することができます。select を出力するにあたり「multiple」が true にセットしてあった場合、その select の入力は複数選択が許可されます。「multiple」の代わりに「checkbox」を指定することで、関連したチェックボックスのリストを出力することができます。</blockquote>

<p>typeはselectのままでmultipleをcheckboxにするという予想外の設定方法。</p>

<?php $KT->viewSource('
echo $form->input(\'Tag\', array(
                                \'type\' => \'select\',
                                \'multiple\' => \'checkbox\',
                                \'options\' => $tags,//Model::find(\'list\', array(\'Model.id\', \'Model.name\'))で取得したデータ
                                \'selected\' => $checked //array(1, 3, 5, 7, 9)
                                ));
'); ?>

<p>こんな感じでOK。</p>

<h3>関連モデルのデータ (HABTM) を保存する</h3>

<p>
checkboxを使う場合ってhasAndBelongsToMany(HABTM)が設定されてることが多い。
まとめて保存するにはModel::saveAll()を利用する。
</p>

<h4>App/models/post.php</h4>
<p>post_idとtag_idをもつpost_tagsテーブルをつくって投稿とタグにHABTMを設定する。</p>
<?php $KT->viewSource('
class Post extends AppModel
{
    var $hasAndBelongsToMany = array(
        \'Tag\' => array(
            \'className\' => \'Tag\',
            \'joinTable\' => \'post_tags\',
            \'foreignKey\' => \'post_id\',
            \'associationForeignKey\' => \'tag_id\',
            \'fields\' => array(\'Tag.id\', \'Tag.name\'),
            )
    );
}
'); ?>

<h4>App/views/posts/add.php</h4>
<p>新規投稿画面。</p>
<?php $KT->viewSource('
echo $form->create();
echo $form->input(\'name\');
echo $form->input(\'Tag\', array(
                                \'type\' => \'select\',
                                \'multiple\' => \'checkbox\',
                                \'options\' => $tags,//Tag::find(\'list\', array(\'Tag.id\', \'Tag.name\'))で取得したデータ
                                \'selected\' => $checked //array(1, 3, 5, 7, 9)
                                ));
echo $form->end(\'追加\');
'); ?>

<h4>App/controllers/posts_controller.php</h4>
<?php $KT->viewSource('
function add()
{
    $this->Production->saveAll($this->data);
}
'); ?>

<p>このときの$this-&gt;dataの中身は下記のようになっている。</p>

<?php $KT->viewSource('
array(
     \'Production\' => array(
                          \'name\' => \'投稿テスト\'
                          ),
                          
     \'Tag\'        => array(
                          \'Tag\' => array(
                                           0 => \'1\',
                                           1 => \'5\',
                                           2 => \'7\'
                                           )
                           )
);
'); ?>

<p>
一応ちゃんと保存されているのでこの形式でsaveAll()すればよいと思うんだけど
array[Tag][Tag][]って形式がなんか釈然としない・・・ほんとにあってるのか不安w
</p>

<p>2009/12/18現在マニュアルには違うカテゴリの内容が表示されてます・・・</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://book.cakephp.org/ja/view/85/Saving-Related-Model-Data-HABTM">関連モデルのデータ (HABTM) を保存する :: データを保存する :: モデル :: CakePHPによる開発 :: マニュアル :: 1.2 Collection :: The Cookbook</a></li>
</ul>
</div>

<?php $KT->am->viewBookGroup('cake'); ?>]]>
   </content>
</entry>
<entry>
   <title>[PHP]マジック定数</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/php_7.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.506</id>
   
   <published>2009-12-16T18:13:51Z</published>
   <updated>2009-12-16T18:17:12Z</updated>
   
   <summary>PHP マジック定数</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="351" label="言語仕様" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>ちゃんと見た記憶がなかったのでメモというかコピペ</p>]]>
      <![CDATA[
<h3>PHP マジック定数</h3>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://www.php.net/manual/ja/language.constants.predefined.php">PHP: 自動的に定義される定数 - Manual</a></li>
</ul>
</div>

<br />

<table class="btType1">
<tr><th>__LINE__</th><td>ファイル上の現在の行番号。</td></tr>
<tr><th>__FILE__</th><td>ファイルのフルパスとファイル名。インクルードされるファイルの 中で使用された場合、インクルードされるファイルの名前が返されます。 PHP 4.0.2 以降では __FILE__ は常に絶対パスで、シンボリックリンクは解決されます。 それより前のバージョンでは、場合によっては相対パスが返されることもあります。</td></tr>
<tr><th>__DIR__ </th><td>そのファイルの存在するディレクトリ。include の中で使用すると、 インクルードされるファイルの存在するディレクトリを返します。 つまり、これは dirname(__FILE__) と同じ意味です。 ルートディレクトリである場合を除き、ディレクトリ名の末尾にスラッシュはつきません (PHP 5.3.0 で追加されました)。</td></tr>
<tr><th>__FUNCTION__</th><td>関数名（PHP4.3.0で追加されました）。 PHP 5以降、この定数は宣言時の関数名(ケース依存)を返します。 PHP 4では、この値は常に小文字で返されました。</td></tr>
<tr><th>__CLASS__</th><td>クラス名（PHP4.3.0で追加されました）。 PHP 5以降、この定数は宣言時のクラス名(ケース依存)を返します。 PHP 4では、この値は常に小文字で返されました。</td></tr>
<tr><th>__METHOD__</th><td>クラスのメソッド名（PHP5.0.0で追加されました）。 メソッド名は宣言時と同じ(ケース依存)を返します。</td></tr>
<tr><th>__NAMESPACE__</th><td>現在の名前空間の名前 (大文字小文字を区別します)。 この定数はコンパイル時に定義されます (PHP 5.3.0 で追加されました)。</td></tr>
</table>

<p>
__FILE__くらいしか使ってなかった。__FUNCTION__、__CLASS__、__METHOD__は使えそうな気がする。
__DIR__は便利そうだけど5.3か・・・。
</p>

<?php $KT->am->viewBookGroup('php'); ?>]]>
   </content>
</entry>
<entry>
   <title>[PHP]CakePHPのAuthメモ</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/phpcakephpauth.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.505</id>
   
   <published>2009-12-15T19:30:11Z</published>
   <updated>2009-12-15T19:33:09Z</updated>
   
   <summary>CakePHPのAuthコンポーネントのセットアップメモ</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="398" label="CakePHP" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="350" label="フレームワーク" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>CakePHPのAuthコンポーネントのセットアップメモ。</p>]]>
      <![CDATA[<h3>環境</h3>
<p>こんな感じでAdminルーティングが設定してある。</p>

<h4>APP/config/core.php</h4>

<?php $KT->viewSource('
Configure::write(\'Routing.admin\', \'admin\');
'); ?>

<h4>APP/config/routes.php</h4>
<?php $KT->viewSource('
Router::connect(\'/admin\', array(\'controller\' => \'pages\', \'action\' => \'index\', \'admin\' => true));
'); ?>

<h4>APP/config/controllers/app_controller.php</h4>
<?php $KT->viewSource('
function beforeFilter()
{
    if (preg_match(\'/^admin/\', $this->params[\'url\'][\'url\'])) {
        $this->view = \'Theme\';
        $this->theme = \'admin\';
    }
}
'); ?>

<h3>設定</h3>

<p>
ほとんどのコントローラーにAdmin用のメソッドが存在してるので
AppControlerでAuthコンポーネント使うぞ宣言する。
</p>

<h4>APP/controllers/app_controller.php</h4>
<?php $KT->viewSource('
var $components = array(\'Auth\');
'); ?>

<p>ヘルパーはbeforeFilter()で追加できるけどAuthはできない。(というかコンポーネントはできないのかな？)</p>

<?php $KT->viewSource('
function beforeFilter()
{
    $this->helpers[] = \'HogeHelper\';//出来る
    $this->components[] = \'Auth\';//出来ない
}
'); ?>

<p>
利用するテーブルとカラムを変えるにはAuth::userModelとAuth::fieldsを設定する。
</p>

<?php $KT->viewSource('
$this->Auth->userModel = \'Member\';
$this->Auth->fields = array(
    \'username\' => \'account\',
    \'password\' => \'secretkey\'
);
'); ?>

<p>
エラーメッセージなどの設定と、admin/以外のアクションは認証なしで
利用できるように設定する。
</p>

<?php $KT->viewSource('
function beforeFilter()
{
    if (preg_match(\'/^admin/\', $this->params[\'url\'][\'url\'])) {
        $this->view = \'Theme\';
        $this->theme = \'admin\';
        
        $this->Auth->userModel = \'Member\';
        $this->Auth->fields = array(
            \'username\' => \'account\',
            \'password\' => \'secretkey\'
        );
        
        $this->Auth->loginError = \'パスワードが違います。\';
        $this->Auth->authError = \'管理者用のページです。\';

    } else {
        // admin/以外は認証不要
        $this->Auth->allow(\'*\');
    }
}
'); ?>

<h3>ログインとログアウトのアクションを追加する。</h3>
<p>マニュアルそのまんまって感じです。</p>

<h4>APP/controllers/members_controller.php</h4>
<?php $KT->viewSource('
function admin_login() {}

function admin_logout() {
    $this->redirect($this->Auth->logout());
}
'); ?>

<h3>ビューを作成する</h3>
<p>
こちらもマニュアルのサンプルがそのまま使える。
Users以外のモデルやカラムの場合変更が必要となる。
</p>

<h4>APP/view/theme/admin/members/admin_login.php</h4>
<?php $KT->viewSource('
if ($session->check(\'Message.auth\')) $session->flash(\'auth\');
echo $form->create(\'Member\', array(\'action\' => \'login\'));
echo $form->input(\'account\');
echo $form->input(\'secretkey\');
echo $form->end(\'Login\');
'); ?>

<p>
想像以上に簡単だ。単純にAuthを使う場合、悩むことはなさそう。
問題はACLとかAROとかACOが絡んできた時かな。そもそも機能がいまいち理解できてないしｗ
</p>


<h3>Authコンポーネントを有効にしたら出たエラー</h3>

<p>Authコンポーネントを有効にしたら</p>

<?php $KT->viewSource('
Warning: Cannot modify header information
'); ?>


<p>
というエラーが出た。ググってみるとheaderの前に何かしらの文字が出力されている可能性があるとのこと。
もしくはutf-8のbom付きだとなる模様。
</p>

<p>まず疑うべきはコントローラーとかモデルの最後の「?&gt;」の後ろに改行などがないか。</p>

<p>
PHPの「?&gt;」はZend Flameworkのコーディング規約でも書くなと言われていたはずなので、
書かないのがPHP界の常識なはず。でも書くな書くなと言われてもホントに？ほんとにいいの書かなくて？
ってどーにも不安だったんですがこれからはきっちりと削除しようかとおもいました。
</p>


<?php $KT->am->viewBookGroup('cake'); ?>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://book.cakephp.org/ja/view/172/Authentication">認証 :: 主要なコンポーネント :: マニュアル :: 1.2 Collection :: The Cookbook</a></li>
</ul>
</div>]]>
   </content>
</entry>
<entry>
   <title>Excel VBA の改行コード</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/excel_vba.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.502</id>
   
   <published>2009-12-09T17:36:47Z</published>
   <updated>2009-12-09T17:38:41Z</updated>
   
   <summary>Excel VBA の改行コード</summary>
   <author>
      <name></name>
      
   </author>
         <category term="Excel VBA" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="431" label="VBA" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>Excel VBA の改行コードではまった。ググったら1発で出てきた。</p>]]>
      <![CDATA[

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://www.officepro.jp/excelvba/dialog/index4.html">vbNewLine</a></li>
</ul>
</div>

<br />

<table class="btType1">
<thead>
<tr>
<th>定義済み定数</th>
<th>実際の値</th>
<th>説明</th>
</tr>
</thead>

<tbody>
<tr><th>vbCr</th><td>Chr(13)</td><td>キャリッジリターン</td></tr>
<tr><th>vbLf</th><td>Chr(10)</td><td>ラインフィード</td></tr>
<tr><th>vbCrLf</th><td>Chr(13) + Chr(10)</td><td>キャリッジリターンとラインフィードの組み合わせ</td></tr>
<tr><th>vbNewLine</th><td>Chr(13) + Chr(10) または Chr(13) (Macintosh では Chr(13))</td><td>プラットフォームで指定した改行文字。現在のプラットフォームで適切ないずれかを使用します。</td></tr>
</tbody>
</table>

<p>この中の「vbNewLine」を使えば基本的にOKらしい。</p>

<?php $KT->am->viewBookGroup('excel'); ?>
]]>
   </content>
</entry>
<entry>
   <title>[PHP]google Analytics からアクセスの多いページの情報を取得</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/phpgoogle_analytics.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.501</id>
   
   <published>2009-12-04T17:19:31Z</published>
   <updated>2010-01-13T08:09:17Z</updated>
   
   <summary>google AnalyticsのAPIを利用してアクセスの多いページの情報を取得します。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="435" label="Google Analytics" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="338" label="サンプルコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="349" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>
google AnalyticsのAPIを利用してアクセスの多いページの情報を取得します。
利用するライブラリは↓
</p>]]>
      <![CDATA[<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://www.electrictoolbox.com/php-class-google-analytics-api/">PHP class for using the Google Analytics API</a></li>
</ul>
</div>

<p>気になっていたcurlが使ってあっていいサンプルになりそう。</p>


<h3>指定期間のPV数の多いページを取得</h3>


<p>利用するのはanalytics_api::data()。引数はたぶんこんな感じ。</p>

<h4>@param string $id</h4>
<p>
必須のパラメータ。サイトのプロファイルID。
IDは 「Analytics 設定  &gt;  プロファイル設定」で確認できる。
</p>
<p class="center"><img src="/pg/img/ga/01.gif" /></p>

<h4>@param string $dimension</h4>
<p>
必須のパラメータ。何のデータを取るかを指定。
ga:pagePathとかga:browserとか。
複数指定する場合はカンマで区切るga:browser,ga:browserVersion
</p>

<h4>@param string $metric</h4>
<p>
必須のパラメータ。何のデータを基準にするか的な指定。訪問者数ならga:visitsとか。
複数指定はカンマで区切る。ga:visits,ga:pageviews
</p>

<h4>@param string $sort</h4>
<p>
ソートの指定。指定しないと$metricに基づく。
</p>

<h4>@param string $start</h4>
<p>
期間の始まりを指定。指定しないと実行日前日から１ヶ月分になる。予め用意されている値には
today、yesterday、weekがある。
</p>

<h4>@param string $end</h4>
<p>
指定する場合はYYYY-MM-DDで。デフォルトは前日。
</p>

<h4>@param integer $max_results</h4>
<p>
取得するMAX件数。デフォルトは10件。最高でも1000件？
</p>

<h4>@param integer $start_index</h4>
<p>
取得するページのインデックス。デフォルトはページ目から。
</p>

<h4>@param string|analytics_filters</h4>
<p>
フィルター。analytics_filtersってクラスが用意されているので
何かしらフィルターをかけれるっぽいけど詳細は不明
</p>

<h4>@param boolean $debug</h4>
<p>
デバッグ用？デフォルトはfalse
</p>



<p>
重要なパラメーターはDimensionsとMetrics。これを把握すれば自在に情報を取得できそう。
</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://code.google.com/intl/ja/apis/analytics/docs/gdata/gdataReferenceDimensionsMetrics.html">Dimensions &amp; Metrics Reference - Google Analytics - Google Code</a></li>
</ul>
</div>



<?php $KT->viewSource('
require_once(\'/analytics_api.php\');
$api = new analytics_api();

// 引数はログイン用のメールアドレスとパス
if($api->login(MAIL, PASS)) {
    $result = $api->data(
              \'ga:792415\',                 // id プロファイルのNoを指定
              \'ga:pageTitle,ga:pagePath\',  // dimension ページタイトルとパス
              \'ga:pageviews\',              // metric ページビュー
              false,                         // sort
              \'2008-11-01\',                // start
              \'2008-11-30\',                // end 
              \'25\'                         //max_results 取得件数
              );
} else {
    throw new Exception(\'ログインに失敗しました。IDとパス要確認\');
}

echo \'<pre>\';
var_dump($result);
echo \'</pre>\';
'); ?>

<p>実行結果は<a href="/pg/sample/ga.php">こちら</a></p>



<p>
キーが日本語でなんだか気持ち悪いけどまぁいいか。
あとはforeachとかでまわすだけ。
</p>

<?php $KT->viewSource('
$html = \'\';
foreach ($result as $name => $pagedata) {
    $title = $name;
    $url = key($pagedata);
    $view = $pagedata[$url][\'ga:pageviews\'];
    
    $html .= sprintf(
                    \'<li><a href="%s">%s(%sビュー)</a></li>\',
                    $url,$title,$view
                    );
}
echo \'<ol>\' . $html . \'</ol>\';
'); ?>


<h4>実行結果</h4>
<div class="result">
<?

require_once('analytics_api.php');
$api = new analytics_api();

// ログイン 引数はIDとパス
if($api->login(GA_ID, GA_PASS)) {
    $result = $api->data(
              'ga:792415',                 // id プロファイルのNoを指定
              'ga:pageTitle,ga:pagePath',  // dimension ページタイトルとパス
              'ga:pageviews',              // metric ページビュー
              false,                       // sort
              '2009-11-01',                // start
              '2009-11-30',                // end 
              '25'                         //max_results 取得件数
              );
} else {
    throw new Exception('ログインに失敗しました。IDとパス要確認');
}


$html = '';
foreach ($result as $name => $pagedata) {
    $title = $name;
    $url = key($pagedata);
    $view = $pagedata[$url]['ga:pageviews'];
    
    $html .= sprintf(
                    '<li><a href="%s">%s(%sビュー)</a></li>',
                    $url,htmlspecialchars($title, ENT_NOQUOTES, 'utf-8', 'auto'),$view
                    );
}
echo '<ol>' . $html . '</ol>';
?>
</div>

<p>んんっ！？(not set)ってなんだ・・・？フィルタ使えばこいうのはじけるのかな？</p>
<p>とりあえず置いておいてデータの比較をしてみる。</p>

<h4>カスタムレポート作成</h4>

<p>
Analyticsのカスタムレポート作成から新規作成でこんな感じで設定。
</p>


<p class="center"><img src="/pg/img/ga/02.gif" /></p>

<p>
レポートプレビューでレポートを表示して期間をあわせると
<a href="/pg/img/ga/03.gif" target="_brank" />こんな感じ</a>で出てくる。
</p>

<p>
なんか似てるけど結構違う結果。なぜだろ？？
数字はもしかしたらタイムゾーンの違いで誤差出てるのかも?
それかAPIのデータとAnalyticsのデータが異なってるか？
</p>

<p>ぼくの書いたスクリプトが間違ってたらごめんなさいw</p>

<p>まっ大体あってるからいいか・・・効果測定するわけじゃないし・・・と言い訳しながら終わります。</p>

<?php $KT->am->viewBookGroup('php'); ?>]]>
   </content>
</entry>
<entry>
   <title>PHPとYAML</title>
   <link rel="alternate" type="text/html" href="http://www.kantenna.com/pg/2009/12/phpyaml.php" />
   <id>tag:www.kantenna.com,2009:/pg//2.500</id>
   
   <published>2009-12-02T13:26:46Z</published>
   <updated>2010-01-13T08:11:48Z</updated>
   
   <summary>設定ファイルとか書くのはYAMLって形式が簡単でいいらしい。</summary>
   <author>
      <name></name>
      
   </author>
         <category term="PHP" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="341" label="テストコード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="349" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.kantenna.com/pg/">
      <![CDATA[<p>設定ファイルとか書くのはYAMLって形式が簡単でいいらしい。</p>]]>
      <![CDATA[<h3>YAMLとは？</h3>

<p>下記サイトがとても詳しくわかりやすく書かれているので読む。</p>

<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://jp.rubyist.net/magazine/?0009-YAML">Rubyist Magazine - プログラマーのための YAML 入門 (初級編)</a></li>
</ul>
</div>

<ul>
<li>データを「配列」「ハッシュ」「スカラー (数値や文字列や真偽値)」だけで表す</li>
<li>XMLより「読みやすい」「書きやすい」「わかりやすい」フォーマット</li>
<li>フロースタイルという形式で書けばJSONとしても扱える</li>
<li>仕様書によると文字コードはユニコードだけどEUCとかでも問題なさそう</li>
</ul>



<h3>PHPで扱うには？</h3>
<p>
簡単な方法はspycっていうクラスをダウンロードするだけ。
PHPの拡張モジュールとしてSyckっていうのがあるのでPHPの環境触れる場合はそちらを使ったほうがいいのかも。
でも機能がYAMLリーダだけ？
</p>


<div class="bqsite">
<h5>参照サイト</h5>
<ul>
<li><a href="http://code.google.com/p/spyc/">spyc - Project Hosting on Google Code</a></li>
<li><a href="http://www.doyouphp.jp/tips/tips_yaml.shtml">PHPでYAMLを扱う - Do You PHP?</a></li>
</ul>
</div>

<h3>テストコード</h3>
<p>サンプルのYAMLは<a href="http://jp.rubyist.net/magazine/?0009-YAML">Rubyist Magazine - プログラマーのための YAML 入門 (初級編)</a>そのままです。</p>

<h4>spyc.phpの中身</h4>
<p>
読み込むとSpycってクラスとspyc_load ($string)、function spyc_load_file ($file) って関数が利用できるようになる。
この2つの関数はSpyc::YAMLLoadString($string)とSpyc::YAMLLoad($file)を単に呼び出してるだけなので、
どちらを利用してもよさそう。関数使ったほうがいいのかな？
</p>



<h4>配列(sample1.yaml)</h4>
<? $KT->viewSource('
- aaa
- bbb
- ccc
'); ?>


<? $KT->viewSource('
require_once(\'spyc.php\');
$yaml = spyc_load_file(\'sample1.yaml\');

var_dump($yaml);
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$yaml_sample = LIB_PG_DATA . 'yaml/';

require_once('spyc.php');
$yaml = spyc_load_file($yaml_sample . 'sample1.yaml');

var_dump($yaml);
?>
</div>

<h4>ネストされた配列(sample2.yaml)</h4>
<? $KT->viewSource('
- aaa
-
  - b1
  - b2
  -
    - b3.1
    - b3.2
- ccc
'); ?>


<? $KT->viewSource('
require_once(\'spyc.php\');
$yaml = spyc_load_file(\'sample2.yaml\');

var_dump($yaml);
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$yaml = spyc_load_file($yaml_sample . 'sample2.yaml');
var_dump($yaml);
?>
</div>

<h4>連想配列(sample3.yaml)</h4>
<? $KT->viewSource('
A: aaa
B: bbb
C: ccc
'); ?>

<? $KT->viewSource('
require_once(\'spyc.php\');
$yaml = spyc_load_file(\'sample3.yaml\');

var_dump($yaml);
'); ?>


<h5>実行結果</h5>
<div class="result">
<?
$yaml = spyc_load_file($yaml_sample . 'sample3.yaml');
var_dump($yaml);
?>
</div>

<h4>ネストされた連想配列(sample4.yaml)</h4>

<? $KT->viewSource('
A: aaa
B:
  B1: bbb1
  B2: bbb2
C: ccc
'); ?>

<? $KT->viewSource('
require_once(\'spyc.php\');
$yaml = spyc_load_file(\'sample4.yaml\');

var_dump($yaml);
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$yaml = spyc_load_file($yaml_sample . 'sample4.yaml');
var_dump($yaml);
?>
</div>



<h4>データ型の確認(sample5.yaml)</h4>
<? $KT->viewSource('
decimal1:  123                           # 整数 (10 進数)
decimal2:  1,234,567,890                 # 整数 (10 進数)
octal:     0644                          # 整数 (8 進数)
hexa:      0xFF                          # 整数 (16 進数)
float1:    0.05                          # 浮動小数点
bool1:     true                          # 真
bool2:     yes                           # 真
bool3:     on                            # 真
bool4:     false                         # 偽
bool5:     no                            # 偽
bool6:     off                           # 偽
null1:     ~                             # Null 値
null2:     null                          # Null 値
date:      2005-01-01                    # 日付
stamp:     2005-01-01 00:00:00 +09:00    # タイムスタンプ
str1:      \'true\'                        # 文字列
str2:      "2005"                        # 文字列
symbol:    :foo                          # シンボル (Syck の独自機能)
'); ?>

<? $KT->viewSource('
echo \'PHP_VERSION : \', PHP_VERSION, \'<br />\';
$yaml = spyc_load_file(\'sample5.yaml\');
echo \'<pre>\';
var_dump($yaml);
echo \'</pre>\';
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
echo 'PHP_VERSION : ', PHP_VERSION, '<br />';
$yaml = spyc_load_file($yaml_sample . 'sample5.yaml');

echo '<pre>';
var_dump($yaml);
echo '</pre>';
?>
</div>

<p>PHPに無い型はともかくとして、その他もアテにならない模様。</p>




<h4>JSON(sample6.yaml)</h4>
<p>YAMLをフロースタイルで書くとJSONと等価になる。</p>

<? $KT->viewSource('
{ "menu": {
    "id": "file",
    "value": "File:",
    "popup": {
      "menuitem": [
        {"value": "New", "onclick": "CreateNewDoc()"},
        {"value": "Open", "onclick": "OpenDoc()"},
        {"value": "Close", "onclick": "CloseDoc()"}
      ]
    }
  }
}
'); ?>

<? $KT->viewSource('
$yaml = spyc_load_file(\'sample6.yaml\');

echo \'<pre>\';
var_dump($yaml);
echo \'</pre>\';
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$yaml = spyc_load_file($yaml_sample . 'sample6.yaml');

echo '<pre>';
var_dump($yaml);
echo '</pre>';
?>
</div>

<p>PHPのspycでは対応していないみたいです。{}がダメっぽい。JSONの場合は<a href="http://www.php.net/manual/ja/function.json-decode.php">json_decode()</a>を使う。</p>

<? $KT->viewSource('
echo \'<pre>\';
var_dump(json_decode(file_get_contents(\'sample6.yaml\')));
echo \'</pre>\';
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
echo '<pre>';
var_dump(json_decode(file_get_contents($yaml_sample . 'sample6.yaml')));
echo '</pre>';
?>
</div>






<h4>配列からYAMLへ</h4>
<p>Spyc::YAMLDump()、Spyc::dump()が用意されている。Spyc::YAMLDump()はstaticにアクセス可能。</p>
<p>YAMLを読み込んで再びYAMLにしてみる。</p>


<h5>実行結果</h5>
<div class="result">
<?
$arr = spyc_load_file($yaml_sample . 'sample4.yaml');
echo '<pre>';
var_dump($arr);
echo '</pre>';

echo '<hr />';

$yaml = Spyc::YAMLDump($arr);
echo '<pre>';
var_dump($yaml);
echo '</pre>';
?>
</div>

<p>「---」はひとつのファイルに複数のYAMLを記述するためのもの。ただしPHPのSpycは対応してないっぽい?</p>

<h4>---で区切られたYAML(sample7.yaml)</h4>
<? $KT->viewSource('
---
- aaa
- bbb
- ccc
---
- ddd
- eee
- fff
'); ?>

<? $KT->viewSource('
$yaml = spyc_load_file(\'sample7.yaml\');

echo \'<pre>\';
var_dump($yaml);
echo \'</pre>\';
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$yaml = spyc_load_file($yaml_sample . 'sample7.yaml');

echo '<pre>';
var_dump($yaml);
echo '</pre>';
?>
</div>

<p>1個の配列で返ってくる。嫌な場合は自力で分割。</p>
<? $KT->viewSource('
$arr = preg_split(\'/^---$/m\', file_get_contents($yaml_sample . \'sample7.yaml\'));

$yamls = array();
foreach ($arr as $yaml) {
    if (!empty($yaml)) {
        $yamls[] = spyc_load($yaml);
    }
} 

echo \'<pre>\';
var_dump($yamls);
echo \'</pre>\';
'); ?>

<h5>実行結果</h5>
<div class="result">
<?
$arr = preg_split('/^---$/m', file_get_contents($yaml_sample . 'sample7.yaml'));

$yamls = array();
foreach ($arr as $yaml) {
    if (!empty($yaml)) {
        $yamls[] = spyc_load($yaml);
    }
} 

echo '<pre>';
var_dump($yamls);
echo '</pre>';
?>
</div>

<p>ってか<a href="http://www.php.net/manual/ja/function.split.php">split()</a>非推奨になったんだ。</p>

<? $KT->am->viewBookGroup('php'); ?>]]>
   </content>
</entry>

</feed>
