「ECHO」を含む日記 RSS

はてなキーワード: ECHOとは

2012-02-14

そっとうに。

/**
 * そっとうに。
 *
 * そっとうにを置く。
 *
 * @param string $str
 * @return string
 * @see <a href="http://vipsister23.com/archives/5204131.html">とある小学生が書いた詩が哲学的過ぎる件</a>
 */
function sottoUni($str) {
  return 'そっと'    .PHP_EOL
         . $str.'に' .PHP_EOL
         .'うに'     .PHP_EOL;
}

$arr = array('せなか','わたげ','たにま');
foreach($arr as $d) {
  echo sottoUni($d);
}

2011-12-05

ping 結果 - Windows 7場合

自分のサブネット以外は、ルーターによる



・「要求がタイムアウトしました」

MACアドレスは分かっているが、icmp.echo の応答が無い - 自分のサブネット



・「宛先ホストに到達できません」

MACアドレスすらわからない - ただし自分のサブネット



これも、OSバージョン変更で仕様が変わったんだぜ。

XPでは、両方「タイムアウト」だったはずだ。

どこからかわざわざdestination host unreachableを返してきたら話は別だがな。

2011-09-21

FizzBuzz問題php

元ネタ

http://anond.hatelabo.jp/20070508170219

php初めて半年程度でこれ。

もっと上手いやり方があるんだろうなぁ。

$i3=1;
$i5=1;
$flag=0;

for($n=1;$n<101;$n++){
	
  if($i3==3 && $i5==5){
    echo "FizzBuzz¥n";
    $i3=1;
    $i5=1;
  }else{
    if($i3==3){
      echo "Fizz¥n";
      $i3=1;
      $flag=1;
    }else{
      $i3++;
    }
    if($i5==5){
      echo "Buzz¥n";
      $i5=1;
      $flag = 1;
    }else{
      $i5++;
    }
    if($flag==0){
      echo $n."¥n";
    }
      $flag = 0;
    }
}

※一部全角化(&¥<)

2011-04-14

パスワード個人情報を扱うサービスを作る際に気をつけたこと

HTMLはわかるけど、サーバーサイドはお遊びでphpを触ったぐらいだったので、会員制でデータをためこむサイト作りに初めて挑戦した

今回重視したのは、「いか個人情報をお漏らししないようにして、万が一漏らしても被害を少なくするか」ということ。

世の中、有償サービスでもパスワードを平文で保存してるサービスが意外と多いらしいので、流出した時のリスクを少しでも減らせる対策として書きます

今回のシステム構成

サーバーロケットネットキャンペーンにでレンタルサーバ年1000円ポッキリプラン

クライアント側の処理HTML+CSS+jQuery(とプラグインもろもろ)
サーバ側の処理PHP
WebサーバーApache
データベースMySQL

個人情報こわい!

個人情報ビビる漏洩とかまじ困るし怒られるしこわい。

俺も巻き込まれたところでは、サミータウンがメールアドレスパスワードセットでお漏らししてお詫びに1ヶ月無料なにそれこわい

サミータウンだけならまだいいけど、メアドパスワードを他のサービスで共通化して使ってる情弱なので、

共通化してメアドパスワードをどこかのサービスが一箇所でも漏らすと、ヤフオクID乗っ取り事件みたいなことになる。

http://internet.watch.impress.co.jp/cda/news/2008/09/26/20967.html

だってできれば人様のメールアドレスパスワードとか預かりたくない。

万が一、肉親のメールドレス発見してパスワードにrapemeとか入ってたら明日からどういう顔すればいいかからない。

ググってみてもどこにも情報のってない。うーん困った。ダメもとで「個人情報ってどうやって保存したらいいんだろう。。。」

って、twitterでつぶやいたら、「住所とかは可逆暗号化でいいけど、パスワードハッシュで不可逆化しないとだめだよ!」

と、呪文のようなありがたい言葉を教えてもらった。

暗号化の種類

「住所とかは可逆暗号化でいいけど、パスワードハッシュで不可逆化しないとだめだよ!」

何のことかわからなったので、調べてみると、

・可逆暗号=元のデータに戻せる暗号化方式。

ハッシュハッシュ値を使った、元のデータに戻せない暗号化方式

うーん。。。よくわからん。。。

電話番号とか住所は、第三者が使用する情報なので、可逆が必要。パスワードは、認証しか使わないので、

ハッシュ値結果が一致すれば元のデータがわからなくてもOK、という方式なのでこういった暗号の使い分けをする。

●可逆暗号イメージ(もとにもどせる) 暗号キー開発者が指定する。
090-xxxx-xxxx →(暗号化)→ !'&%($% →(復号化)→ 090-xxxx-xxxxハッシュイメージ(もとにもどせない) 
登録passwordDBに保存)→(ハッシュ値抽出)→!"$#'$#="
ログインpassword →(ハッシュ値抽出)→!"$#'$#="
※二つのハッシュ値が合っていれば、パスワード一致として認証する。

暗号化の実現方法

可逆暗号電話番号とか住所とかに適用

今回はMySQL関数で実現した。encode関数暗号化して、decode関数でもとに戻す。

例えばtel_noという項目だけあるテーブルがあるとすると、

//データベースに保存する時
insert into テーブル名 (tel_no)  values (encode(tel_no,'暗号キー'));
//データベースから取得する時
select decode(tel_no,'暗号キー') from テーブル名;

これで、データベース格納時は暗号化(バイナリ化)されて、データベースから取り出してHTML表示する時に復号化はされる。

ハッシュパスワードかに適用

今回はphpのhash関数で実現した

ユーザ登録時>

$password=(フォームから取得)
$hash=hash('sha512',$password)
//ユーザ登録時は、ここで生成した$hashをデータベースにぶっこむ。

ユーザ認証時は、入力されたパスワードと、データベースパスワードが一致するかチェック。

ログイン認証時>

//フォームから入力されたパスワード
$input_password=(フォームから取得)
$input_hash=hash('sha512',$input_password);

//MySQLに保存されたパスワードを取得(略)
$db_hash==(データベースから取得)

//判定
if($input_hash==$db_hash)
	echo 'ログインしますよ!';
	//ここにログイン処理を書く
else
	die('メアドパスワードがあってないよ!');

これでもしSQLインジェクションとかでデータ流出しても、ハッシュ暗号パスワードに関してはまず解析されないはず。。。

可逆暗号データphp側の暗号キーが盗まれない限りバレない。。。はず。。。

暗号化する対象のデータをえらぶ

何でもかんでも暗号化するとコードが煩雑になるし、パフォーマンスにも影響でそうなので、

住所データ都道府県とか、漏れても良いような情報暗号しませんでした!!

本人が特定できなければ個人情報はないらしいので。。。

個人情報保護法
2条による定義個人情報」とは、生存する個人に関する情報であって、当該情報に含まれる氏名、生年月日その他の記述等により特定の個人を識別することができるもの(他の情報と容易に照合することができ、それにより特定の個人を識別することができることとなるものを含む。)をいう。

http://ja.wikisource.org/wiki/%E5%80%8B%E4%BA%BA%E6%83%85%E5%A0%B1%E3%81%AE%E4%BF%9D%E8%AD%B7%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E6%B3%95%E5%BE%8B#2

これで、もし漏れても、俺、ウンコ漏らして臭いけど、パンツから出てないからいいよね?というレベルはなった。はず。

お漏らさないようにキツくする

万が一漏れても大丈夫!と書いたけど、そもそも漏らすなというお話になる。色々調べた結果、以下の対策をほどこした

SQLインジェクション対策

・当初jQuery側でSQL組み立ててPHPに渡してたので、これだと任意のSQLが実行できて漏らし放題なのでやめる。

GETとかPOSTでDBに渡すパラメータを扱ってる場合、ちゃんとエスケープする。

例えばログイン認証するPHPで、GETメソッドでフォームからデータを取得するような場合

$id=$_GET['id']
$pwd=$_GET['pwd']
$sql="select * from ユーザーテーブル where uid='$id' and pwd='$pwd'

とかやってると、login.php?id=admin'&pwd=' OR '1'='1とかパラメータを渡されるとあら不思議

select *from ユーザテーブル where uid='root' and pwd='' or 1=1

で、誰でもログイン出来ちゃう!ので、mysql_real_escape_stringでエスケープしたり、渡されたパラメータが想定した値かどうか(例えば数値かどうか、とか)のチェックをいれたりする。

クロスサイトスクリプティング

・保存するデータタグJavascriptを埋め込まれないように、保存されたデータを出力する場合PHP側でhtmlspecialchars関数使ってエスケープするようにする。


こんな感じでお漏らし対策をした。間違いがあったら教えて欲しい

ちなみに出来上がったサイトはこれ。

http://oreni-makasero.com/

2011-03-30

http://anond.hatelabo.jp/20110330125201

というわけでサンプルコード書きなおしてみた。

サンプルコード意味はないので注意な。

JAVA

public class Main {

    public static void main(String[] args) {
        int count= args.length==0?100000:Integer.parseInt(args[0]);

        long start=System.currentTimeMillis();
        Main m=new Main();

        double result=0;
        for(int i=0;i<count;i++){
            result+=m.test((double)(0.1f*i));
        }
        System.out.println(result);
        System.out.println(String.format("COMPLETE! %d msec",System.currentTimeMillis()-start));
    }

    private double product=0;
    public double test(double rad){

        return this.product+=Math.tan(rad);
    }
}

PHP

<?php
class Test{
    private $product;
    public function test($rad)
    {
        return $this->product+=tan($rad);
        
    }
}

$count =is_null($argv[1])?100000:(int)$argv[1];
$start=microtime(true);

$t=new Test();
$result=0;
for($i=0;$i<$count;$i++){
    $result+=$t->test(0.1*$i);
}
echo "{$result}\n";
printf("COMPLETE! %f msec",  (microtime(true)-$start)*1000);

結果

JAVA

$java -jar test.jar 100000
-7.524990063072938E9
COMPLETE! 31 msec

PHP

$ php -f test.php 100000
-11900078829.3
COMPLETE! 209.314108 msec

うむ。有意な差はあるっぽいな。(結果が違い過ぎてるのはなんか問題があるかもしれん)

多分、変数の型が出鱈目で計算されるようなもんだとPHPは遅くなるのだと思われ。javaは強い型制約があるから、同じ型同士の計算だと速いとか?

http://anond.hatelabo.jp/20110330114912

サンプルコード

JAVA

package test;

public class Main {

    public static void main(String[] args) {
        int count= args[0]==null?10000:Integer.parseInt(args[0]);

        long start=System.currentTimeMillis();
        Main m=new Main();
        for(int i=0;i<count;i++){
            System.out.println(m.test());
        }
        
        System.out.println(String.format("COMPLETE! %d msec",System.currentTimeMillis()-start));
    }


    public String test(){


        return "ぽぽぽぽーん";
    }
}

PHP

<?php
class Test{
    public function test(){

        return "ぽぽぽぽーん";
    }
}

$count =is_null($argv[1])?10000:(int)$argv[1];
$start=microtime(true);

$t=new Test();
for($i=0;$i<$count;$i++){
    echo $t->test()."\n";
}

printf("COMPLETE! %f msec",  (microtime(true)-$start)*1000);

結果

$ java -jar test.jar 10000

ぽぽぽ...

COMPLETE! 1008 msec

$ php -f test.php 10000

ぽぽぽ...

COMPLETE! 988.869190 msec

実行したのは全く同じ環境jdkは1.6でPHPは5.2。

どういうことなのか説明してもらおうか?

2011-03-20

より良いPHPerにならないための20Tips

http://1-byte.jp/2011/03/20/20_tips_you_need_to_learn_to_become_a_better_php_programmer/

良いPHPerだって?そんなものは丸めゴミ箱にでも捨ててしまった方が資源の再利用になる分いくらかマシだ。

つまり俺たちがしなくちゃならないことは「より良いPHPerにならないため」に何ができるかってことなのさ。

それじゃ、始めよう。

1. ?>を使うな

?>なんて使っちゃいけない。そう俺たちはBAD PHPer。

無駄ホワイトスペースの出力に悩まされるくらいなら対称性なんて丸めゴミ箱にでも捨てた方がまだマシだ。非対称性こそが賛美。

2. 設定ファイルPHPで書くな

require_once("config.php");

未だにこんなことやってるやつがいるのかいベイベー。絶対にダメだ。この一行を見たら俺は悶絶する。

ダメだ、早く何とかしないと。

大抵このconfig.phpの中身はこうなっている。見て絶望だ。

$hoge_path = '';
if (!LOCAL) {
    define('FOO_FLAG', 1);
    if (HONBAN) {
        define('HOGE_FLAG', 1);
    }
    else if (TEST) {
        define('HOGE_FLAG', 2);
    }
}
else {
    $hoge_path = '/local';
    define('FOO_FLAG', 2);
    define('HOGE_FLAG', 3);
}

define('HOGE_URL', $hoge_path.'/hoge/');

こういうのが延々と続くわけだ。もういやだ。もう見たくない。

本番環境テスト環境でどういう値の違いがあるのか、ローカル環境だとどうなるのか、まったく把握できる気がしない。

なまじPHPな設定ファイルのせいで処理をついつい書いてしまう。そしてどんどん複雑になってしまう。

やはり設定データは基本的にYAML等のデータしか定義できない形式のもので用意すべきだ。そして環境ごとに設定ファイルを分けるべきである

そうすることで何にどういう違いがあるのかすぐにわかるし、diffすれば一度にすべて把握することができる。

# 本番環境設定ファイル
foo_flag: 1
hoge_flag: 1
hoge_url: '/hoge/'
# テスト環境設定ファイル
foo_flag: 1
hoge_flag: 2
hoge_url: '/hoge/'
# ローカル環境設定ファイル
foo_flag: 2
hoge_flag: 3
hoge_url: '/local/hoge/'

3. コメントを信用するな

そう、あなたはこんな状況に遭遇したことがあるんじゃ?

// ここで後の処理のためにhogeメソッドを呼び出しておく
$q->foo();

// $a['foo']はここに来る時点で真のはず
// 2010-03-10 判定がおかしいので修正
// 2010-06-21 やっぱり値が入ってる方が正しい
if ( !isset($hoge[0]) ) {
}

コメント保守されない。そう、それは真実。こんなコメント発見したら即効削除しよう。コメントは基本信じるな。

俺たちにちょっとしたヒントと大きな損害を与えてくれる、それがコメントの役割なのだ。

4. タブとうまく付き合うしかない

わかる。いいたいはとてもわかる。俺たちはしばしばインデントにスペースを使うはずだ。一方でIDEのしっかりした言語ではタブも使うことがある。しかし悪いことに、両者を混同しているプログラマも一定数いるのだ。

タブを画面上で認識しにくいエディタが世の中には存在する(何とは言わないが)

そして画面上で認識しにくいことを理由にタブを気にしないプログラマがいる。

この二つの条件が重なると、タブとスペースの交じり合ったインデントが完成する。もうぐちゃぐちゃだ。これは永遠に続く戦いだ。

私たちが勝利を掴むためにできることなどせいぜい、常にスペースしか使わない。タブを見つけたらその都度スペースに変換する。そういった地道な活動が明日へとつながるのだ。

5. 変数名に時間をかけるな

われわれがプログラムをするとき、何に一番時間がかかってるか。実は変数の命名なのである。ここで拘り過ぎて時間をかけ過ぎては何も進まない。

御託はイイからさっさと書け、だ。しかしとはいっても変数名は重要。日頃からどういうときにどんな名前を使うかを決めておくといい。

そして変数名に型はまったく必要ない。型宣言のないPHPにおいて、型の変数名をつけること自体ナンセンスだ。

コンパイラ様に保証されてない状態での

$iNumber = 'aaa';

になんの意味もない。コメントを信じるなでも言ったが、これはプログラマを混乱させるだけの害悪なものだ。

6. 変数初期化場所

変数を使う前に初期化するのは、警告を出さないという意味でも良い癖だ。しかし具体的にどこでやるかが問題だ。

$foo = null;
$foo = $q->foo();

こんな初期化意味はない。よくあるのはやはり、if文で値を振り分けるケースだろう

$foo = null;
if ( $hoge ) {
    $foo = 1;
}
else if ( $bar ) {
    $foo = 2;
}

このとき初期化はとても有効だ。もしnullの初期化を忘れたまま$fooを使うと警告が出るが、ちゃんと初期化してるので出ない。基本中の基本だ。

7. 不正なら常に死ね

function getStatus() {
    $bReturn = false;
    if ($i == 2) $bReturn = true;
    return $bReturn;
}

(中略)

もし、何かしらの理由で、あなたの書いたif文が間違っていたら?

この書き方をしていれば、間違った値に対して、常にfalseが返る。

私たちが、PHPでsensitiveなデータを取り扱うなら、正しいデータ入力されるまでは、動かないコードを書くべきだ。

trueとfalseの条件がいまいち明確ではないが、本当に動かないコードを書けというのであれば以下のようにすべきだ

function getStatus() {
    $bReturn = false;
    if ($i == 2) $bReturn = true;
    else if ($i == 1) $bReturn = false;
    else throw new Exception("bad status! $i");
    return $bReturn;
}

中途半端にfalseを返して生存させる必要性はまったくない。今すぐ死ね

8. 連想配列キーアクセスする場合

単なる配列に対して数値をクオートで囲う必要はない。

連想配列キーを指定する場合だけ定数と間違わないようにクオートで囲まなければならない。そして逆に定数を使いたい場合はクオートで囲ってはいけない。

更に後世のプログラマ処理を見たときに、定数が使いたかったのか、文字列が使いたかったのかを明確にした場合はconstantを使うと良い。

// 定数のFOOを使うよということが明確になる
print $a[constant('FOO')];

9. echoよりもprintfを使え

もし、文字列変数の値と一緒に出力するときPHPではコンマの代わりにprintfを使うことが使える。

なぜ?コンマを使うよりも可読性がグッとあがるから

printf( “Hello, my name is %s“, $sName);

以下の代わりに上記のコードを使う。

echoHello, my name is “, $sName;

出力すべき変数が増えれば増えるほど、有効になっていく。とにかく迷ったならば、printfを使え、だ。

10. 三項演算子は一回まで

三項演算子はとても有効だ。しか優先順位に難があるせいで三項演算子ネストしようとすると以下のようなコードになってしま

$n = (($i == 1) ? 2 : (($i == 2) ? 3 :$i));

括弧だらけで読みにくいったらありゃしない。三項演算子を使うなら一回まで。約束守れないやつは丸めゴミ箱にでも捨てちまえ。

11. 真偽値のチェックは生でいけ

if ( $flag ) {
}

仕様をちゃんと把握しているなら真偽値のチェックなどこれで十分。

もし事前にbool型だというのが確定してるのなら「$flag === true」を使えばいい。

12. ++と--の演算子を見極めろ

インクリメント、デクリメント演算子は前に付くか後ろに付くかで意味が変わるので慣れるまでは非常にややこしい

けがからなくなるくらいなら初めから使わないほうが良い。見極められないなら使うな。それがPHPerなのだ。

13. 代入演算子を使え

文句なしだ。これは文句がない。

他にも色々あるので覚えておこう

$a %=  1;
$a &=  1;
$a |=  1;
$a ^=  1;
$a <<= 1;
$a >>= 1;

14. 変数dump関数はより便利に

てっとり早く画面に表示する際にpreはよく使うが、デザインの関係上画面の文字が見えないときがある。

なのでdivを使って以下のようにしとくと便利だろう。

function p($var) {
    echo "<div align='left' style='background-color:white;color:black;'><pre>";
    print_r($var);
    echo "</pre></div>";
}

15. 定数から手を洗え

君らが通常作るアプリケーションなんぞに、定数なんぞ必要ない。いいか、もう一度言う、お前ら程度のもんが、定数使おう何ぞ、おこがましいわ!

大丈夫。なんでもかんでも定数にする必要はない。結局設定ファイルに定数をずらずら作りまくってわけがからなくなってるパターンが多い。

貴様たいなもんに、定数は制御できん。いいか設定ファイルYAML等のデータで持つようにし、その連想配列データ構造を一つ持ってるだけで定数の変わりになる。

このメリットに比べれば、定数だと書き換えられなくて良いという利点などこの歯のカスほどのものだ。そんなものは丸めゴミ箱へ捨ててしまうといい。

認識を改めろ。俺たちはより良いPHPerにならないために努力している。

16. $_GETと$_POSTを生で使うな

できれば何かしら簡単なクラスでもいいのでラップしろ。

class Request {
    private $parameters;
    private $method;
    function __construct () {
        $this->method = $_SERVER['REQUEST_METHOD'];
        if ( strtoupper($this->method) === 'POST' ) {
            $this->parameters = $_POST;
        }
        else {
            $this->parameters = $_GET;
        }
    }
    function param ($key) {
        return isset($this->parameters[$key]) ? $this->parameters[$key] : null;
    }
}

これだけでもいい。たったこれだけでもとても便利だ。ここから拡張してGETやPOSTを明示的に取るメソッドとかも作ってみるといい。自分の手を動かすのだ!

17. 関数だのオブジェクトだのの問題ではな

例が良くない。こんなのは引数20個ある関数からset20回呼ぶオブジェクトに変わっただけではないか

そもそもこの20個の引数はなんなのか。何かのデータ構造なんであれば連想配列にして引数一つとして渡すべきだし、それぞれまったく異なる用途の変数なのであればWindowsプログラミングじゃあるまいし20個も引数取る時点設計が間違えている。

何がいいたいか。別に関数でもオブジェクトでもどっちでもいいということだ。

そんなことで悩んでる暇があったら設計を見直せ。

18. メソッドチェインを愛用せよ

スキあらば自分自身を返せ。スキあらばオブジェクトを返せ。配列はArrayObjectのARRAY_AS_PROPSで返せ。

ひたすらメソッドチェイン。来る日も来る日もメソッドチェイン。とにかくメソッドチェインを使い続けろ。そこに未来はある。

19. コードの汎用化は慎重に

どんなコードも繰り返すな。もし、少しでも同じコードを書いていたなら、それは関数に置き換えてしまえ。

・・・と、いうのはやめなさい。

一見同じように見えた処理でも前後の流れでまったく違うものということが往々にしてある。

まとめ方にも問題があるケースもある。何でもかんでも関数化すると、関数が膨大に増えていく。君は見たことがあるだろうか。common.phpやfunction.phpの恐ろしさを。

かに細かく関数化はされているが、適切に関数化していないのである。結合度が非常に高い。なんでもかんでも盲目的にまとめれば良いという話ではないのだ!

20. 結合度は適切に減らし、適切に結合せよ

あまりに極度に意識しすぎると、プログラムそのものができなくなる。そういう状態に陥る。

気を抜いて。そう気を抜いて。所詮あなたコードなんてすぐに消えてなくなるよ。きっともっと偉い人が作り直すよ。だからまずは思うが侭にやるといい。

結合度を減らすというのは非常に難しい何度何度も失敗し続けて、ようやくここは分けた方が良かったんだなと気付く。次に活かそうと心に決める。そしてまた同じ過ちを繰り返していくわけだ。

まずは実装することだ。これが一番の早道だ。まずはがっつり結合した関数をあえて作るといい。何も考えずに作ろう。

そしてその後に、一部分使いましたいとおもうことがあるはずだ。その時に関数に切り出そう。それを繰り返すといい。そのうち初めから分けた方が良いと気付く。

何事も経験が必要である経験を積まないプログラマ丸めゴミ箱に捨ててしまえ。

さて、先の例で言うならば、私ならadd_result_outputという関数を作ってしまうだろう。だってaddとresultを連続して呼ぶのはめんどくさいんだもん。一連の流れをいつも使うのなら、その流れをやってくれる関数を作ればいいじゃないか

function add_result_output ($iVar, $iVar2) {
    $r = add($iVar, $iVar2);
    echo result($r);
}

もっと言えばクラス化してしまってもいいかもしれない。どんな感じになるかは君の手を動かして確認しよう!


最後

このTipsはとてもわかりにくく、ニッチ過ぎる部分も多いかもしれない。

しかしもう一度タイトルを確認してほしい

あくまでも「より良いPHPerにならないための20Tips」なのだ。

君はこの記事を鵜呑みにしてはならない。PHPPHPと見抜けないPHPerはPHPを使うのは難しい


おまけ

もし、あなたPHPプログラマなら、公式のPHPドキュメントあなたのケツの穴を拭くための紙になるだろう。

私は、それぞれのセクションを眺めて、各関数でどんなことが出来るかなんぞ、歯クソのゴミ程に役に立たないとおもっている。動けばいい。はは。

あなたは、PHPで用意された既製関数で多くのことが実現できることに、(俺の仕事を減らすなと)驚くはずだ。

この記事があなたの役に立たない事を。

どんなコメントでも待ってます

ふざけんな!


個人的な感想

この記事に書かれている内容は、丸めゴミ箱に捨てた方が良いレベルです

もしここまで読んでしまったら、丸めゴミ箱に捨てましょう。



プログラ増田のあなぐら

2010-10-12

トラックバックが怖くて見られない

echo "0.0.0.0 anond.hatelabo.jp" &gt;hosts

2009-12-25

[]create_functionで生成された匿名関数の一覧を得る関数

ひーほー。いやぁさてさて一体このコード中に何度create_functionで匿名関数が生成されたのかふと気になったあなたのためにこんな関数作ってみたよ!



function get_lambda_functions () {
    $i     = 1;
    $funcs = array();
    while(function_exists("\0lambda_$i")){
        $funcs []= "\0lambda_$i";
        $i++;
    }
    return $funcs;
}

$a = create_function('','echo 100;');
$a = create_function('','echo 200;');
$a = create_function('','echo 300;');

print_r(get_lambda_functions());
Array
(
    [0] =>  lambda_1
    [1] =>  lambda_2
    [2] =>  lambda_3
)


ね。凄いでしょ。あとはforeachとかで存在する全ての匿名関数を実行したりすると面白いかもネ!




foreach ( get_lambda_functions() as $lambda ) {
    $lambda();
}


何が起こるかは自己責任だよ!!!!!!



プログラ増田のあなぐら

2009-08-25

http://anond.hatelabo.jp/20090825153433

ハロワ?プログラミング初心者の最初の一歩ってところだな。

Cなら

include <stdio.h&gt;

void main(){

puts("hello.world!");

}

で、javaなら

static void main(Strng[] args){

System.out.println("hello.world!");

}

で、PHPなら

echo 'hello.world!';

だ。

SQLだと

SELECT 'HELLO.WORLD!'

だな。

ほかの言語は他の増田たちに任せる。

2009-06-21

PHP「$a="0x0A";++$aは11ですがよろしいですか」

ぼく「えっ」

PHP「$a="0x0A";++$aは11になりますが」

ぼく「いえ"0x0B"です」

PHP「えっ」

ぼく「えっ」

PHP「まだインクリメントしたことがないということでしょうか」

ぼく「えっ」

PHP「えっ」

ぼく「変化するってことですか」

PHP「なにがですか」

ぼく「型が」

PHP「ああ文字列でも整数っぽい文字列なら自動で型変換されますよ」

ぼく「そうなんだすごい」

PHP「ではインクリメントいたしましょうか11ですよ」

ぼく「でも"0x0A"は明示的にキャストしたら0になりますよね」

PHP「えっ」

ぼく「えっ」

PHP「ああ16進数のことなら10進数自動で変換してから演算するんですよ」

ぼく「なにそれこわい

PHP「for($i="0w9Z";$i<12;$i++){echo $i;}と書くと $i="0w9Z", "0x0A", 11と変化します」

ぼく「なにそれきもちわるい」

PHP「えっ」

ぼく「えっ」

http://d.hatena.ne.jp/fbis/20090618/1245297557

2009-06-09

この上なく簡易なアラームが欲しい

諸氏は、下記のような事をどうしているのだろうか。

時間がきたら、メッセージボックスを出すだけで良い

・ただし、時刻の登録にマウスを操作するような煩雑さは、断じて許容できない

・常駐すんなボケ

とりあえず、if文なんて高尚なものを使ったことなかったけど、バッチファイルでやってみた。

@echo off
REM 1-31の日付でしか登録できない低能アラーム
REM 時刻は必ず入力されるものとみなす
REM よって、組み合わせはDAY×MESGのみで考える。

REM 変数初期化
SET yotei_day = 0
SET yotei_mesg = ""

SET /P yotei_time="アラームを表示する時刻 :"
SET /P yotei_day="アラームを表示する日付(1-31で指定、省略した場合は今日) :"
SET /P yotei_mesg="表示するメッセージ(省略時は、予定チェック) :"

REM 条件分岐。バッチのelseはしょぼすぎる。複数条件指定できない??
if "%yotei_day%" == "0" goto :NO_DAY
if "%yotei_mesg%" == "" goto :NO_MESG

REM 指定したもの -> DAY,MESG
echo %yotei_day%日の%yotei_time%に通知します'
at %yotei_time% /NEXT:%yotei_day% net send pc_Name "%yotei_mesg%"
goto :SLEEP


:NO_DAY
REM 分岐: + NO_MESG
if "%yotei_mesg%" == "" goto :NO_MESG_NO_MESG
REM 指定したもの -> MESG
echo 次の%yotei_time%'に通知します'
at %yotei_time% net send pc_Name "%yotei_mesg%"
goto :SLEEP


:NO_MESG
REM 分岐: + NO_DAY
if "%yotei_day%" == "0" goto :NO_DAY_NO_MESG
REM 指定したもの -> DAY
echo %yotei_day%日の%yotei_time%に通知します'
at %yotei_time% /NEXT:%yotei_day% net send pc_Name "予定チェック"
goto :SLEEP


:NO_DAY_NO_MESG
REM 指定したもの -> なし(時刻のみ)
echo %yotei_day%日の%yotei_time%に通知します'
at %yotei_time% net send pc_Name "予定チェック"
goto :SLEEP

REM 終了
:SLEEP
ping 127.0.0.1 -n 2 > nul:

これに適当名前をつけて、ランチャのfenrirで起動させる。

キーボードのみの操作で済むので、とても快適ではあるものの、見ての通りnet sendを使うため、

Windows messenger serviceを起動させるという、常駐ソフトの方がマシな本末転倒なウンコーな一品である。

ActiveDirectoryとかグループポリシーでmessenger制限されてたら使えないし。

VBWSHなら色々できそうだけど、これ以上機能はいらんのよね。いっそ、メッセージはtxtに書き込んで、それを開くだけにするか・・・・。

### しかし「>」を表示させるのに、数値参照文字じゃないとダメとか・・・。

### &#62;を半角にしたら>になりますよっと。。。

2009-05-31

http://anond.hatelabo.jp/20090531015507

バッチファイルで良いじゃん?

例えばだが、タスクスケジューラーにはバッチファイルを日に一度くらいスケジュールしておいて

スタートアップにも登録しておく

で、echoあたりでバッチファイルからログ吐かして

ログの日時を調べて適当定義する同一週じゃないログなら実行っていう風にすればいい

2008-10-20

Re:Re:Re:Re:Re:Re:Re:エガミくんの脆弱性のやつ

http://anond.hatelabo.jp/20081020054933

id:hiroyukiegamiだよ!

id:Hamachiya先生から2つの課題を貰ったよ!

1つめ!!

1つは、タグエスケープしわすれている箇所がある点

↑これは勉強になる!実際にやってみます!

変更前

//変更前	      echo $server_id."/".$id."_".$secret."_s.jpg' border=0 title=$title alt=$title />";
    	      echo $server_id."/".$id."_".$secret."_s.jpg' border=0 title=nl2br(htmlspecialchars($title, ENT_QUOTES)) alt=nl2br(htmlspecialchars($title, ENT_QUOTES)) />"; //変更後

2つめ!!

もう1つが、html属性値(alt=ナントカとか)をクオートでくくってない点

↑これは勉強になる!実際にやってみます!

変更前

//変更前	      echo $server_id."/".$id."_".$secret."_s.jpg' border=0 title=$title alt=$title />";

                      $title = nl2br(htmlspecialchars($title, ENT_QUOTES));  
      		      echo $server_id."/".$id."_".$secret."_s.jpg' border=0 title='\"$title\"' alt='\"$title\"' />"; //変更後

このソースがの中で書かれてるのでちゃんち「"」の前の「\」をつけて「\"」って言うのが忘れかけてて危なかったです!(えへ)

おお!!!!!!!!!!!!!!

完璧やないかーい!

http://flickr2.in/fli.html?data=%3Cscript%3Ejavascript%3Aalert(%27xss%27)%3B%3C%2Fscript%3E

ちゃんとソース

<a href='http://farm4.static.flickr.com/3022/2930297659_dc20386697.jpg' rel=lightbox><img src='http://farm4.static.flickr.com/3022/2930297659_dc20386697_s.jpg' border=0 title='"XSS session 1"' alt='"XSS session 1"' /></a>

とうまく表示されてます!

本当に有難う御座います!!

今回凄く勉強になった!でも、、、結局皆が言ってたXSS脆弱性って・・・

簡単に言うと

$hensuu と言う魔法みたいなワードを

nl2br(htmlspecialchars($hensuu, ENT_QUOTES)) と出力のところで囲んであげて

"nl2br(htmlspecialchars($hensuu, ENT_QUOTES))" 更に"とかで囲んであげる

簡単に言うと、この数十個の文字で変数で囲んということだったのですか??

この数文字の魔法を教えてもらってたらすぐ実践してたんですか・・・。

でも、もしかしたら実はもっとXSS脆弱性って色々深い事があるんですかね!?

なんかXSS脆弱性に興味が沸いてきました!!

先生!教えて下さい!ヘルプミー!

追伸

それだけエガミくんの生み出すものが注目されているってことだよ。

目立つとどうしても悪い人も寄ってきちゃうから困るよね。

なるほど!!!こういってもらえると、凄く嬉しいです!!!

でも、なんかサービスをいっぱい作っても、こうやって

XSS脆弱性しか意見貰えないって寂しいですよね・・・。

あっ、でもこれってそれだけXSS脆弱性って大事って事なんですか??

http://anond.hatelabo.jp/20081020053019

はいこんにちは! Hamachiya2だよ。

alertでなくなったね。こんな短時間ですごい。
エガミくん飲み込みはやい感じだね…。

ええと、あとは、下の方の画像で、どうもマーキータグ(marquee)が埋め込まれてるみたいってことだよね。
うん。もう一回、htmlソースを表示ってして確認してみたよ。
こんなのが埋め込まれてた。

<img src='http://farm4.static.flickr.com/3120/2784053843_b7a7d07c9a_s.jpg' border=0 title=<marquee>test XSS</marquee> alt=<marquee>test XSS</marquee> />

これは問題点が二つあってね、
1つは、タグエスケープしわすれている箇所がある点
もう1つが、html属性値(alt=ナントカとか)をクオートでくくってない点

この二つを直していこうか!

phpプログラムの中のどこかで、<img>タグを出そうとしている部分があるはずだよ。
まずはそれを探そう。

そしたらきっと、その部分は、imgにphp変数を色々埋め込んで出そうとしているはず。
たとえばこんな風に。

echo "<img src='xxxxxx" . $hensuu1 "' title=" . $hensuu2 . " />";

これの$hennsuuも全てhtmlspecialchars()してあげる感じかな。

echo "<img src='xxxxxx" . htmlspecialchars($hensuu1, ENT_QUOTES) "' title=" . htmlspecialchars($hensuu2, ENT_QUOTES) . " />";

こうだね。

そうすればmarqueeタグが埋め込まれていても、

<img src="xxxxxxxx" title=&lt;marquee&gt;test xss&lt;/marquee&gt; />

こんな風にmarqueeとかがタグじゃなくなるので防げる。
でも完全じゃないんだこれ。
さっきも言った、属性値のクオートが足りてないから、ちょっと工夫すればxssやられちゃう。
詳細は長くなるので今は省くけど。

だから上の対処に加えて、titleとかaltとかの中身が、htmlでみた時に、ダブルクオートかシングルクオートで
くくられているようにしてやれば、いい感じになるよ!

<img src="xxxxx" title=ぺろぺろ alt=ぺろぺろ />

こうじゃなくて

<img src="xxxxx" title="ぺろぺろ" alt="ぺろぺろ" />

こうなるようにしよう。


(追記)

ちなみに、何で悪い大人の人はXSS脆弱性を突いてきて悪い事をするんですかー??

それだけエガミくんの生み出すものが注目されているってことだよ。
目立つとどうしても悪い人も寄ってきちゃうから困るよね。

Re:Re:Re:Re:Re:エガミくんの脆弱性のやつ

http://anond.hatelabo.jp/20081020051835

id:hiroyukiegamiだよ!

id:Hamachiya先生から

ブラウザから「htmlソースを表示」ってしてみてくれるかな。

アドバイスを貰って

http://flickr2.in/fli.html?data=%3Cscript%3Ejavascript%3Aalert(%27xss%27)%3B%3C%2Fscript%3E

ソースを見てみたよ!

あっ!!!ここが悪の根源なんだ!
	<title>
		htmlspecialchars(<script>javascript:alert('xss');</script>, ENT_QUOTES)の画像一覧 - flickr2.in
	</title>

あ・・・!さっきのhtmlspecialcharsがうまくいってなかったんだ・・・!

なるほど、じゃぁ今後は絶対

エラーが出ている → エラーの出ているページのソースで何処が問題が確認

と言う事を心がけます!

勉強になるなぁ・・・。

実際に問題の箇所を全部直してみる!
	<title>
		<?php
			$query = $_GET["data"];
			echo nl2br(htmlspecialchars($query, ENT_QUOTES));
			echo "の画像一覧";
		?> - flickr2.in
	</title>

↑のように何箇所が出力箇所があって、全部しらみつぶしに直してみたよ!

一箇所だけ直してて、他は・・・となってたんだけど先生に教えてもらった方法を使ったら

凄く簡単に問題点が分かって凄く早く問題解決できた!

結果!

http://flickr2.in/fli.html?data=%3Cscript%3Ejavascript%3Aalert(%27xss%27)%3B%3C%2Fscript%3E

わーいわーい!!!!

先生アラートが消えたよー!

id:zapa氏の呪いが消えたー!!!!

あっ・・・!でも・・・!

<img src='http://farm4.static.flickr.com/3135/2896115083_333bcb8862_s.jpg' border=0 title=test pilot of a show alt=test pilot of a show />

の箇所が治ってない!!!

え・・・!?コレはどういう事!?

先生ヘルプミー!!!

追伸

なるほどーーー!!!徹夜ですかー!

さすが先生!!!参考になりやす!

ちなみに、何で悪い大人の人はXSS脆弱性を突いてきて悪い事をするんですかー??

凄く、僕は寂しいです。

Re:Re:Re:エガミくんの脆弱性のやつ

http://anond.hatelabo.jp/20081020045037

早速お返事有難う御座います!id:hiroyukiegamiです!

id:Hamachiya2先生からのまとめ

なるほど!前回

$Hamachiya2 = htmlspecialchars($_GET["data"], ENT_QUOTES); //←ここを追加

$params = array('api_key' => 'フリッカーAPIキー',

'method' => 'flickr.photos.search',

'text' => $Hamachiya2,

と$_GET のところ(入力)で何かしようとしてたけど

レスポンスのコーナーのところ、html変数埋め込んで echo してるとこ。”

が大事なんですね!勉強になります!

先生からの説明で

その際に注意すべきは、html属性内(alt=ナントカとか、src=ナントカとか)に変数を埋め込んでいる場合は、ちゃんとクオートの類もエスケープする感じ?

とあって、うーんどういう意味だろうとグーグル先生に聞いてみたよ!

クオート(正確にはクォーロみたいですね!) ・・・ クォートとは、文字が通常有する特別な意味を奪うことである。

つまり”とか’の事ですね!勉強になります。

実際にやってみよー

今回echoで実際に書き出している部分は

$query = $_GET["data"];

echo "$query";

でした!

じゃぁ、ここをこうすればいいのかな??

$query = $_GET["data"];

echo nl2br(htmlspecialchars($query, ENT_QUOTES));

今回はXSS対策の定番『nl2br』を追加してみたよ!

PHP: nl2br - Manual

http://php.benscom.com/manual/ja/function.nl2br.php

nl2br ・・・ nl2br()関数は、改行文字(\n、\r、\n\rなど)を
タグに置き換えます。

$str = nl2br("STUDIO WINGでは\nPHP開発を行っています。");

print $str;

※上記の結果、「STUDIO WINGでは
PHP開発を行っています。」を出力します。

どうなったかな?

うーん、、、ではid:zapa氏の荒らしURLをみてみよう・・・。

http://flickr2.in/fli.html?data=%3Cscript%3Ejavascript%3Aalert(%27xss%27)%3B%3C%2Fscript%3E

id:Hamachiya2先生!全然解決されないよ(涙)

今回nl2brタグで改行を回避したけど・・・これじゃダメみたいですね・・・!

あれ・・・荒らしソースを見てみると・・・

<script>javascript%3Aalert('xss')%3B<%2Fscript>

・・・!!!

先生!僕は大きな間違いをしていたようです!

htmlspecialcharsとかnl2brタグも大事だけど、、、これじゃ解決できないみたい!!!!

これって、どうしたらいいんですか!?ヘルプミー!!!

追伸

最近朝型生活になってきました。

なんとか直さないと・・・。

どうにか解決方法はありますかね??

http://anond.hatelabo.jp/20081020041605

はい! こんにちは! Hamachiya2ですよ!
いま、エガミくんの書き込みみながら、ざくっとソースみてみたよー。

XSSの対策ってね、ぼくもよくわかってないけど、
「出力時にエスケープする」っていうのが定石らしいよ。
でもエガミくんのやろうとしたのは「入力時のエスケープ」だね。

だから $_GET のところ(入力)で何かをするのではなくて…、
レスポンスのコーナーのところ。html変数埋め込んで echo してるとこ。
そこの全ての変数エスケープしちゃう方がいい感じかな。

その際に注意すべきは、html属性内(alt=ナントカとか、src=ナントカとか)に変数を埋め込んでいる場合は、ちゃんとクオートの類もエスケープする感じ?

echo '<img src="' . $hensuu . '" alt="ぺろぺろ" />';

とかなら、$hensuu はダブルクオートもエスケープだよ。
あ、htmlspecialchars ってダブルクオートはデフォルトで「&quot;」に変換されるんだっけ?
ちょっと試してみてね。

もし↓こんな風に、html属性のクオートにシングルクオートを使ってる場合だと…

echo "<img src='" . $hensuu . '" alt='ぺろぺろ' />";

これは

echo "<img src='" . htmlspecialchars($hensuu, ENT_QUOTES) . '" alt='ぺろぺろ' />";

こうする感じかな?

あと、サンプルコードには含まれていなかったけど、
本番の方だと、htmlheadの中でも変数つかってるよね。
たとえば、xxxで検索すると、titleタグメタタグにもxxxが入ってくる。
そのあたりも、とりあえず「表示しようとしてる箇所」の「表示する一歩手前」で全てエスケープしてやればいいと思うよ。

もしかしたら言ってること間違ってるかもしれないけど、
その時はきっと誰かが突っ込んでくれるはずー。


追記
あと、寂しいことってなに?

2008-10-19

http://anond.hatelabo.jp/20081019143453

for /R %i in (*) do @echo %i

カレント以下のファイル一覧(フルパス)が取得可能です。

2008-10-18

real street angels から mechanize を使って動画を取ってきてEmacsで見てみるよ

せっかく書いたから匿名でのせてみるよ

使い方は

  • 動画を取ってきたいよ
    • config.yamlユーザとかを設定するよ
    • ids.txt に取ってきたいIDを書くよ
    • sangels.bat を実行するよ
  • Emacs動画を見たいよ
    • sangels.el を load するよ
    • M-x sangels だよ

必要なものを gem で取ってくるにはこうすればいいよ

  • gem install -r log4r
  • gem install -r -v 0.6 hpricot
  • gem install -r mechanize

長すぎてelispが消えたから続きがあるよ

sangels.bat - 起動用バッチファイル

@echo off
setlocal
set WD=%~dp0
cd /d %WD%

ruby get_movies.rb
ruby get_images.rb
ruby create_m3u.rb

ruby

config.yaml - 設定ファイル
user: ユーザID
password: パスワード
ids_file: ids.txt
done_file: ids_done.txt
movies_dir: movies

log4r_config:
  pre_config:
    global: INFO
  loggers:
    - name: app
      type: Log4r::Logger
      level: INFO
      outputters:
        - STDOUT
        - FILE
  outputters:
    - name: STDOUT
      type: Log4r::StdoutOutputter
      formatter:
        type: Log4r::PatternFormatter
        pattern: "%d [%l] %C - %M"
        date_pattern: "%H:%M:%S"
    - name: FILE
      type: Log4r::FileOutputter 
      filename: "#{LOGDIR}/sangels.log"
      formatter:
        type: Log4r::PatternFormatter
        pattern: "%d [%l] %C - %M"
        date_pattern: "%Y-%m-%d %H:%M:%S"
get_movies.rb
require 'fileutils'
require 'logger'
require 'mechanize'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"
require "#{BASEDIR}/sangels"

$config = load_config(BASEDIR)
prepare_logger(BASEDIR)
$log = new_logger("get_movies")
WWW::Mechanize.log = new_logger("mechanize")
WGet.log = $log

class IDFile
  def initialize(file)
    @file = file
    unless File.exist?(@file)
      Fileutils.touch(@file)
    end
  end

  def ids(contains_comment = nil)
    File.open(@file) {|io|
      io.to_a.map {|x|
        x.chomp
      }.select {|x|
        if x.empty?
          nil
        elsif contains_comment
          true
        else
          not /^\s*\#/ =~ x
        end
      }
    }
  end

  def add(id)
    ids = ids(true)
    unless ids.any? {|x| x == id}
      write(ids + [id])
    end
  end

  def delete(id)
    ids = ids(true)
    if ids.any? {|x| x == id}
      write(ids - [id])
    end
  end

  def write(ids)
    File.open(@file, "w") {|io|
      ids.each {|x| io.puts x}
    }
  end
end


$log.info("BEGIN #{$0} ================")
exit_code = 0
begin
  ids_file = IDFile.new($config.ids_file)
  done_file = IDFile.new($config.done_file)
  movies_dir = $config.movies_dir
  wget = WGet.new

  sangels = SAngels.new
  sangels.login($config.user, $config.password)
  ids_file.ids.each {|id|
    begin
      movies = sangels.movies(id)
    rescue SAngels::Movies::InvalidMoviesError
      $log.warn("invalid movie id: #{id}")
      next
    end
    dir = File.expand_path(id, movies_dir)
    movies.each {|link|
      wget.retrieve(link.href, dir)
    }
    expected = movies.movie_links.map{|x| File.basename(x.href)}
    actual = Dir.glob("#{dir}/*").map {|x| File.basename(x)}
    if (expected - actual).empty?
      done_file.add(id)
      ids_file.delete(id)
    end
  }
rescue => e
  $log.error(e)
  exit_code = 1
end

$log.info("END #{$0} (#{exit_code}) ================")
exit exit_code
get_images.rb
require 'fileutils'
require 'logger'
require 'mechanize'
require 'ostruct'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"
require "#{BASEDIR}/sangels"

$config = load_config(BASEDIR)
prepare_logger(BASEDIR)
$log = new_logger("get_images")
WWW::Mechanize.log = new_logger("mechanize")
WGet.log = $log

$log.info("BEGIN #{$0} ================")
exit_code = 0
begin
  movies_dir = $config.movies_dir
  sangels = SAngels.new
  sangels.login($config.user, $config.password)
  thumbnails = sangels.thumbnails

  Dir.glob("#{movies_dir}/*").each {|dir|
    next unless File.directory? dir
    id = File.basename(dir)

    url = thumbnails.url(id)
    unless url
      $log.warn("#{id} is not found")
      next
    end
    path = File.expand_path("00_thumbnail#{File.extname(url)}", dir)
    next if File.exist? path

    $log.info("retrieving #{url}")
    thumbnail = thumbnails.get_file(id)
    File.open(path, "wb") {|io| io.write(thumbnail)}
  }
rescue => e
  $log.error(e)
  exit_code = 1
end

$log.info("END #{$0} (#{exit_code}) ================")
exit exit_code
create_m3u.rb
BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"

$config = load_config(BASEDIR)
movies_dir = $config.movies_dir
Dir.glob("#{movies_dir}/*") {|dir|
  next unless File.directory? dir
  name = File.basename(dir)
  files = Dir.glob("#{dir}/*.wmv").sort

  File.open("#{movies_dir}/#{name}.m3u", "w") {|io|
    files.each {|file|
      io.puts "#{name}/#{File.basename(file)}"
    }
  }

  File.open("#{dir}/00_movies.m3u", "w") {|io|
    files.each {|file|
      io.puts "#{File.basename(file)}"
    }
  }
}
sangels.rb
require 'mechanize'
require 'hpricot'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"

class SAngels
  HOST = "real2.s-angels.com"
  LOGIN_URL = "http://#{HOST}/member/"
  INFO_URL = "http://#{HOST}/teigaku/item.php"
  THUMBNAILS_URL = "http://#{HOST}/teigaku/"
  THUMBNAIL_URL = "http://#{HOST}/images/default/thumb/"

  def initialize()
    @agent = WWW::Mechanize.new
  end

  def login(user, password)
    login_form = @agent.get(LOGIN_URL).forms.find {|form|
      form.fields.any? {|field| field.name == "frmLoginid"}
    }
    login_form.frmLoginid = user
    login_form.frmPw = password
    @agent.submit(login_form)
  end

  def movies(id, no_validate = nil)
    Movies.new(@agent, id, !no_validate)
  end

  def thumbnails
    Thumbnails.new(@agent)
  end

  class Thumbnails
    def initialize(agent)
      @agent = agent
      doc = Hpricot(@agent.get_file(THUMBNAILS_URL))
      elems = doc.search("div[@class=realthum]/a")
      @links = Hash(
        elems.map {|elem|
          href = elem["href"]
          id = $1 if /ID=(.+)/ =~ href
          url = elem.search("img")[0]["src"]
          [id, url]
        })
    end

    def get_file(id)
      @agent.get_file(url(id))
    end

    def url(id)
      @links[id]
    end

    def exist?(id)
      url(id)
    end
  end

  class Movies
    class InvalidMoviesError < StandardError
    end

    def initialize(agent, id, no_validate)
      @agent = agent
      @id = id
      if !no_validate &amp;&amp; !valid?
        raise InvalidMoviesError
      end
    end

    def info_page_url
      "#{INFO_URL}?ID=#{@id}"
    end

    def info_page
      @agent.get(info_page_url)
    end

    def movies_page
      @agent.click(info_page.links.find {|link| /P=10/ =~ link.href})
    end

    def movie_links
      movies_page.links.select {|link|
        /wmv$/ =~ link.href
      }.sort {|a, b|
        File.basename(a.href) <=> File.basename(b.href)
      }
    end

    def valid?
      info_page.uri.to_s == info_page_url
    end

    def each(&amp;block)
      orig_links = movie_links
      orig_links.each {|orig_link|
        link = movie_links.find {|l| File.basename(l.href) == File.basename(orig_link.href)}
        block.call(link)
      }
    end
  end
end
util.rb
require 'log4r'
require 'log4r/yamlconfigurator'
require 'singleton'
require 'fileutils'
require 'ostruct'

def Hash(a)
  Hash[*a.flatten]
end

def load_config(basedir)
  OpenStruct.new(File.open("#{basedir}/config.yaml") {|io| YAML.load(io)})
end

def new_logger(name)
  Log4r::Logger.new("app::#{name}")
end

def prepare_logger(basedir, logdir = nil)
  logdir ||= basedir
  Log4r::YamlConfigurator["LOGDIR"] = logdir
  Log4r::YamlConfigurator.load_yaml_file("#{basedir}/config.yaml")
end

class NullObject
  include Singleton
  def method_missing(message, *arg)
    NullObject.singleton
  end
end

class WGet
  class << self
    attr_accessor :log
    def initialize
      super
      @log = NullObject.singleton
    end
  end
  
  def log
    self.class.log
  end

  def retrieve(url, dir)
    FileUtils.mkdir_p(dir)
    file = File.expand_path(File.basename(url), dir)
    if File.exist?(file)
      log.info("already retrieved #{url}")
      return true
    end

    tmp = "#{file}.part"
    log.info("retrieving #{url}")
    ret = system("wget", "-c", "-O", tmp, url)
    if ret
      log.info("retrieving succeeded #{url}")
      File.rename(tmp, file)
    else
      if $? == 0x020000 # Ctrl-C
        exit($?)
      else
        log.error("retrieving failure #{url} (#{$?})")
      end
    end
    return ret
  end
end

2008-09-14

60行で作らないPHPテンプレートエンジン

今更だけど60行で作るPHP用テンプレートエンジンクラス化した。

  1. PHP5で動かしてね
  2. 細かい使い方はコード見て適当に判断してね
  3. もちろん改変、商用利用自由にね
  4. サンプルテンプレート60行で作るPHP用テンプレートエンジンと一緒
コード
<?php
class NoSixTemplate{
   protected $template_dir = null;
   protected $template = null;
   protected $context = array();
   
   function __construct($filename = null, $directory = null){
      $this->set_template($filename);
      $this->set_dir($directory);
   }
   
   function set_template($filename){
      $this->template = $filename;
   }
   
   function set_dir($directory){
      if(substr($directory, -1) != '/') $directory .= '/';
      $this->template_dir = $directory;
   }
   
   function set_data($context_key, $context_data, $overwrite = false){
      if(empty($this->context[$context_key]) || $overwrite){
         $this->context[$context_key] = $context_data;
      }else{
         if(is_array($context_data) &amp;&amp; is_array($this->context[$context_key])){
            $this->context[$context_key] = array_merge($this->context[$context_key], $context_data);
         }else{
            $this->context[$context_key] .= $context_data;
         }
      }
   }
   
   function reset($context_key = null){
      if(is_null($context_key)){
         $this->context = array();
      }else{
         $this->context[$context_key] = null;
      }
   }
   
   function convert_template(){
       $filename = $this->template_dir.$this->template;
       $cachename = $filename.'.cache';
       if(!file_exists($cachename) || filemtime($cachename) < filemtime($filename)){
           $s = file_get_contents($filename);
           $s = $this->convert_string($s);
           
           if(is_writable($cachename) || is_writable($this->template_dir)){
               file_put_contents($cachename, $s);
           }
       }
       return $cachename;
   }
   
   function convert_string($s) {
       $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s);
       $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s);
       $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1,ENT_QUOTES); ?>', $s);
       return $s;
   }
   
   function display(){
       $cache = $this->convert_template();
       extract($this->context);
       include($cache);
   }
}
?>
サンプルコード
<?php
require_once('NoSixTemplate.php');
$template = new NoSixTemplate('template.php', 'template_directory');
$template->set_data('title', 'Example');
$template->set_data('list', array(10,'<A&amp;B>',NULL));
$template->display();
?>

2008-07-10

csh

#! /bin/csh -f

##処理選択
echo "処理を選んでください"
echo "1 Dir生成"
echo "2 Dir削除"
echo " "
echo -n "No入力 1 or 2 :"
set num <$


##入力エラー処理
##1でない or 2でない場合はエラー出してシェル再読み込み
if [ $num != 1 -a $num != 2 ] ; then
  echo "入力エラー。1か2を入力してください"
 select.csh
fi  

##以下numは1か2

##実行許可入力
if [ $num = 1 ] ; then
  echo "1 Dir生成を実行します Y or N"
  echo -n "Y or N を入力してください"
 set Ans <$
fi

if [ $num = 2 ] ; then
  echo "2 Dir削除を実行します Y or N"
  echo -n "Y or N を入力してください"
 set Ans <$
fi

##入力エラー処理
##Yでない or Nでない場合はエラーを出してシェル再読み込み
if [ $Ans != Y -a $Ans != N ] ; then
  echo "入力エラー。YかNを入力してください"
 select.csh
fi 

##以下AnsはYかN
##シェル選択&実行
if [$num =1 -a Ans = Y] ; then
  source kadai2.csh
  echo "Dir生成が終了しました"
fi

if [$num =2 -a Ans = Y] ; then
  source del.csh
  echo "Dir削除が終了しました"
fi

2008-03-28

http://anond.hatelabo.jp/20080327165052

PHPも対話型コンソールがほしくなった。

C:\> php -r "echo 'unko'; "

ってやるのは長いのが書きにくいし、都度都度「php -r ""」って打つのがウザかった。

調べてみるとあった。

C:\> php -a
Interactive mode enabled

<?
echo "unko";
unko
?>

こりゃらくだ。

2007-11-08

60行テンプレートエンジンがパワーアップしてレイアウト機能に対応

前の60行テンプレートエンジンを改良して、レイアウトテンプレート機能を追加してみた(それでも全部で90行)。


レイアウトテンプレート機能とは、例えば個別のテンプレートが<table>...</table>を出力して、それをレイアウトテンプレートが<html><body>...</body></html>で囲って出力するとかそんなの。

詳しくは終わりの方のサンプルをみてくれ。


これは Ruby on Rails(とその仲間たち)にある便利機能のひとつ。

ついでにいうとSmartyにはない機能のひとつ。

今まで知らなかった人はぜひ試してくれ。チョー便利だから。


前回はたくさんのブックマークありがと。

コメントで「男前テンプレート」と名前がついてたので、勝手採用

名前がキモいっていわれるよ?でもそんなのカンケイネー


あと、これ以上の機能追加はしないので、各自勝手に改造して使ってくれ(そのためにコメントをつけてるから)。何でも人任せにするな。


コード

<?php
/*
 *  OtokomaeTemplate.php -- レイアウトテンプレートに対応した90行のテンプレートエンジン
 *
 *  - レイアウトテンプレート中で echo $_content; とすると中身が表示される。
 *  - テンプレート中で設定した変数レイアウトテンプレートで使うことが可能。
 *  - レイアウトテンプレート名をテンプレート側で指定することも可能。
 *  - 使い方:
 *      require_once('OtokomaeTemplate.php');
 *      $TEMPLATE_DIR    = 'templates';  // 省略可、パーミッションに注意
 *      $LAYOUT_TEMPLATE = 'layout.php'; // 省略可
 *      $context = array('title'=>'Example',
 *                       'list'=>array(10,'<A&amp;B>',NULL));
 *      include_template('template.php', $context);
 *  - 要 PHP 5.1 or later
 *  - ライセンス: public domain (自由に改造してね)
 */

/*
 *  設定用のグローバル変数
 */
$TEMPLATE_DIR    = NULL;   /* テンプレートを探すディレクトリ */
$LAYOUT_TEMPLATE = NULL;   /* レイアウトテンプレートファイル名 */

/*
 *  テンプレートを読み込んで実行する。
 *  $_context は変数名をキー、値を要素とする連想配列。
 *  $_layout はレイアウトテンプレートファイル名。
 *  - NULL または省略した場合は $LAYOUT_TEMPLATE を使う。
 *  - FALSE ならレイアウトテンプレートを使わない。
 *  - $_context['_layout'] = '...'; とすればテンプレート側でも指定可能。
 */
function include_template($_filename, $_context, $_layout=NULL) {
    global $LAYOUT_TEMPLATE;
    $_content = render_template($_filename, $_context);
    if (@$_context['_layout'] !== NULL)   // テンプレート側で指定された場合は
        $_layout = $_context['_layout'];  // それを使う。
    elseif ($_layout === NULL)            // 引数で指定されなかった場合は
        $_layout = $LAYOUT_TEMPLATE;      // デフォルトファイル名を使う。
    if ($_layout) {
        $_context['_content'] = $_content;  // レイアウトテンプレート中で使う変数
        $_content = render_template($_layout, $_context);
    }
    echo $_content;   // or return $_content;
}

/*
 *  テンプレートを読み込んで実行し、その結果を文字列で返す。
 *  include_template() の実体。
 */
function render_template($_filename, &amp;$_context) {
    $_cachename = convert_template($_filename);
    extract($_context);     // 連想配列ローカル変数に展開
    ob_start();
    include($_cachename);   // テンプレートを読み込んで実行
    return ob_get_clean();
}

/*
 *  テンプレートファイルを読み込み、convert_string() で置換してから
 *  キャッシュファイルに書き込む。読み込み時のロックは省略。
 *  (file_get_contents() もファイルロックできるようにしてほしいなあ。)
 */
function convert_template($filename) {
    global $TEMPLATE_DIR;
    if (! file_exists($filename) &amp;&amp; $TEMPLATE_DIR)
        $filename = "$TEMPLATE_DIR/$filename";
    $cachename = $filename . '.cache';
    if (! file_exists($cachename) || filemtime($cachename) < filemtime($filename)) {
        $s = file_get_contents($filename);
        $s = convert_string($s);
        file_put_contents($cachename, $s, LOCK_EX); // LOCK_EX サポートは 5.1.0 から
    }
    return $cachename;
}

/*
 *  テンプレートの中身を置換する。
 *  - '#{...}' を 'echo ...;' に置換
 *  - '%{...}' を 'echo htmlspecialchars(...);' に置換
 *  - ついでにXML宣言も置換
 */
function convert_string($s) {
    $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s);
    $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s);
    $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1); ?>', $s);
    return $s;
}
?>

サンプルPHPコード:

<?php
require_once('OtokomaeTemplate.php');
$TEMPLATE_DIR    = 'templates';
$LAYOUT_TEMPLATE = 'layout.php';
$context = array('list'=>array(10,'<A&amp;B>',NULL));
include_template('template.php', $context);
?>

レイアウトテンプレート(layout.php):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <body>
    <h1>%{$title}</h1>
    <div id="maincontent">
<!-- テンプレートの内容 -->
<?php echo $_content; ?>
<!-- /テンプレートの内容 -->
    </div>
  </body>
</html>

テンプレート(template.php):

<?php // レイアウトテンプレート名をテンプレート中で指定する場合 ?>
<?php //$_context['_layout'] = 'mylayout.php'; ?>
<?php // レイアウトで使用する変数テンプレート中で指定する場合 ?>
<?php $_context['title'] = 'レイアウトのサンプル'; ?>
<table>
<?php foreach ($list as $i=>$item): ?>
  <tr bgcolor="#{$i % 2 ? '#FFCCCC' : '#CCCCFF'}">
    <td&gt;#{$i}</td&gt;
    <td&gt;%{$item}</td&gt;
  </tr>
<?php endforeach ?>
</table>

出力例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <body>
    <h1>レイアウトのサンプル</h1>
    <div id="maincontent">
<!-- テンプレートの内容 -->
<table>
  <tr bgcolor="#CCCCFF">
    <td&gt;0</td&gt;
    <td&gt;10</td&gt;
  </tr>
  <tr bgcolor="#FFCCCC">
    <td&gt;1</td&gt;
    <td&gt;&lt;A&amp;B&gt;</td&gt;
  </tr>
  <tr bgcolor="#CCCCFF">
    <td&gt;2</td&gt;
    <td&gt;</td&gt;
  </tr>
</table>
<!-- /テンプレートの内容 -->
    </div>
  </body>
</html>

いくつか補足:

2007-10-30

[]55行で作るC#テンプレートエンジン

http://anond.hatelabo.jp/20071030034313二番煎じ

あまりのアホさに、作ってて気が狂いかけた


方針


using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;

delegate void ConvertTemplateDelegate(TextWriter tw, Dictionary<object, object> args);
static class TemplateGenerator {
    public static ConvertTemplateDelegate Generate(string code) {
        CompilerParameters param = new CompilerParameters();
        param.GenerateInMemory = true;
        param.ReferencedAssemblies.Add("System.Web.dll");
        CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, ParseTemplate(code));
        if (0 < rs.Errors.Count) {
            StringWriter sw = new StringWriter();
            sw.WriteLine("Compile Error...");
            foreach (CompilerError err in rs.Errors)
                sw.WriteLine(err.ToString());
            throw new Exception(sw.ToString());
        }
        return (ConvertTemplateDelegate) Delegate.CreateDelegate(typeof(ConvertTemplateDelegate), rs.CompiledAssembly.GetType("Template", true).GetMethod("Convert"));
    }
    private static string ParseTemplate(string code) {
        using (StringWriter sw = new StringWriter()) {
            sw.WriteLine("using System; using System.Collections.Generic; using System.IO; using System.Web;");
            sw.WriteLine("public static class Template {");
            sw.WriteLine("public static void Convert(TextWriter tw, Dictionary<object, object> args) {");
            int index = 0;
            while (0 <= index &amp;&amp; index < code.Length) {
                int i = code.IndexOf("<%", index);
                sw.WriteLine("tw.Write(\"{0}\");", EscapeString(i < 0 ? code.Substring(index) : code.Substring(index, i - index)));
                if (0 <= i) {
                    i += 2;
                    int i2 = code.IndexOf("%>", i);
                    if (0 <= i2) {
                        string cc = code.Substring(i, i2 - i);
                        if (cc.StartsWith("="))
                            sw.WriteLine("tw.Write(HttpUtility.HtmlEncode(\"\"+({0})));", cc.Substring(1));
                        else
                            sw.WriteLine(cc);
                        i = i2 + 2;
                    }
                }
                index = i;
            }
            sw.WriteLine("}}");
            return sw.ToString();
        }
    }
    private static string EscapeString(string code) {
        return code.Replace("\\", "\\e").Replace("\"", "\\\"").Replace("\t", "\\t").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\\e", "\\\\");
    }
}

サンプル C# コード。ためしにテンプレートから Xml 生成して、標準出力してみる。

class Program {
    static void Main(string[] args) {
        ConvertTemplateDelegate func = TemplateGenerator.Generate(TemplateEngine.Resource1.template);
        using (StringWriter sw = new StringWriter()) {
            Dictionary<object, object> arg = new Dictionary<object, object>();
            arg["title"] = "template sample";
            arg["data"] = new string[] { "foo", "fooo", "<strong>foooooooooo!</strong>" };
            func(sw, arg);
            Console.WriteLine(sw);
        }
    }
}

サンプルテンプレート

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title><%= args["title"] %></title>
  </head>
  <body>
    <h1><%= args["title"] %></h1>
    <table>
<% string[] data = (string[]) args["data"]; %>
<% for(int i = 0; i < data.Length; i++) { %>
      <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>">
        <td><%= i %></td>
        <td><%= data[i] %></td>
      </tr>
<% } %>
    </table>
  </body>
</html>

出力例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>template sample</title>
  </head>
  <body>
    <h1>template sample</h1>
    <table>


      <tr bgcolor="#FFCCCC">
        <td>0</td>
        <td>foo</td>
      </tr>

      <tr bgcolor="#CCCCFF">
        <td>1</td>
        <td>fooo</td>
      </tr>

      <tr bgcolor="#FFCCCC">
        <td>2</td>
        <td>&lt;strong&gt;foooooooooo!&lt;/strong&gt;</td>
      </tr>

    </table>
  </body>
</html>

CodeDom 使って動的コンパイル……って、このコードのままだとセキュリティ的に大問題な気がするな。

素直に ASP.NET 使ったほうが楽だと直感した。

あと EscapeString すっごく自信ない。たぶん修正が必要だと思うw

- 転職ならen
- 派遣ならen
2ページ中1ページ目を表示(合計:26件)