php

phpは適当でも動くので楽です

DB接続(oracle)

pearとかあるので普通こんな再発明やらないです、ばかです。ソースはこれです。bindhelper.php

Bindhelper_Conでコネクションを裏管理して、行単位管理のBindhelper、テーブル単位管理のBindHelperListクラスを管理したいテーブルごとに継承して使います。継承時それっぽいテーブル定義を書きます。DB上に存在しても、列を定義しなければ無視されます。


<?php
//dbdef.php
require_once( "bindhelper.php" );

//###動物小屋
$CAnimal_TD = array(
"ANIMAL",//テーブル名
6,//全カラム数
1,//プライマリキーの数、左詰め必須です

"ID", TD_AUTO,
"NAME", TD_AUTO,
"FOOT", TD_AUTO,
"EYE", TD_AUTO,
"REGISTDATE", TD_DATE_I,//insert時オートsysdate
"CHANGEDATE", TD_DATE_U,//insert/update時オートsysdate
 );

class CAnimal extends BindHelper {
    function CAnimal()
    {
        global $CAnimal_TD;
        BindHelper::BindHelper($CAnimal_TD);
    }
};


class CAnimalList extends BindHelerList {
    function CAnimalList()
    {
        global $CAnimal_TD;

        //第二引数に子クラス名を指定しないと標準のBindhelperにTDを渡して生成するが
        //子クラスでextendしたメソッドは使えないしpkshadowの設定もできない
        BindHelerList::BindHelerList($CAnimal_TD,"CAnimal");
    }
};

?>

以上継承したクラスで色々操作します。bh_PrintDebugBuf()で発行したSQL文をデバッグ表示したりします。


<?php
//animal.php
require_once("dbdef.php");

    //コネクション作成
    global $bhc;
    $con =& $bhc->Init( "ID", "PASS", "DBSTR" );
    if(!$con)
    {   //エラー
        return;
    }


    $al = new CAnimalList();//インスタンス作成
    $al->Load();//DBからデータロード
    if( 0 < count($al->rows) )//データがあった
    {
        foreach( $al->rows as $row )
        {
            printf( "ID:%d, 名前:%s, 足:%d, 目:%d\n",
                $row->GetValue(0),       //ID
                $row->GetValue(1),       //名前
                $row->GetValue(2),       //足の数
                $row->GetValue(3) );     //目の数
        }

        //動物データの変更
        $al->rows[0]->SetValue( 2, 6 );   //突然変異して足が増えた
        $al->Save(true);                  //変更された所だけ検出してSQLを発行します
                                          //trueでオートコミット
    }
    else
    {
        echo "データがありません";
    }


    //新しい動物を追加
    $a = new CAnimal();//インスタンス作成
    $insdata = array(
        10,             //ID(この例ではプライマリキーなので本来はきちんと得る必要があります)
        "ゴロンタ",     //名前
        4,              //足の数
        2,              //目の数
                        //TD_DATE_Iの項は書かなくてもinsert時自動でsysdateが入力されます
                        //TD_DATE_Uの項は書かなくてもinsert/update時自動でsysdateが入力されます
    );

    if( $a->Insert( $insdata ) === false )
    {   //失敗
        bh_Rollback();//ロールバック。もし他インスタンス等でコミットしていないならそれらも
        return;
    }

    bh_Commit();//コミットしないと反映されません



    $bhc->End();//コネクション切る
    bh_PrintDebugBuf();//発行したSQL文が表示される
?>

あと継承したクラスで専用の操作が要るなら継承先でメソッド追加するといいです。たとえば上記例でプライマリキーのIDを発行するメソッドなど。他にLoad()時のソート順を特殊にしたいとか特殊な条件にしたいとかならBindHelerList::Load()を継承先でオーバーライドしたり、中身持ってきて別名で好きに改変したりするといいです。

他におまけのbh_Request()/bh_RequestBind()でストレートにSQL発行もできます。

結局これのうれしい所は変更された所だけ検出更新、何でもバインドしまくり、dbdef.phpにカスタムなSQL文が集約されやすい、とかです多分。あとMerge()でなんとなくマージできるのも(作ったけどあまり使ってない)

basic認証(権限機能込)

pear::authでも使うか、と思ったらたくさん依存ファイルがあったのでだるくなった。ソースはこれです。mauth.php

どうせ適当なbasic認証しか使わないしユーザーpassの暗号化作る時もその時crypt()呼ぶし。


<?php

require_once( "mauth.php" );

//認証する
$auth = ma_AuthUser( "passwd.txt");//パスワードファイルの名前渡す
if( $auth < AUTH_GUEST )//あんただれですか?
{   //よくない
    header("WWW-Authenticate: Basic realm=\"mgmt\"");
    header("HTTP/1.0 401 Unauthorized");

    echo "正しいIDとPASSを入力してください";
    exit;
}


//認証されたので以下にひみつページを出力

printf("<p>%sさんの権限は%sです</p>", $_SERVER['PHP_AUTH_USER'], ma_GetAuthS() );

if( AUTH_GUEST <= ma_GetAuth() )
{
    //ゲストさんには普通のものを見せる
    ...

    if( AUTH_USER <= ma_GetAuth() )
    {
        //ユーザーさんは追加でちょっとアレなものを見てよい
        ...

        if( AUTH_POWERUSER <= ma_GetAuth() )
        {
            //パワーユーザーさんは更に追加ですごくアレなものを見てよい
            ...

            if( AUTH_ADMIN <= ma_GetAuth() )
            {
                //管理人はなんとか会の実権を握っている。
                ...
            }
        }
    }
}


?>

みたいな感じで使う。passwd.txtのフォーマットは権限番号:ユーザー名:crypt()済のpass:で

0:touko:maMatsuDaiRA:
1:yumi:maFukuZawA:
2:sachiko:maOgasAwaRa:
3:youko:maMiZuNo:

みたいな。これは当然httpで触れないとこに置く。

権限番号はmauth.phpの先頭に

define( "AUTH_GUEST", 0 );
define( "AUTH_USER", 1 );
define( "AUTH_POWERUSER", 2 );
define( "AUTH_ADMIN", 3 );

みたいに書いてあるので増やしたかったら0以上で適当に改変する。その際併せて

$ma_name = array( "GUEST", "USER", "POWERUSER", "ADMIN" );

も適切に変えるように。ma_GetAuthS()使わないならどうでもいいですが。

数字が大きいほど権限は強くなりがちな感じ。が、別に上記の例みたいな入れ子しなければ適当なグループとして扱ってよいのではないか。

ajaxでページめくり(pager)

最低限。実際の所コントローラーを吐いてるだけ。表示する内容は別に用意する。引数に総ページ数とか要りますが、計算は自分でしてください。あとIE6,7でしか確認していません。ソースはこれです。majaxpager.php
加えてajaxライブラリのこれが必要。v0.512で確認した。これは軽いのでお勧め。

で、たとえば以下のように、


<?php

require_once( "mydata.php" );//よくわからないがとにかくデータを管理してる何か
require_once( "majaxpager.php" );

//用意 何らかのデータ列をロードする
$data = new myData();
$data->Load();//データロード

$perpage = $data->GetperPages();//1ページにアイテムは何個入っているか
$pagenum = $data->GetnumPages();//pager用のために総ページ数が必要

$data_partial = $data->Get( 0, $perpage );//データの先頭0番目から$perpage個得る

//pagerオブジェクト
$pager = new mAjaxPager( array(
            'prefix'=>'mypager_',//他所の誰かと被らないためのprefix
            'pagenum'=>$pagenum,//総ページ数
            'currentpage'=>1;//最初に表示してるページ 普通1
            'ajaxlib_url'=>'https://mydomain.jp/js/ajax.js',//依存してるajaxライブラリへのURL
            'ajaxif_url'=>'cgi-bin/pagerif.php',//ページャーが通信してページデータをやり取りするcgiとかのURL

            //追加アトリビュート cssで見た目とか設定するとよいかもしれない

            'controllerattr'=>'class="map_controller"',//コントローラの見た目
            'buttonattr'=>'class="map_button"',//コントローラ内、ボタン
            'infoattr'=>'class="map_info"',//情報表示してるとこ
            'bodyattr'=>'class="map_body"',//ページ内容のとこ
        ) );


echo $pager->Get( $data_partial );//$data_partialをページ内容として受け取り、コントローラをくっつけて完成

?>

すると1ページ目とnew,oldボタンが表示されると思う。そして別にXMLHttpRequest経由で次のページを送ってくれるインターフェイスが必要です。たとえば以下のような


<?php
//https://mydomain.jp/cgi-bin/pagerif.php

require_once( "mydata.php" );//よくわからないがとにかくデータを管理してる何か

$data = new myData();
$data->Load();//データロード

$perpage = $data->GetperPages();//1ページにアイテムは何個入っているか

$page = $_POST["page"];//ページャーが表示したいページ番号を送って来た 開始番号は1から、つまりこの例だと
$start = ($page-1)*$perpage;//である

$data_partial = $data->Get( $start, $perpage );//$startから$perpage個得る


header("Content-type: text/html; charset=SHIFT_JIS");//文字コードを間違えるとたいてい失敗する
echo $data_partial;//送る

?>

のを設置する。と、ボタンを押した時これと通信してデータ内容がめでたく書き換わる。ちなみに通信中にくだらないローディング表示が出るかもしれない。通信が早いと多分見えません。以上を見た暇な人に宿題をあげます。