yoyaのメモ

2010/11/09(Tue) array_diff_recursive

[]array_diff_recursive

ググっても見つからなかったので作ってみた。(所要時間10分)

解決したい問題

<?php
$a = array('a' => 'a',
        'b' => array('b', 'c'));

$b = array('a' => 'a',
        'b' => array('b'));

var_dump(array_diff($a, $b));

残念な結果

array(0) {
}

function

<?php
function array_diff_recursive($a, $b) {
    $result = array();
    foreach ($a as $k => $v) {
        if (array_key_exists($k, $b)) {
            if (is_array($v)) {
                $result[$k] = array_diff_recursive($v, $b[$k]);
            } else {
                if ($v != $b[$k]) {
                    $result[$k] = $v;
                }
            }
        } else {
            $result[$k] = $v;
        }
    }
    return $result;
}

テスト

<?php
$a = array('a' => 'a',
        'b' => array('b', 'c'));

$b = array('a' => 'a',
        'b' => array('b'));

var_dump(array_diff($a, $b));
var_dump(array_diff_recursive($a, $b));

結果

array(0) {
}
array(1) {
  ["b"]=>
  array(1) {
    [1]=>
    string(1) "c"
  }
}

追記

ほぼ同じルーチンが既にありました。(count 0 の扱いが違うだけ)

見ないで作ったのに、そっくりになったのはちょっと感動。

追記2

当初(5分で)作った没バージョン。色々微妙だけど晒してみる。

<?php
function array_diff_recursive($a, $b) {
    $result = array();
    if (is_array($a)) {
        foreach ($a as $k => $v) {
            if (isset($b[$k])) {
                $ret = array_diff_recursive($a[$k], $b[$k]);
                if (count($ret) > 0) {
                    $result[$k] = $ret;
                }
            } else {
                $result[$k] = $a[$k];
            }
        }
    } else {
        if ($a != $b) {
            return $a;
        }
    }
    return $result;
}

これを5分位で改良して、冒頭の array_diff_recursive が出来ました。

2010/06/23(Wed) PHPでBit処理の簡易フレームワークを作ってみた。

[]PHPでBit処理の簡易フレームワークを作ってみた。

名付けて BitIndexer

とりあえず Parse だけ。Builder はこれから作る。

テストコード

14bit ずつ切り出してダンプ

<?php

// SampleParser

require_once dirname(__FILE__).'/ByteBit.php';
require_once dirname(__FILE__).'/BitIndexer.php';
require_once dirname(__FILE__).'/BitIndexer/Parser.php';

class SampleParser extends BitIndexer_Parser {
    function getChunk($data, $offset, $length) {
        static $i = 0;
        $ret = array('name' => "sample_$i", 'length' => new ByteBit(0, 14));
        $i++;
        return $ret;
    }
}

// sample code

$data = 'ABCDE';

$parser = new SampleParser();
$indexer = new BitIndexer($parser);
$indexer->parse($data, strlen($data));

$indexer->dump();

実行結果

% php SampleParser.php
* sample_0
            0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  0123456789abcdef
0x00000000 41 42                                             AB

* sample_1
            0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  0123456789abcdef
0x00000000    42 43 44                                        BCD

* sample_2
            0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  0123456789abcdef
0x00000000          44 45                                       DE

プログラム

phps を php にすれば、動作するはず。

課題

本当にやりたいのは、Chunk をいじって後の連結で、

つまり、バイナリの編集をやりやすくしたいって事です。

あと入れ子構造もうまく表現したい。

2010/03/24(Wed) 配列の + 演算子が便利な件 (2)

[]配列の + 演算子が便利な件 (2)

以前、PHP 配列の + 演算子が便利な件 - yoyaのメモ

の中で、上書き関係がどうのと書きながら、

もっと本質的な挙動の違いに触れなかったので、今更ながら追記。

array_merge は連想配列の合成には使えない

連想配列でキーに数字(又は数字と解釈できる文字列)を使うと、

その数値がリナンバリングされるので、配列の merge には便利ですが、

連想配列の merge を期待すると痛い目を見ます。

実例

$a = array('XXX' => 'a', '111' => 'b', '222'  => 'c', );
$b = array('XXX' => 'x', '222' => 'y', 'ZZZ' => 'z');
print_r(array_merge($a, $b));
print_r($a + $b); echo "\n";

実行結果

Array
(
    [XXX] => x
    [0] => b
    [1] => c
    [2] => y
    [ZZZ] => z
)
Array
(
    [XXX] => a
    [111] => b
    [222] => c
    [ZZZ] => z
)

例えば、何かの id値 を key にして連想配列で処理というのはありがちで、

そんなデータ構造に array_merge を使うと、key が 0, 1, 2 に書き変わっちゃうと。

ついでに array_merge_recursive

$a = array('XXX' => 'a', '111' => 'b', '222'  => 'c', );
$b = array('XXX' => 'x', '222' => 'y', 'ZZZ' => 'z');

print_r(array_merge_recursive($a, $b));
Array
(
    [XXX] => Array
        (
            [0] => a
            [1] => x
        )

    [0] => b
    [1] => c
    [2] => y
    [ZZZ] => z
)

意地でもデータをロストしない、この努力が涙ぐましいですw

でも、key は renumbering されるんですよね。使いどころが難しい関数群です。

2009/07/09(Thu) swftools for PHP

[]swftools for PHP

swftools を PHP に binding する試みを開始。

準備

とりあえず、php extension を作る際のイニシエーションの儀式。

% cd php-5.2.9
% ./ext_skel --extname=swftools
% cd swftools
% vi config.m4
% ./configure
% make

詳しくはこっち ↓

HEAD の swftools をコピってきて同じディレクトリに置く

↓こんな感じ

 swftools4ph
    |- php_swftools.h
    |- swftools.c
    |- swfcombine.c
    |- config.m4
    |- swftools/

実装

とりあえず、swfcombine を。

  • php_swftools.h と swftools.c に関数のエントリを作成
  • src/swfcombine.c をコピって来て main を書き換える

とりあえずは、PHP の arguments リストをそのまま main の argv に変換するだけ。

  • zend_parse_parameters に a を指定して PHP 配列を取得
  • 配列の要素数を数えて argc にセット& argv の格納場所を alloc
  • 配列を argv に入れ直して、その要素を convert_to_string_ex で文字列に変換

これだと exec してるのを使い勝手が変わらないので、

(プロセスを新規に作らないだけ)、PHP っぽいインターフェースを考え中。

とりあえず、ファイルを介さないとダメなのはダサいので、

ビルド

phpize
CFLAGS="-g -O2 -DSWFTOOLS_DATADIR=\\\"hoge\\\"" ./configure
make

現状

これから動作確認開始。

多分、動かないと思うけどファイルを晒します。

今のところ、

$args = array('-m', '/tmp/master.swf', '-s', '/tmp/slave.swf',

...);

$swfdata = swfcombine($args);

こんな感じで動かせるところまで持っていこうかと。

2009/03/23(Mon) PHP勉強会@関東

[]PHP勉強会@関東

http://events.php.gr.jp/events/show/71

なんでかPHPと関係ないバグ管理システムのRedmineが1番面白くてタメになった気がする不思議。id:yandodさん最高!

冒頭のフレームワーク話しは XSS対策で入力バリデート強化って時点で…なんていうか、サニタイズ言うなや的な…レイヤーレンダリングも便利というより面倒そうなイメージでちょっと残念。

スパイダリング話しで、パッケージの頭にWWWを付けて良いか、そもそもPHP自体がWWWを扱うのに?という話しがあったけど全く問題ないと思う、だってWWWはインターネット上に拡がる蜘蛛の巣で、その上に乗ってるサービス(リソース?)にアクセスしてる訳だし。Net_ も思い付くけど、こっちはもっとRawレベルなイメージ

…懇親会にも出たかったけど、明日も仕事があるので涙を飲んで諦め。すっかり朝型の自分が恨めしい(;´・`)

P.S. Shimookaさんがめちゃスマートなのに驚いた。Wassrではあんなにデップリしてるのにw

P.P.S. 素敵な場所を提供してくれてありがとうございます。> トライコーンさん

きちんと伝えられなくて申し訳ない - MugeSoの日記

id:MugeSoさんから補足がありました。

XSS脆弱性の報告によって発覚したバリデーションの抜け穴を塞いだ
ということであって、XSS対策でというわけではありません。

なるほど。勘違いしてました。

あと、レンダリングのレイアウト機構もこの説明で納得です。

どのテンプレートを使うかという情報はレイヤーの設定はレイアウト
といって設定ファイル(output_type.xml)で設定できます。
<layouts default="default">
     <省略>

これだけの設定で、あちこちの template に include を入れまわる

のをやめられるのは素晴らしいです。

きちんと読み取れませんでした。すみません精進します。(´Д`;)