2008年03月12日

いってるそばから、Updateされるらしいです。

akihiro kamijo: 来月 (2008/4) の Flash Player セキュリティアップデート

確かに、昨年末には発表してたけど、予定日の発表おそすぎます。

夏くらいかなぁ?と余裕ぶっこいてました。

ま。不満を言ってても始まりませんので。

さて。

前回のエントリーしましたが、Socket用のcrossdomain.xmlは同一ドメインでもダメで、HTTP経由のcrossdomain.xmlでもダメになりますという話で、今回もそこを中心に補足したいと思います。

なお、通常の(Socket,XMLSocketクラス以外)crossdomain制約については従来通りと思いますので、ご心配なく。

ちょっとアレゲなことをしている人達が被害にあいます。

(他の変更点もあるので、安心しないでください。kamijoさんのブログ参照。)

かなり暴力的に説明すると、Flashが(ドメイン関係における)セキュリティにひっかかって動かないのは大きく2パターンで、外部ドメイン(領域)のデータ(バイナリ)にアクセスするような場合は、crossdomain.xmlが必要になり、もうひとつは、クロススクリプト(ロードしたswfのスクリプトをコールしたり、オブジェクトにアクセスするような行為)はallowDomain()を利用することになります。

クロススクリプトのほうが、Security.sandboxTypeなどの根が深いのでいろいろ面倒かもしれません。

問題のcrossdomain.xmlが必要になるようなケース、データにアクセスするような行為というのは、絶妙で、例えば画像やサウンドをロードするだけではポリシーに引っかからないのですが、いざピクセル操作や、drawとか、サウンドの場合はスペクトラムを見に行こうとすると、突然セキュリティエラーになるわけです。

逆に、テキストのロードや、バイナリを、URLLoader.load()しようとするとその時点でセキュリティエラーとなります。

おそらく現場では、

「うわー画像操作でエラーでたー」

「load()の引数の、LoaderContext設定しとくといいらしいぜ」

といった感じで単発解決しがちだと思いますが(少なくとも昔の私はそうであった)その法則はいろんなところで当てはまるというのを理解しておくと良いかもしれません。

(まぁ、これはcrossdomain.xmlの存在というよりは、必要になるのでメッソド実行の前にcrossdomai.xmlをチェックしておくようにという処理なのですが)

ロードするだけであれば、crossdomain.xml が必要されないメソッドは

Loader.load()~~Sound.load()~~NetStream.play()

らしいです。メソッドに依存するんですね。

詳しくは、Essential ActionScript の 19章にとてもよくまとめられています。(ホント、良い本です。日本語だったらもっとよかった。)

さて、大幅に脱線しましたが、Socketも同様にcrossdomain.xmlを必要として、上記のデータにアクセスする行為と一件して同じに見えるのですが、実装しようとすると大変な作業になります。

Adobeのサイトには、気軽にcrossdomain.xml置いてね。

とありますが、via HTTP の取得が不可能ということで、crossdomain.xmlを返すサーバを用意しろという話になります。

で、どんなプロトコルなのかドキュメントから引用すると

サーバーはポリシーファイルを送信するか、メイン接続を確立するかの決定の前に、クライアントからの最初の送信を待機する必要があります。Flash Player は、ポリシーファイルを要求する場合、接続が確立されると同時に、必ず次のストリングを送信します。~~ ~~

こんだけ。

これにポリシーファイルを返して接続を切れ。

という仕様しか書いてないと思います。Essential ActionScript にもそれしか書いてないし。

Adobe的には、それ以外のエラーはスクリプトで処理せよ。ということなのかな?

デフォルトのポートは843ということなので、Socket.connectを発動したときにFlashプレイヤーは、843へ自動的に問い合わせるのでしょう。

手動で問い合わせる方法は

Security.loadPolicyFile('xmlsocket://hoge:808');

となります。

あとは、Socket.connect をtryして、SecurityError を catch することで判断するしかないのかもしれません。

前回説明したとおり、1024番ポート以上でポリシーファイルを返した場合、Socketは1024番ポート以上にしかアクセスできないので注意してください。

crossdomain.xml内のallow-access-fromタグに、to-port属性もお忘れなきよう。

~~

 ~~

to-ports属性にアスタリスク(*)も指定できますが、1024番ルールは有効ですので注意してください。

私もいろいろ試してみようと思います。

試した方は、いろいろ教えてください。

追記

Flash Player が、policy file 取得に投げる

ですが、正確には最後にNullのバイトコード(00)が付きます。

それ以外のゴミはつきませんので、特殊な心配はいらないようです。

Socket.connect 時にデフォルトで、843ポートに問い合わせることも確認済みです。

エラーはSecurityErrorEventをハンドリングするしかないようです。

イベントオブジェクトを toString() で変換してから出力しても、種類は分類できそうにありません。

内容は以下の通りです。

[SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048"]



(00:47)

2008年03月03日

今日はAS3のSocketクラスを使うのが結構大変だ。というネタを。
めずらしく真面目に書いてみようと思います。
How toではなく、AS3のSocketってどうなの?的な話です。
おい!勘違いしてんじゃねぇボケ!などあれば
ツッコミなどもらえると嬉しいです。

■FlashでSocketがなぜ必要なのか
多くのFlashコンテンツにおいて、サーバ連携のためにSocketが必要になることはあまりないでしょう。
Loader系のクラスを使えば、HTTP経由でサーバ上のデータをひっぱってこれるからです。
HTTP以外のプロトコルを使う場合にSocketが必要ですが、現場レベルでは、あまり必要ないでしょう。
ただし、ビルトインのAS3クラスだけでは、HTTPのプロトコルを自在に扱うことが出来ないので、APIを利用したい場合など問題になることがあります。
例えばレスポンスヘッダが(一部しか)取れません。
Atomなどを利用したサーバAPIと連携する場合、Socketを利用する必要が出てきます。
多くの人は、自前で作るのではなく、以下のようなライブラリを利用していることと思います。

---------------------------------------------------------
as3httpclient - Google Code
as3httpclientlib - Google Code
---------------------------------------------------------

ちなみに、後者のほうが最近に出たものです。
Javaライクなので、Javaになじみのある方は後者のほうがより読みやすいかもしれません。
(私はJava専門じゃないので、自分で確かめてください。)
as3httpclient の作者であるAbdul Qabiz氏も、後者のほうがベターといっているので参考にしてみてください。
as3httpclientlib - a better http-client in ActionScript by Gabe: Abdul Qabiz's Blog - India

■SocketとFlash Playerセキュリティ
Flash Playerは別ドメインのデータへのアクセスについて、セキュリティな制限を持ちます。
クロスドメインというやつですが、正確にいうと、サブドメインが違うものも別領域として扱われます。
また、IPアドレス直によるアクセスも別領域扱いです。
(名前解決の結果、同一のIPであっても、URL指定のアクセスとは別領域として扱われる。)
FlashPlayerの全体的なセキュリティの話は、ボリューム満点なので、別の機会にしてSocketについてのみ触れておきます。
Socketによる別領域へのアクセスは、crossdomain.xml の制約を受けます。
ただし、通常のcrossdomain.xmlポリシーファイルでは、アクセス制限を解除できない場合があり、専用のルールを持っていて、ソケットポリシーファイルと呼ばれます。
ソケットポリシーファイルは、to-ports属性を持つことで特定のポートへのアクセスを許可します。
ソケットポリシーファイルのルールは、やや複雑です。
以下のようなルールになっています。
-----------------------------------------
・to-ports属性のないソケットポリシーファイルは、いかなるポートへのアクセスも許可しない。
・1023番ポート以下のポートから受け取ったポリシーファイルのみ、1023番以下のポートへのアクセスを許可できる。
・HTTP経由で取得したポリシーファイルでは、1023番以下のポートへはアクセスできない。
・HTTP経由で取得するポリシーファイルは、ルート(ドキュメントルート)にある必要がある。
・HTTP経由で取得したポリシーファイルは、暗黙的に1024番以上の全てのポートへのアクセスを許可する。
-----------------------------------------
どうでしょう?違和感を感じませんか?
つまり、ソケットポリシーファイルというのは、それ自身ソケットを利用して取得されます。
ポリシーファイルを返すように、サーバでリッスンしておく必要があります。
特に80番ポートといったような、すでに何かしらのサーバサイドデーモンが動作している場合、別に(1023番ポート以下で)ポートを空けて、ポリシーファイルを返さなければいけません。
これは面倒なので、大抵の場合はHTTP経由のポリシーファイルを利用すると思います。
この場合、to-ports属性は全く無意味で、結局1024番ポート以上にしか接続できないということなのです。

■将来Socketが引き起こすかもしれない問題
以上のような問題に加えて、昨年末に以下のような発表がありました。
Adobe - Developer Center : Security changes in Flash Player 9

この記事によるポリシーファイルに関する発表はふたつ。
ひとつは、Meta-policyファイルと呼ばれる、ポリシーファイルのポリシーファイル(ポリシーファイルを許可するとかしないとか設定できる)ホスティングを展開するときに使うようなもの。
もうひとつが、ソケットポリシーファイルについてで、以下のように言及されています。
-------------------------------------------
・A SWF file may no longer make a socket connection to its own domain without a socket policy file
・HTTP policy files may no longer be used to authorize socket connections
-------------------------------------------
つまり、将来的にはクロスドメインでなくとも、ソケット接続にはポリシーファイルが必要になる。
HTTP経由のポリシーファイルは許可されなくなる。
ということで、これは実質、サーバの準備をしていないと、Flash Player がアップデイトされたときに、Socketの多くが機能しなくなることを意味しています。
これは、私の理解が間違っているのかもしれません(そう思いたい)。
ので、誰かちゃんと読んでください。(他力本願ですんません)

ちなみに、Flash Player が発行するポリシーファイル取得のプロトコルが不明瞭で、私が知る限り、非常にシンプルなもので、テキストを一行なげるので、それにポリシーファイルを返すだけ。という定義しかありません。

なお、前述したas3httpclientlibの作者であるAbdul氏が、AdobeのJIRAにポストしている内容があるので貼っておきます。
[#ASC-3122] ECR: Binary Socket connection should be allowed to a HTTP server without any special policy file - Adobe Bug System

せめて、URLLoaderを改良するか、ポリシーファイル用のデーモンを用意するとかの処置が欲しいものです。

(23:31)

2008年02月06日

Flash CS3 を普段なーんも考えずに使っていますけど。
なんか、アップデイトされてますね。
System.gc とかいうガーベッジコレクタを強制発動するメソッドが追加されてました。
CS3 でも使えるって知ってましたか?
僕は知りませんでした。(ダメ)

実際の製作物内に使うことは、あまりないかもしれませんが
これで挙動をチェックしたりできますね。
(そもそも、デバッグモードでしか動かないとかあるかな?)

というわけで、実験!実験!
まずは、function の中の変数は、function が終了した時点で GC の餌食になるのを見てみます。

テキトーに、test_mc というインスタンス名の MC を作って置いてください。
んで、コレ。

import fl.transitions.Tween;
import fl.transitions.easing.None;

var testTween:Tween;
GCdemo();
// System.gc();

function GCdemo():void {
  var testTween:Tween =
    new Tween(test_mc,'y',None.easeNone,0,100,1,true);
}

単純にTweenで、MCが、0から100まで動くサンプルですが
System.gc(); をコメントインすると動かなくなります。
function が最後まで流れた時点で、testTween オブジェクトが GC されるから。

グローバルに持たせておくと、GC されません。

import fl.transitions.Tween;
import fl.transitions.easing.None;

var testTween:Tween = GCdemo();
System.gc();

function GCdemo():Tween {
  return(new Tween(test_mc,'y',None.easeNone,0,100,1,true));
}


addChild されてる、表示オブジェクトも GC されません。
(ちゃんとStageからの一連の表示リストに入ってないとアウト)
以下、TestMC クラスはライブラリ内にテキトーに作っておいて。

GCdemo();
System.gc();

function GCdemo():void {
  var testMC:TestMC = new TestMC();
  addChild(testMC);
}


どうでしょう?
相変わらず、あんま役に立たなそうな情報ですが。
まぁ、自分で試してください。

UPDATE3 は、結構いろいろありますね。
Flash Player 9.0.115.0 は、大きめのリリースでして。
今後の Security Update Phase2 ってのが怖いトコロです。
別途、気が向いたら書きます。

(00:42)

2008年01月27日

AS3で陥りがちなメモリーリーク - AS3S.ORG

コレについて、私は真偽は知らないんですが(確かめろって話ですが。。)、
ただ removeEventListener() しないと表示オブジェクトがガベッジコレクタの対象にならないわけではありません。(たぶんね。)

以下のコードは、TextField を増やしていって、ガベッジコレクタが走ったと思われる瞬間に、処理を終了するコードです。
(参考:Essential Actionscript3.0 P277)


package {
  import flash.display.*;
  import flash.events.*;
  import flash.text.TextField;
  import flash.system.System;

  public class GCDemo extends MovieClip {
    var _start_memory:uint = 0;
    var _prev_memory:uint = 0;

    public function GCDemo() {
      _start_memory = _prev_memory = System.totalMemory;
      addEventListener(Event.ENTER_FRAME, enterFrameListener);
    }

    private function enterFrameListener(e:Event):void {
      var cur_memory:uint = System.totalMemory;
      var cur_text:TextField = new TextField();
      //cur_text.addEventListener(MouseEvent.CLICK, textClickHandler);

      if(_prev_memory <= cur_memory) {
        trace("increasing : " + cur_memory);
        _prev_memory = cur_memory;
      } else {
        trace("cleared!");
        trace("starting memory : " + _start_memory);
        trace("current memory : " + cur_memory);
        trace("previous memory : " + _prev_memory);
        e.target.removeEventListener(e.type, arguments.callee);
      }
    }

    private function textClickHandler(e:MouseEvent):void {
    }
  }
}


cur_text は TextField オブジェクトへの参照を持ちますが
関数内のローカル変数なので、変数 cur_text 自体は enterFrameListener が終了した時点で有効でなくなります。
つまり、そこで作られた TextField オブジェクトは、それ自身を参照してくれる変数を失います。
よって、そこで作られた TextField オブジェクトはガベッジコレクタの対象になります。

これは、cur_text を作る、次の行での addEventListener をコメントインしても同様の結果が得られるはずです。
逆に addChild してしまった場合、removeChild しないと
cur_text に null を代入しておいても、ガベッジコレクタの対象になりません。

as3 の参照のややこしさは、表示オブジェクトまわりでしょうね。
まぁ、自分が removeEventListener することを心がけてないので、自己弁護したかっただけです。
ごめんなさい。
がんばります。

(18:58)

2007年12月17日

「豚本」とでも呼ばれるのでしょうか。

初めてのFlash Video


(23:40)

2007年11月27日

もうちょっと、ちゃんと書きなさいと怒られたので、少し補足。
RegExp のほうが遅いかなぁって言ったやつ。
簡単に試してみました。
ちなみに、ウチの環境は flash CS3 / Pen4 3.2GHz / WindowsXP です。

// 50,000 文字の文字列サンプル
var num:uint = 10000;
var str:String = '';
while(num --) {
str += 'あかさたな';
}

// 実験その1 --------------------
// 開始時間とか
var start_time:uint = getTimer();
var len:uint = str.length;

// 一文字づつ50,000文字をチェック
while(len --) {
if(str.charCodeAt(len) <= 0xff) break;
}
trace(getTimer() - start_time);

// 実験その2 --------------------
// 開始時間とかを初期化
start_time = getTimer();
len = str.length;

// 置換
var pattern:RegExp = /[ぁ-ん]+/g;
str = str.replace(pattern, '');
trace(getTimer() - start_time);


ループするほうが、14msec
置換するほうが、6msec
でした。

おい!ループのほうがおそいやんけ!
という話ですが、使う文字列を
str += 'あかaたな';
の繰り替えしにすると、置換する場所が一気に増えますね。

その場合の結果は
ループするほうが、0msec(3文字目でループ抜けるし)
置換するほうが、9627msec
でした。

まぁ、使わない知識ですね。
5万文字のフォームなんてないし。

それと、正規表現のオプション g は全てを置換するオプションです。
純粋に、全角だけで構成されるのを調べたい場合は、g を外して length が 0 かどうかを調べれば済む話なので、g を取ってしまえば問題ありません。
(/[ぁ-ん]+/g のやつ)

将来的に、「全角を含む文字列」判定とかもいるかなと思って、ループにしてますが、まぁ用途の応じてといったところでしょうか。
正規表現は、すごく便利ですが、そういった仕事はなるべくサーバサイドにやらせて、AS 内ではあまり使いたくないなぁと今のところ思ってます。
正規表現って、すぐ忘れるんですよね。
コピペ、コピペです。

(00:40)

2007年11月25日

全角とかチェックするやつ。
いまさら、こんなコードが書けるのもASだからこそって感じですが、ホントもうね。。。
めんどくさい。
というワケで、適当ですが。

AS3 文字コード判定するやつ

これをコピペして、JCharChecker.as という名前にして、import してください。
こんな感じで。
import JCharChecker;
// 全部半角だったらtrue
trace(JCharChecker.isHankakuKana('調べたい文字列'));


かなりテキトーなコードですが、参考にしてもらって、作業時間の短縮になればなによりです。間違いとかあったら教えてください。

ネームスペースとか切るのも、なんだかなぁというコードなので、参考にして、綺麗に書いてくれたり、JValidator なんて作ってくれる人がいたらステキですね。

このコードでは、よくある(?)文字コードで判別していますが、AS3 では、正規表現も使えるので、そちらでやってみるのも一興かもしれません。

/* 全角半角スペースの連続パターン */
private static const HIRAGANA_PATTERN:RegExp = /[ぁ-ん]+/g;
public static function isHiragana(val:String):Boolean {
return(val.replace(HIRAGANA_PATTERN, '').length == 0);
}


とか?
中身が短い場合は、パフォーマンスにほぼ差がないハズです。
ただ、数万文字単位の文字列の場合は、(入力される文字列にもよりますが)RegExp 使ったほうが遅いハズです。
(たぶん。ちゃんと調べろ。オレ)

あとは、TextField には、maxChars や restrict というプロパティがあるので、そちらで入力可能な長さや、文字を指定するとかでいいと思います。

サーバ連携が必要な場合、基本的には、簡単にコレだけで済ませておいて、true / false をサーバ側から返してもらうのが、簡単・安全な方法かもしれませんね。

クライアントサイドだけで、アラート出したりする要望も結構あると思いますが、その辺りは、納期やサーバ側のエンジニアと相談というったトコロでしょうか。

(20:17)

2007年11月11日

ES4 を追いかけてる暇あったら、AS3 追いかけなきゃいかん状況なんですが、少し気になりますね。Adobe Max(Shibuya.js も同じかな?)で使われた、スライドがあがってるみたいです。
John Resig - ECMAScript 4 Speaking Tour

前にも書きましたが、個人的にはカオスなイメージです。
C++? JAVA? Haskell?
もう堪忍してほしいです。高次レイヤー専門にしておいて。。。

moock.org のブログに、ML での議論抜粋みたいなのがあって、おもしろい。
moockblog: the politics of javascript/actionscript's future

AS3ですら普及の道が危ういんじゃないかと思ってるんですけど(実務・現場レベルでの話し)、どうなんでしょうね?
うれしい人のほうが多いのかしら?

(01:16)

2007年11月10日

まずは、コチラをご覧ください。
http://www.borndigital.co.jp/reallusion/image/neko.gif

これは、夢に出てきそうな勢いですね。
というワケで、ソフトを使って画像シーケンスを切り出せるので、これにスクリプトをつけると、ちょっと遊べますね。
(ちなみに、アニメーションgifは、そのままflaファイルにもってくとシーケンスにしてくれるので、この猫でも実験できます)
実務で使うことは、あんまりなさそうですが、引き出しのひとつとして覚えておいても良いかもしれません。

ボーンデジタル / Reallusion Crazy Talk 4

(01:07)

2007年11月03日

Daniel Dura » Google OpenSocial ActionScript Library

期待。
時間に余裕がある人は、出し抜いてみては?
corelib を import するのかな?

(20:07)