0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHPフレームワーク「OFFWORK 5.2」

Last updated at Posted at 2019-08-04

###経緯
PHPでアプリケーションフレームワーク的なものができたので、公開します。
現在100行程度のindex.phpですが、磨けば、ミニマリスト、シンプリスト、プリミティビスト、学習者、など、一部の方のお役に立つかもしれないと、妄想しています。
「OFFWORK」と名付けました(語源:One File Frame Work)。

###動作概要
「~/index.php/{コントロール名}/{アクション名}/{パラメータ}」の形式のURLでアクセスします。./controllers/{コントロール名}.phpの中にあるclass {コントローラ名}のfunction {アクション名}が呼ばれ処理した後、./views/{コントロール名}_{アクション名}.phpが呼ばれ画面を作成します。functionの戻り値配列に"controller"か"view"があれば、画面作成のPHPを変更します。functionの戻り値配列に"redirect"があれば、リダイレクトを行います。「_」から始まるコントローラ名とアクション名は、URLから呼び出されません。

モデルのクラスは、class _{テーブル名} extends model を推奨します。_{テーブル名}.phpのファイルを作り、コントローラからrequire_onceしても構いませんが、コントローラのファイルの中にモデルのコードを書くと(小さいプログラムの場合)見通しが良いかも知れません。複数形/単数形、キャメルケース/スネークケース、などの命名規則は定めていません。

###実装例
フルームワークの本体はindex,phpのみです。他の4つのファイルuser*.phpはサンプルです。保存する際はutf8を指定してください。「********」の箇所はDB接続の設定に書き換えてください。

./index.php
<?php
    session_start();
    ini_set('error_reporting', E_ALL);
    ini_set('display_errors', '1');
    $DSN="mysql:host=********;dbname=********;charset=utf8mb4";
    $DB_USERNAME="********";
    $DB_PASSWORD="********";
    $SESSION_NAME="APP1";
    @include("./local.php");//load local setting
    //----------
    class Model{
        protected $db;
        public function __construct(){
            global $DSN,$DB_USERNAME,$DB_PASSWORD;
            try{
                $options = array(
                    PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_EMULATE_PREPARES=>false,
                    PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
                    PDO::MYSQL_ATTR_INIT_COMMAND=>"SET CHARACTER SET 'utf8'");
                $this->db=new PDO($DSN,$DB_USERNAME,$DB_PASSWORD,$options);
            }catch(PDDOException $e){$this->exit500($e->getMessage());}
        }
        function executeQuery($sql,$vars,$fetchable=false){

            try{
                $stmt=$this->db->prepare($sql);
                $result=$stmt->execute($vars);
                if($fetchable==true){
                    $data=$stmt->fetchall();

					// key<-id
                    if(isset($data[0]['id'])){
                    	$tmp=array();
	                    $flag=true;
                    	foreach($data as $ele){
                    		if(isset($tmp[$ele['id']])){
                    			$tmp[$ele['id']]=$tmp[$ele['id']]+1;
                    		}else{
                    			$tmp[$ele['id']]=1;
                    		}
                    		if($tmp[$ele['id']]>1){$flag=false;}
                    	}
                    	if($flag==true){
	                        $data=array_column($data, null, 'id');
	                    }
                    }

                    return array("data"=>array(get_class($this)=>$data),"return"=>$result,"count"=>$stmt->rowCount());
                }else{
                    return array("return"=>$result,"count"=>$stmt->rowCount());
                }
            }catch(PDDOException $e){$this->exit500($e->getMessage());}
        }
        function exit500($msg){
            header('Content-Type: text/plain; charset=UTF-8', true, 500);
            exit(h($msg));
        }
    }
    function h($s){
        return htmlspecialchars($s,ENT_QUOTES,'UTF-8');
    }
    function redirect($s){
        $tmp=$_SERVER["HTTP_ORIGIN"].$_SERVER["SCRIPT_NAME"].$s;
        header('Location: '.$tmp);
        exit;
    }
    //session----------
    function _login($value){
        global $SESSION_NAME;
        session_regenerate_id(true);
        $_SESSION[$SESSION_NAME]=$value;
    }
    function _logout(){
        global $SESSION_NAME;
        unset($_SESSION[$SESSION_NAME]);
        //session_destroy();
    }
    function _verify_login($exitto){
        global $SESSION_NAME;
        if(isset($_SESSION[$SESSION_NAME])){return;}
        redirect($exitto);
    }
    //paramaters----------
    $controller="";$action="";$para=array();$msg=array();$fname="";
    if (!empty($_SERVER['PATH_INFO'])) {
        $para=explode('/',$_SERVER['PATH_INFO']);
        $controller=array_shift($para);if($controller==""){$controller=array_shift($para);}
        $action=array_shift($para);
    }
    //action----------
    function getControllerFileName($controller){
		return "./controllers/".basename($controller).".php";
		//return "./".basename($controller).".php";
	}
    function getViewFileName($controller,$view){
		return "./views/".basename($controller)."_".basename($view).".php";
		//return "./".basename($controller)."_".basename($view).".php";
	}
	{
        //controller&action----------
        $fname=getControllerFileName($controller);
        if($controller==""||substr($controller,0,1)=="_"){
        	$msg[]="No controller specified.";
        }elseif(file_exists($fname)){
            include($fname);
            if(class_exists($controller)){
                $class = new $controller();
		        if($action==""||substr($action,0,1)=="_"){
		        	$msg[]="No action specified in the class [".h($controller)."] .";
		        }elseif(method_exists($class,$action)){
                    $d=$class->$action($para);
                    if(!is_array($d)){$d=array($d);}
                }else{$msg[]="method [".h($action)."()] not found in the class [".h($controller)."] .";}
            }else{$msg[]="class [".h($controller)."] not found.";}
        }else{$msg[]="file [".h($fname)."] not found.";}
        //redirect----------
        if(isset($d['redirect'])){redirect($d['redirect']);}
        //view----------
        if(isset($d["cntroller"])){$controller=$d["cntroller"];}
        $view=$action;if(isset($d["view"])){$view=$d["view"];}
        $fname=getViewFileName($controller,$view);
    }
    if($controller==""||$action==""||substr($controller,0,1)=="_"||substr($action,0,1)=="_"){
    }elseif(!file_exists($fname)){$msg[]="view file [".h($fname)."] not found.";}
    //drawing----------
    header('Content-Type: text/html; charset=utf-8');
    header('X-FRAME-OPTIONS: SAMEORIGIN');
    foreach($msg as $x){echo $x."<br>";}
    if(file_exists($fname)){include($fname);}
// PHP frame work "offwork 5.2" made by arigato2050
./controllers/user.php
<?php
class user{
    function login(){
        $msg="";
        if(isset($_REQUEST["username"])&&isset($_REQUEST["password"])){
            $_user=new _user();
            $result=$_user->check($_REQUEST["username"],$_REQUEST["password"]);
            if(count($result['_user'])==1){
                _login(current($result['_user']));
                return array("redirect"=>"/user/index");
            }else{$msg="usernameまたはpasswordが異なります";}
        }
        $username="";if(isset($_REQUEST["username"])){$username=$_REQUEST["username"];}
        return array("data"=>array("_user"=>array("username"=>$username,"password"=>"")),"msg"=>$msg);
    }
    function logout(){
        _logout();
        return array("redirect"=>"/user/login");
    }
    function index(){
        _verify_login("/user/login");
        $_user=new _user();
        $result=$_user->getAll();
        return array("data"=>$result);
    }
    function add(){
        _verify_login("/user/login");
        return array("view"=>"edit","data"=>array('_user'=>array(0=>array("id"=>0,"username"=>"","password"=>""))));
    }
    function edit($para){
        _verify_login("/user/login");
        $_user=new _user();
        $result=$_user->get1($para[0]);
        return array("data"=>$result);
    }
    function save($para){
        _verify_login("/user/login");
        $_user=new _user();
        $result=$_user->set1($_REQUEST);
        return array("redirect"=>"/user/index","data"=>$result);
    }
    function del($para){
        _verify_login("/user/login");
        $_user=new _user();
        $result=$_user->del1($para[0]);
        return array("redirect"=>"/user/index","data"=>$result);
    }
}
class _user extends Model{
    function getAll(){
        $result=$this->executeQuery("SELECT * FROM user;",array(),true);
        return $result['data'];
    }
    function check($username,$password){
        $result=$this->executeQuery("SELECT * FROM user WHERE username=:username and password=:password;",array(":username"=>$username,":password"=>$password),true);
        return $result['data'];
    }
    function get1($id){
        $result=$this->executeQuery("SELECT * FROM user WHERE id=:id;",array(":id"=>$id),true);
        return $result['data'];
    }
    function del1($id){
        $result=$this->executeQuery("DELETE FROM user WHERE id=:id;",array(":id"=>$id));
        return $result['data'];
    }
    function set1($para){
        if($para['id']==0){
            $result=$this->executeQuery("INSERT INTO user (username,password,created) VALUES (:username,:password,:created);",array(":username"=>$para['username'],":password"=>$para['password'],":created"=>date("Y/m/d H:i:s")));
        }else{
            $result=$this->executeQuery("UPDATE user SET username=:username, password=:password, modified=:modified WHERE id=:id;",array(":id"=>$para['id'],":username"=>$para['username'],":password"=>$para['password'],":modified"=>date("Y/m/d H:i:s")));
        }
        return $result['data'];
    }
}
/*
サンプルのDBは以下です。`id`は主キーかつAUTO_INCREMENTです。ログイン用のusername/passwordを登録してからお使いください。
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `username` text,
  `password` text,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
*/
./views/user_login.php
<!DOCTYPE html>
<html>
<body>
<h1>login</h1>
<form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/login/'; ?>" method="post">
username:<input type="text" name="username" value="<?php echo h($d['data']['_user']['username']); ?>"><br>
password:<input type="password" name="password" value="<?php echo h($d['data']['_user']['password']); ?>"><br>
<input type="submit" value="送信">
</form>
<?php echo $d["msg"]; ?><br>
<?php if($d["msg"]>""){echo date("Y/m/d H:i:s")."<br>";} ?>
</body>
</html>
./views/user_index.php
<!DOCTYPE html>
<html>
<body>
<h1>index</h1>
<table border=1>
<tr>
<th>id</th>
<th>username</th>
<th>password</th>
<th>created</th>
<th>modified</th>
</tr>
<?php
    foreach($d['data']['_user'] as $row  ){
        echo "<tr>";
?>
<td><a href="<?php echo $_SERVER['SCRIPT_NAME'].'/user/edit/'.h($row['id']); ?>"><?php echo h($row['id']); ?></a></td>
<td><?php echo h($row['username']); ?></td>
<td><?php echo h($row['password']); ?></td>
<td><?php echo h($row['created']); ?></td>
<td><?php echo h($row['modified']); ?></td>
<?php
        echo "<tr>";
    }
?>
</table>
<form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/add/'; ?>" method="post">
<input type="submit" value="追加">
</form>
<br>
<form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/logout/'; ?>" method="post">
<input type="submit" value="ログアウト">
</form>
<!--
<br>cookie:<br>
<?php var_dump($_COOKIE); ?>
<br>session:<br>
<?php var_dump($_SESSION); ?>
-->
</body>
</html>
./views/user_edit.php
<!DOCTYPE html>
<html>
<body>
<h1>edit</h1>
id:<?php
    if(current($d['data']['_user'])['id']==0){
        echo "(new)";
    }else{
        echo h(current($d['data']['_user'])['id']);
    }
?>
<form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/save/'; ?>" method="post">
<input type="hidden" name="id" value="<?php echo h(current($d['data']['_user'])['id']); ?>">
username:<input type="text" name="username" value="<?php echo h(current($d['data']['_user'])['username']); ?>"><br>
password:<input type="text" name="password" value="<?php echo h(current($d['data']['_user'])['password']); ?>"><br>
<input type="submit" value="送信">
</form>
<form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/index/'; ?>" method="post">
<input type="submit" value="キャンセル">
</form>
<?php if(current($d['data']['_user'])['id']!=0){ ?>
    <br>
    <form action="<?php echo $_SERVER['SCRIPT_NAME'].'/user/del/'.h(current($d['data']['_user'])['id']); ?>" method="post">
    <input type="submit" value="削除">
    </form>
<?php } ?>
</body>
</html>

###実行例

[URL]http://~/index.php/user/login
20190805login.png

[URL]http://~/index.php/user/index
20190805index.png

[URL]http://~/index.php/user/edit/7
20190805edit.png

###参考

参考にさせていただきました。
https://qiita.com/kahirokunn/items/175b82295ab683ffb624
http://choilog.com/katty0324/blog/6
https://qiita.com/mitsuru793/items/45b2452284e321c7a5a9
https://qiita.com/mpyw/items/b00b72c5c95aac573b71
https://qiita.com/7968/items/6f089fec8dde676abb5b
https://qiita.com/t_kawai/items/ed5e86c32966931c8e9b

0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?