Neo Inspiration

Avatar

中の人:jakkrokk (HN統一しました) がphp,javascript,air,flex などなど好き勝手書いてます。仕事は主にWEBシステムの設計と開発、SEO全般など。

FizzBuzz問題

最近朝頭の体操がてら今更ながら コードゴルフをやってたりするんですが、
こんなの

世の中の人はすげえなぁっと。

FizzBuzz問題っていうのは
検索すればいっぱい出てきますが、ようは
世界のナベアツをコードにすればいいだけの話。
(3の倍数はFizz 5の倍数はBuzz 15の倍数はFizzBuzzを出力)

これだけなんだけど、どこまでコードを短くできるかっていうと
めっちゃむずい。

結局ここでオレはくじけました。

<?for(;++$i<101;)echo($i%3?$i%5?$i:'':'Fizz').($i%5?"\n":"Buzz\n");

これで67文字ですが、もはやphpとは思えない。。
部下がこんなソースコード書いたら張り倒します。

でもTOPの人とは11文字も差があるわけで。
そもそも三項式とか使わないやり方じゃないとむりかもなーと思ったり。
printfあたりで何かできそうな予感。と思いつつ、一旦ここでくじけ。

どうやって56文字作るんだろう。

PHPで非同期的なことをやってみる

非同期といっても、イベントを投げるだけなので、
非同期で行った結果を取得できないので、使いどころは少ないという。。

まあ一応こんなやり方もできましたってことで。

やり方としてはキックする側とキックされる側を少し弄ればOK

キックする側

こんな感じの関数を書いてみました。
単純にURIにアクセスして、fgetせずに即コネクションを落とすというだけ。

function async_access($uri){
    if ($parsed = parse_url($uri)) {
        $host = $parsed['host'];
        $path = ($parsed['query'])?$parsed['path'].'?'.$parsed['query']:$parsed['path'];
        if (isset($host) && isset($path)) {
            $fp = fsockopen($host,80,$errNumber,$errMessage,3);
            if ($fp) {
                $request = "GET {$path} HTTP/1.1\r\n";
                $request .= "Host: {$host}\r\n";
                $request .= "Connection: close\r\n\r\n";
                fputs($fp,$request);
                fclose($fp);
                return true;
            }
        }
    }
    return false;
}

ただ普通にやるとこれだけだと、キックされる側によって、
PHPが最後まで実行される or されない というのが変わってしまうので、
キックされる側のPHPをチェックします。

キックされる側

ここらへんPHPの接続処理関係
をみればわかるように、PHPのステータスは3つあるわけですが、
今回のように即コネクションを閉じてしまうと基本的にはABORTEDになるわけです。
で、このABORTEDになったときにPHPの処理をとめるorとめないというのを制御してあげれば
上の関数でキックしたあと、きちんと処理をして終わってくれるというわけです。

で、調べた限りでPHPが最後まで実行してくれるようにするには2パターンありました。

●1個目
PHP側で一切出力処理をしない。
⇒単純にheader()とか echo,print などを削除&バッファ関連の ob_~ も削除する。

●2個目
どうしてもprintなどの処理が必要な場合は
ignore_user_abort(true)を最初にかき、 ob_startにてバッファ処理をさせて、
出力時は ob_flush() などで対応する。

これのどちらかをやれば問題なく動きました。

まあいずれにせよ、キックされた側のPHPの終了を読み取るには register_shutdown_function などを使って
再度こっちにキックしなおさないといけなかったりするので、
基本的には片道切符として使ったほうがいいと思います。

参考文献
ignore_user_abort(false)でPHPが処理を中断しない件
ignore_user_abort=falseなのにスクリプトが止まらない
ignore_user_abort
PHPの接続処理関係

PHPのGDライブラリだけで角丸する

imagick使ったほうが明らかに綺麗&楽にできるんだけど
勉強がてらGDオンリーでやってみた。

結果

やっぱ綺麗に抜けないw

あとimagickだと3行くらいのソースが無駄に長くなるのがね。
実用的ではないです。

まあ一応GDで画像操作するコツみたいなのはわかったので
無駄ではないかな。。。

一応こんなかんじになりました。

//角の大きさ
$cornerRad = 15;

//元画像の読み込み
$originalImage = imageCreateFromJPEG('images/test.png');
//角画像の読み込み
$cornerPng = ImageCreateFromPNG('rounded_corner.png');

//角をリサンプリングするための画像
$cornerResized = imageCreateTrueColor($cornerRad,$cornerRad);
//リサンプリング用の画像(真っ黒)に角画像をコピーしてついでに大きさを調整する($cornerRad)
imageCopyResampled($cornerResized,$cornerPng,0,0,0,0,$cornerRad,$cornerRad,imageSX($cornerPng),imageSY($cornerPng));
//黒を透明にするため黒を定義
$black = imageColorAllocate($cornerResized,0,0,0);
//リサンプル画像の黒を透明にする
imageColorTransparent($cornerResized,$black);

//元画像のデータ取得
$sizeX = imageSX($originalImage);
$sizeY = imageSY($originalImage);

//元データの左上の角を丸める
imageCopyMerge($originalImage,$cornerResized,0,0,0,0,$cornerRad,$cornerRad,100);

//imageRotateで角丸画像を回転させて、元データの右上の角を丸める
$rotated = imageRotate($cornerResized,90,0);
imageCopyMerge($originalImage,$rotated,0,$sizeY - $cornerRad,0,0,$cornerRad,$cornerRad,100);

//imageRotateで角丸画像を回転させて、元データの左下の角を丸める
$rotated = imageRotate($cornerResized,270,0);
imageCopyMerge($originalImage,$rotated,$sizeX - $cornerRad,0,0,0,$cornerRad,$cornerRad,100);

//imageRotateで角丸画像を回転させて、元データの右下の角を丸める
$rotated = imageRotate($cornerResized,180,0);
imageCopyMerge($originalImage,$rotated,$sizeX - $cornerRad,$sizeY - $cornerRad,0,0,$cornerRad,$cornerRad,100);

//画像出力
header("Content-type: image/jpeg");
imagePNG($originalImage);
imageDestroy($originalImage);
imageDestroy($cornerPng);

左上の画像をPNGで作って
こんなやつ

(背景は黒じゃなくて透明でもOK:どっちにしろ黒バックの画像にリサンプルするから)

それを真っ黒な画像にリサンプルして黒をimageColorTransparentする
でそれを90度ずつ回転させながら角に当ててくってかんじです。

Continue Previous page Next page

Twitter