TheoryOfContraints official blog -2ページ目

function cmdline()

http://turusuke.hatenablog.com/entry/2012/10/17/php-routing

 

を見て、URLを使ったルーティング処理を

 

$requestDATA = cmdline();
print_r($requestDATA);
exit;

function cmdline() {
    $str = str_replace("\0", "", $_SERVER['REQUEST_URI']);
    $str = trim($str, "\/");
    $data = explode("/", $str);
    
    return $data;
}
    
ってPHPで作った。それで

 

Array ( [0] => category [1] => food )

 

となる

 

C++とかのコマンドライン引数の取得方法と同じですね。などなど、プログラムを作っている

 

 

 

 

Very Light Weight Frame work "Typon" proto type.

今、PHPでウェブのプログラムを作っているけど、作っているライブラリがコンパクト過ぎて。他の機能を仮組みで作って、テストもデバッグもしてないけれど、見せた方が面白そうなので見せてみる

 

動作テストもしてないので、このフレームワークを使わないで! 事故っても責任は取りませんよ

 

でも、これらの機能のみでもPHPのプログラムを動かせるよな、と実験的な試みです

 

ちゃんとテストできて確かめて動かせるなら、githubで上げ直しますので

 

とりあえず、ドメインなプログラミングなMVPパターンで組んでいて、HTMLテンプレートはSmartyで、パスワードのハッシュなどは別にLOGINドメインを作ってて、そこに置いてます

 

以上、暇潰し報告でした

 

------- 以下、ソースコード -------

<?php
    //     ヌルバイトアタック処理
    function sanitizer($array) {
        if (is_array($array)) {
            return array_map('sanitizer', $array);
        }
        return str_replace("\0", "", $array);
    }

    $_POST = sanitizer($_POST);
    $_COOKIE = sanitizer($_COOKIE);
    
    $exec = str_replace("\0", "", $_GET['exec']);
    $_GET = array(); // Delete gets.
    
    // mb Setting.
    mb_language("Japanese");
    mb_internal_encoding("UTF-8");
    
    // セッションIDリセット
    session_start();
    session_regenerate_id(true);    
    
    // プレゼンテーターネームチェック
    if ($exec == "") {
        // "/"なのでindexを実行
        $exec = "index";
    } elseif (!preg_match('/\A[a-zA-Z0-9\-\_]+\z/i', $exec)) {
        // 不正アクセスなのでログアウト
        STD::logout();
        exit;
    }
    
    // プレゼンテーターがあるか?
    if (! file_exists("frames/".$exec.".frame")) {
        if ($exec == "index") {
            // error.
            echo("Error: No thing [index].");
            exit;
        } else {
            // 不正アクセスなのでログアウト
            STD::logout();
            exit;
        }
    }
    
    // 実行
    require_once("frames/".$exec.".frame");
    exit;

class STR {    
    // 全角トリム
    function mbTrim($str) {
        $str = self::toUtf8($str);
        $str = preg_replace('/[\r\n]/u', '', $str);
        return preg_replace('/\A[\p{C}\p{Z}]++|[\p{C}\p{Z}]++\z/u', '', $str);
    }
    
    // UTF変換
    function toUtf8($str) {
        return mb_convert_encoding($str, "UTF-8", "auto");
    }
    
    // Nullバイト削除
    function nullDelete($str) {
        return str_replace("\0", "", $str);
    }
    
    // <br>変換
    function toBr($str) {
        $str = preg_replace('/\n\r/u', '\r\n', $str);
        $str = preg_replace('/\r\n/u', '\r', $str);
        $str = preg_replace('/\n/u', '\r', $str);
        $str = preg_replace('/\r/u', '<br>', $str);
        return $str;
    }
    
    function toRn($str) {
        $str = preg_replace('/<br>/u', '\r\n', $str);
        return $str;
    }

    function len($str) {
        return mb_strlen($str);
    }
    
    function empty($str) {
        return empty($str);
    }
    
    function htmlConvert($str) {
        return htmlspecialchars($str, ENT_QUOTES);
    }

    function checkUrl($str) {
        return preg_match('/\Ahttps?(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)\z/', $str);
    }

    function checkPassword($str) {
        return preg_match('/\A[a-zA-Z0-9]+\z/i', $str);
    }

    function checkNumber($str) {
        return preg_match('/\A[0-9]+\z/i', $str);
    }
    
    function checkMail($str) {
        // https://gist.github.com/felds/864067
        $regexp = '/^(?:[a-z0-9!#$%\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}'.
                '~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\['.
                '\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-'.
                '9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-'.
                '9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?'.
                '|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-' .
                '\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/';
        return preg_match($regexp, $str);
    }
}

class STD {
    // Loginセーブ
    function loginSave($userId) {
        $_SESSION['id'] = $userId;
        self::uidMake($userId);
    }
    
    // Loginチェック
    function loginCheck() {
        if (! uidCheck()) {
            self::logout();
            exit;
        }
    }

    // ログアウト
    function logout() {
        $_SESSION = array();
        session_destroy();
        header("Location: ./index");
    }
    
    // uID.
    function uidMake($user_id) {
        $_SESSION['uid'] = self::uidGet($user_id);
        return $_SESSION['uid'];
    }
    
    function uidCheck() {
        if (empty($_SESSION['uid']) || empty($_SESSION['id'])) {
            return false;
        } elseif (self::uidGet($_SESSION['id']) == $_SESSION['uid']) {
            return true;
        }
        return false;
    }

  
    function uidGet($user_id) {
        $str = $user_id."nje4HDa"; // ジャミング
        
        // ブラウザー情報など
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $str .= $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            $str .= $_SERVER['REMOTE_ADDR']; 
        }
        $str .= $_SERVER['HTTP_USER_AGENT'];
        
        // ジャミング
        $str .= "nje4HDa";
        
        // 暗号化
        $str = crypt($str, '$2y$07$ZvnOUqcYywVVmukaNHFVoP$');
        $uId = hash_hmac("haval160,4", $str, "heJH6hfHIh4JNHJe");
        
        return $uId;        
    }
    
    // time.
    function timeSectime($y, $mon, $d, $a, $m) {
        return mktime($a, $m, 0, $mon, $d, $y);
    }
    
    function timeDateRss($sectime) {
        return date(DATE_RFC822, $sectime);
    }
    
    function timeDate($sectime) {
        return getdate($sectime);
    }
}

class DB {
    var $db;
    
    // mysql
    function make() {
        if (empty($this->db)) {
            $this->db = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
        }
        
        return $this->db;
    }
    
    function get() {
        return self::make();
    }
    
    function error() {
        $str = "";
        
        if($this->db->connect_errno) {
            $str = $this->db->connect_errno . ' : ' . $this->db->connect_error;
        }
        return $str;
    }
    
    function close() {
        mysqli_close($this->db);
    }

    // JSON.
    function jsonWrite($data, $array) {
        $file = "data/{$data}.data";
        if (! file_exists($file)) {
            return false;
        }
        if (file_put_contents($file, serialize($array)) == false) {
            return false;
        }
        return true;
    }
    
    function jsonRead($data) {
        $json = array();
        $file = "data/{$data}.data";
        if (! file_exists($file)) {
            return $json;
        }
        $json = unserialize(file_get_contents($file));
        return $json;
    }
}

class MAIL {
    function send($toAdrs, $fromAdrs, $subject, $body) {
        if (!STR::checkMail($toAdrs)) {
            return false;
        } elseif (!STR::checkMail($fromAdrs)) {
            return false;
        }
        
        $header = "From: $fromAdrs\nReply-To: $fromAdrs\n";
        return mb_send_mail($toAdrs, $subject, $body, $header);
    }
}

class SONOTA {
    // Make Crypt's Salt.
    function makeSalt() {
        $char = array_merge(range('a', 'z'), range('A', 'Z'), array('.', '/'));
        
        $salt = "";
        for ($i = 0; $i < 22; $i++) {
            $salt .= $char[mt_rand(0, count($char) - 1)];
        }
        
        return $salt;
    }
}
?>

 

 

 

PHPでプログラムを作っている

最近、PHPでプログラムをしている

 

スマホのゲームのサーバーは、まだ、golangではなく、PHPで出来ているそうなので、久々、PHPでプログラムを作って、少しサーバーのプログラムの作り方を覚え直そうと思ったので

 

まぁ、それほどPHPのプログラムの作り方変化はなかったので、どこまでしょぼく、と言うかスマートに作ろうと思ってたのですけど、データのバリテーションの部分は、(バグが残っているかも知れない)仮組みの状態で

 

<?php

class STR {    
    // 全角トリム
    function mbTrim($str) {
        $str = self::toUtf8($str);
        $str = preg_replace('/[\r\n]/u', '', $str);
        return preg_replace('/\A[\p{C}\p{Z}]++|[\p{C}\p{Z}]++\z/u', '', $str);
    }
    
    // UTF変換
    function toUtf8($str) {
        return mb_convert_encoding($str, "UTF-8", "auto");
    }
    
    // <br>変換
    function toBr($str) {
        $str = preg_replace('/\n\r/u', '\r\n', $str);
        $str = preg_replace('/\r\n/u', '\r', $str);
        $str = preg_replace('/\n/u', '\r', $str);
        $str = preg_replace('/\r/u', '<br>', $str);
        return $str;
    }
    
    function toRn($str) {
        $str = preg_replace('/<br>/u', '\r\n', $str);
        return $str;
    }

    function len($str) {
        return mb_strlen($str);
    }
    
    function empty($str) {
        if ($str == "") {
            return true;
        }
        return false;
    }
    
    function htmlConvert($str) {
        return htmlspecialchars($str, ENT_QUOTES);
    }

    function url($str) {
        return preg_match('/\Ahttps?(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)\z/', $str);
    }

    function password($str) {
        return preg_match('/\A[a-zA-Z0-9]+\z/i', $str);
    }

    function number($str) {
        return preg_match('/\A[0-9]+\z/i', $str);
    }
    
    function mail($str) {
        // https://gist.github.com/felds/864067
        $regexp = '/^(?:[a-z0-9!#$%\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}'.
                '~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\['.
                '\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-'.
                '9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-'.
                '9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?'.
                '|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-' .
                '\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/';
        return preg_match($regexp, $str);
    }
}

?>

 

って、クラスをネームスペース的に組んで、

 

        $str = STR::mbTrim($_POST['station']);
        $str = STR::htmlConvert($str);
        $data['station'] = $str;
        if (STR::empty($str)) {
            $error['error'] = 1;
            $error['station'] = "ポッドキャストの名前がありません";
        } elseif (STR::len($str) > 100) {
            $error['error'] = 1;
            $error['station'] = "ポッドキャストの名前が100文字以上です";
        }
 

って、elseifでバリデーションを羅列するプログラムの作り方をしているけど、

 

バリデーションの条件で使う、文字列データのチェックの関数があればelseifを使ってバリデーションをチェック出来るので、PHPの標準関数でバリデーション関数があれば、普通にBASICな作り方でウェブのアプリが作れるのでは?

 

って思った

 

標準のfilter関数は使えないんですよね。URLのチェックでスペースや<を調べてないので、正規表現で調べないといけない。それらのバリデーションが標準であれば、普通にウェブのプラグラムが作れるのに

 

ウェブのプログラムは基本、データは文字列変数で、php5では型も無く、基本、文字列変数なので、ウェブのプログラムはほとんど文字列変数の処理を作るのが仕事になるよなと思いながら作っていた

 

あ、unsetの処理は$hoge==""はやめて、empty()へ変更しておこう

 

 

 

 

games.pdbrec.com業務用連絡20190504

ドメインなデータ指向プログラミングでゲームを作る為に、グローバル変数を使わないといけないので、モードのソースコードを一つのpackageとして、命名規則でドメインを分離してC言語な作り方をしてたけど。packageの変数をpublicするとグローバル変数になるのを発見したので

プログラミングのドメインをpackageで分離して、変数をpublic化して、実装を作り直した

バグは変数を変更する時に発生するので、変更を変更するのはメゾットを使ってバグを見つけやすくして、データの読み込みはバグが無いので直接読み込んで見た

あとは、View層を分離して内部状態のモードに合わせた表示するって言うFluxパターンな発想もしてみた

まぁ、プログラミングオタクな部分の作業になるけれど

【追記】

複数のドメインで使うデータは、package regとかでデータベース的なpackageを作って、それぞれのドメインでpackageを読み込ませて変数を使っている。この辺はflixel辺りを調べた時見た技を少し変更してみた




games.pdbrec.com業務連絡20190117

TOWERモードとDIGモードの実装で、テレビゲームらしく見えてきましたよ
(・∀・)





games.pdbrec.com業務連絡20190414

golangでの移植作業は大体出来て、ゲームその物は普通に動いてます

golangはコンパイルが速いので、素早くゲームが作れて良いですよね

そして、新しいルール追加。10秒間動かなかったら、強制的に次のネクストブロックが出てきます

それによって、思考がリセットされるので、なるべく素早く行動しなければいけなくなる

まぁ、ちゃんとゲーム作れてますよ
(`・ω・´)




games.pdbrec.com業務連絡 20190410

とりあえず、

 

-------

package gameos

import (
    "fmt"
    "os"
    "github.com/veandco/go-sdl2/sdl"
    "github.com/veandco/go-sdl2/img"
)

var texture []*sdl.Texture // スライス化

func ImageMake (no int) {
    texture = make([]*sdl.Texture, no)
}

func ImageDelete() {
    for i := range texture {
        if texture[i] != nil {
            texture[i].Destroy()
        }
    }
}

func ImageLoad (no int, imageName string) {
    image, err := img.Load(imageName)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to load PNG: %s\n", err)
        os.Exit(3)
    }
    defer image.Free()
    
    if texture[no] != nil {
        texture[no].Destroy()
    }

    texture[no], err = renderer.CreateTextureFromSurface(image)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create texture: %s\n", err)
        os.Exit(4)
    }
}

func ImageCopy(no int, x int32, y int32, xx int32, yy int32,
                mx int32, my int32, mxx int32, myy int32) {
    
    renderer.Copy(texture[no], &sdl.Rect{x, y, xx, yy}, &sdl.Rect{mx, my, mxx, myy})
}

func ImageCopyFill(no int, x int32, y int32, xx int32, yy int32) {
    
    renderer.Copy(texture[no], nil, &sdl.Rect{x, y, xx, yy})
}

 

 

 

 

-------

Go言語でSDLで画像処理を行うライブラリ

 

Go言語はメモリを押さえてから処理を行うのが普通なので、makeでtextureポインタのスライスのメモリを確保して、スライスへ読み込んで使っている

 

押さえているスライスのメモリを超えてPNG画像を読み込んでもGo言語ではエラーにはならないはず。でも、メモリの押さえ直しとガベージコレクタで処理速度が遅くなるはず

 

SDLの画像処理は基本的にはCopy処理のみなので、MSXのSCREEN5的な処理でゲームを作る。追加出来るとしたらスプライトシート処理だろうな

 

WASMの準備も少し進めた

 

 

 

 

games.pdbrec.com業務連絡 20190408

とりあえず、今日の午前中でGo言語とSDLでシステムがらみの部分が出来て、ゲーム本体を実装出来る状況まで来た

まぁ、ゲーム本体はTypeScriptで作った奴をGo言語へ持ってくれば良いので、すぐ作れる

今回は、プチコンって子供向けゲームを作るアプリっぽく、わざとゲームのプログラムを作っているので、あまりプログラムを見せられない

SDLはウェイト処理をメインループへ埋め込めるので、タイトルモードやゲームモードのプログラムへメインループを埋め込んで、昔らがらの、14歳から始めるゲームプログラミング講座な作り方をして楽しんでいるのだ

まぁ、ドメインプログラミングな作り方で似非タスク処理やオブジェクト指向なタスク処理をしてないので、昔ながらの作り方でも良いってのはあるけれど

次のゲームモードのフラグ建ててゲームループ抜けたら次のゲームモードへ移動して、ゲームエンドフラグ建ててゲームループ抜けたらアプリを落とす処理をするので、プログラムがスマートになるし

やっと、ゲーム本編のプログラムへ進める





games.pdbrec.com業務連絡 20190405

とりあえず、Go言語でのFPS処理は

 

-------

package gameos

import "time"

var fpsTimeThen       int64 = 0
var fpsTimeNow        int64 = 0


func vsyncNowTime() int64 {
    return time.Now().UnixNano()
}

func VsyncInit() {
    fpsTimeThen = vsyncNowTime()
}

func Vsync() {
    if fpsTimeThen == 0 {
        VsyncInit()
    } else {
        // Fps Time.
        var a int64
        a = 0
        if fpsCount % 3 == 0 {
            a = 1
        }
        
        fpsTimeNow = vsyncNowTime()
        
        var fpsWait    int64
        fpsWait = 16666667 - (fpsTimeNow - fpsTimeThen - a)
        
        // Fps Wait.
        if fpsWait > 0 {
            time.Sleep(time.Duration(fpsWait))
        }
        
        // Reset.
        fpsTimeThen = vsyncNowTime()
    }
}
-------

な感じ

 

GolangのsleepはNano秒単位なので、それに合わせて数値も決めています

 

ゲームのパターンってのがあって、なるべく、packageなライブラリの形でゲームのプログラムのパターンをまとめたいので。プチコンのVsyncなライブラリを作ってみました

 

とりあえず、プログラムの実装は続いてます

games.pdbrec.com業務連絡 20190401

お久しぶりです

 

とりあえず、phaser3でのゲーム制作ですが、モード絡みのバグが残っていて動けない

 

ゲームのモードを移動しすぎるとゲームが動かなくなる

 

Phaser3のゲームの作り方のウェブなら、この人、「エマニエル先生」のウェブのプログラムでも、同じ状態を回避する技があって、動くには動くけど、タイトル画面には戻らないでリプレイする回避方法で、それだとモードが選べなくなるので、いろいろと不便なので

 

Go言語でのWindows版の制作を開始します

 

Phaser3のバグが無くなれば、そちらの方も平行作業で続けますが

 

とりあえず、Go言語、久々に使ってみたら

 

・npmなパッケージシステムが増えていた

・キャッシュを使った差分コンパイル対応でコンパイルが速い

 

と、使いやすい。で、とりあえず、XorShiftのライブラリを

 

-------

package gameos

import "time"

var gameosXorshiftSeed uint32 = 3141592653    // Dummy Seed.

func XorshiftSeed() {
    gameosXorshiftSeed = 0
    
    // Seedが0なら再設定
    for gameosXorshiftSeed == 0 {
        gameosXorshiftSeed = uint32(time.Now().UnixNano())
    }
}

func Xorshift() int {
    y := gameosXorshiftSeed
    y = y ^ (y << 13)
    y = y ^ (y >> 17)
    y = y ^ (y << 5)
    gameosXorshiftSeed = y
    return int(y)
}
-------

と作り替え

 

簡単なテストを行って、ちゃんと動いているのを確認した

 

あ、Go言語でSDLを使うのに、変な構造体とかを使う人が多いけど、SDLを扱うpackageを作って、そのpackageでSDLなウインドウを作ったら、普通に、そのpackage内でSDLが使えるので

 

Go言語で普通にゲーム作れますよ!

 

とりあえず、嘘ではない業務連絡でした