TPP:一个简单的PHP框架


#博客


2013-12-04

TPP是一个基于PHP的web框架,使用了MVC模式以支持快速开发。该框架源自于之前写的tinierPHP2 (给自己写一个 PHP 框架 (2))。tinierPHP2是web框架的一个实验项目,限于各种原因,没有进行优化。TPP是对tinierPHP2的重写,并使用了新的名称。TPP进行了大量的重新设计,架构更为清晰,代码也更加整洁。不过TPP仍然保持着简单的原则,以求给予开发者最大的灵活性。

项目地址:https://github.com/letiantian/TPP

新的文件布局

其实改动很小:

.
├── Controller
│   ├── error.php
│   └── welcome.php
├── Core
│   ├── tpp_config.php
│   ├── TPP_Index.php
│   ├── TPP_Loader.php
│   └── TPP.php
├── Corelib
│   ├── Medoo.php
│   └── Render.php
├── index.php
├── static
│   ├── bootstrap3
│   │   ├── css
│   │   │   ├── bootstrap.css
│   │   │   ├── bootstrap.min.css
│   │   │   ├── bootstrap-theme.css
│   │   │   └── bootstrap-theme.min.css
│   │   ├── fonts
│   │   │   ├── glyphicons-halflings-regular.eot
│   │   │   ├── glyphicons-halflings-regular.svg
│   │   │   ├── glyphicons-halflings-regular.ttf
│   │   │   └── glyphicons-halflings-regular.woff
│   │   └── js
│   │       ├── bootstrap.js
│   │       └── bootstrap.min.js
│   └── jquery-1.10.2.min.js
├── Template
│   └── error
│       └── 404.php
└── Userlib

新的变化

去除./Corelib/Rcache.php: Rcache.php是一个简单的用Reids作缓存的类,但是类实现的功能过于简单,且未经测试,故去除之。

去除tinierPHP2中的Config目录: 该目录被重命名为Core,其内的文件名也以TPP或者tpp开头。

新的配置方案: url路由(或者说url映射)在./Core/tpp_config.php中配置($url_maps),tpp_config.php中也可以配置基本url($tpp_base_url)、默认控制器($tpp_default_controller)、控制器的默认方法($tpp_default_method)、是否因为在浏览器中显示异常($tpp_show_error)、404页面位置($tpp_404_page)。 $tpp_base_url相当于tinierPHP2中./Config/Config.php文件中的$_site_url。现在的$tpp_base_url的值可以设为'http://127.0.0.1/'、'http://127.0.0.1/tinierPHP2/'、'/tinierPHP2/'、'/tinierPHP2' 、 'tinierPHP2' 、 'tinierPHP2/' 这些形式,./Core/TPP.php中的tpp_base_url()方法将根据配置而返回更使用的base_url,例如若配置$tpp_base_url为'tinierPHP2',tpp_base_url()将返回'/tinierPHP2/'。

控制器类 控制器类应继承TPP类,./Core/TPP类中实现了tpp_loader()方法,所以现在可以使用在控制器中使用this来使用类加载器(./Core/TPP_Loader)。 控制器的类名和文件名必须相同。TPP中不会修改根据url去加载控制器类的时候不会改变url的大小写,控制器的命名和url的关联更显而易见。我们可以看到./Controller/welcome.php内容如下:

<?php
/*
 * Default controller
 */
class welcome extends TPP
{

    public function index()
    {
        echo 'hello, I am TPP';
    }
    public function hello()
    {
        echo 'hello, I am TPP';
    }
}

控制器中的函数的传参机制也进行了修改。假定./Core/tpp_config.php中$url_maps为空,$tpp_base_url为''(即TPP项目在web server的根目录里),如果url为http://127.0.0.1/welcome/hi/1/2,我们会创建控制器welcome的新的对象,调用hi方法的现行形式是hi('1','2'),而非hi(['1','2'])。

./Corelib/Medoo.php Medoo.php和Medoo项目中的版本更为接近,只是将构造函数更名为connect函数,构造函数被置空了。当然,TPP中Corelib和Userlib中的类不允许带参数的构造函数。

./Corelib/Render.php新增匿名函数 在Render类的render()方法中新增了匿名函数$tpp_base_url,这样就可以在视图中使用$tpp_base_url()获取基本url,方便开发。

实战:使用TPP做一个简单的登录系统

在mysql5中的test库下建立表users

CREATE  TABLE `test`.`users` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `name` VARCHAR(45) NOT NULL ,
  `email` VARCHAR(45) NOT NULL ,
  `passwd` VARCHAR(45) NOT NULL ,
  PRIMARY KEY (`id`) ,
  UNIQUE INDEX `name_UNIQUE` (`name` ASC) )
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci;

主键是id字段,name字段内容具有唯一性约束。

添加一组数据,用户名为a,email为aaa@163.com,密码aaa。图个方便,密码明文存储。

将TPP放在/var/www中,TPP的配置不变。

创建文件./Userlib/userstate.php:

<?php

class userstate extends TPP{

    public function is_login() {
        if (isset($_SESSION['user_name'])) {
            return true;
        }
        else {
            return false;
        }
    }

    public function login($user_name, $user_passwd) {
        $db = $this->tpp_loader()->load_core_class('Medoo');
        $db->connect([
            'database_type' => 'mysql',
            'database_name' => 'test',
            'server' => 'localhost',
            'username' => 'root',
            'password' => '123']);
        $sql = "select * from users where name =".$db->quote($user_name)." and passwd=".$db->quote($user_passwd).";";
        //$datas = $db->select("users","*");
        $datas = $db->query($sql)->fetchAll();
       if(count($datas) >= 1) {
           $_SESSION['user_name'] = $user_name;
           return true;
       }
        else {
            return false;
        }
    }

    public function logout() {
        unset($_SESSION['user_name']);
        return true;
    }

    public function  get_user_name() {
        return $_SESSION['user_name'];
    }
}

session会在控制器文件中启动,所以该文件中也就没有session_start()。SESSION只存储用户名user_nameis_login()函数判断是否已经登录。login($user_name, $user_passwd)函数提供登录功能,登录成功则返回true,否则false。logout()函数提供退出功能。get_user_name()函数获取登录用户的名字。

创建文件./Controller/usermanager.php:

<?php

class usermanage extends TPP {

    public function __construct() {
        session_start();  
        $this->userstate = $this->tpp_loader()->load_user_class('userstate');
    }

    public function index() {
        if($this->userstate->is_login()) {
            header("Location: /usermanage/show");
        }
        else {
            header("Location: /usermanage/login");
        }
    }

    public function login() {
        if($this->userstate->is_login()) {
            $this->show();
            return;
        }
        if(isset($_POST['user_name']) && isset($_POST['user_passwd'])) {
            if ($this->userstate->login($_POST['user_name'], $_POST['user_passwd'])) {
                $this->show();
                return ;
            }
        }

        $render = $this->tpp_loader()->load_core_class('Render');
        $render->render('usermanage/header',['title'=>'登录']);
        $render->render('usermanage/login_body',['welcome'=>'登录']);
        $render->render('usermanage/footer', null);
        $render->show();

    }

    public function logout() {
        $this->userstate->logout();
        header("Location: /usermanage/index"); 
        exit;
    }

    public function show() {
        if($this->userstate->is_login() === false) {
            header("Location: /usermanage/login");
            return;
        }
        $render = $this->tpp_loader()->load_core_class('Render');
        $render->render('usermanage/header',['title'=>'主页']);
        $render->render('usermanage/show_body',['user_name'=>$this->userstate->get_user_name()]);
        $render->render('usermanage/footer', null);
        $render->show();
    }
} 

在构造函数中启动了session,同时生成./Userlib/userstate.php中userstate类的实例$this->userstate。login()函数为用户展示登录页。在登录成功后,跳转到show()生成的页面中。函数logout()提供退出功能。index()函数根据用户是否登录选择跳转到login()或者show()。

建立视图文件:

./Template/usermanager/header.php文件内容如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title><?=$title;?></title>

    <script src="<?=$tpp_base_url();?>static/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script src="<?=$tpp_base_url();?>static/bootstrap3/js/bootstrap.min.js" type="text/javascript"></script>
    <link href="<?=$tpp_base_url();?>static/bootstrap3/css/bootstrap.min.css" rel="stylesheet">

    <style>
        .user_margin {
            height: 20px;
            width: 100%;
        }
    </style>
</head>
<body>

由于TPP配置不变,$tpp_base_url()的结果是'/'。

./Template/usermanager/login_body.php文件内容如下:

<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4 ">
        <div class="user_margin"></div>

        <h2><?=$welcome;?></h2>

        <div class="user_margin"></div>
        <form role="form" method="POST" action="/usermanage/login">
            <div class="form-group">
                <label>用户名</label>
                <input type="text" class="form-control"  placeholder="Enter name" name="user_name">
            </div>
            <div class="form-group">
                <label>密码</label>
                <input type="password" class="form-control" placeholder="Password" name="user_passwd">
            </div>
            <button type="submit" class="btn btn-default">登录</button>
        </form>
        <div class="user_margin"></div>
    </div>
    <div class="col-md-4"></div>
</div>

./Template/usermanager/show_body.php文件内容如下:

<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4 ">
        <div class="user_margin"></div>

        <h2>你好,<?=$user_name;?></h2>

        <a class="btn" href="/usermanage/logout">注销</a>

    </div>
    <div class="col-md-4"></div>
</div>

./Template/usermanager/footer.php文件内容如下:

</body>
</html>

效果图

输入http://127.0.0.1/usermanage/,则跳转到登录页面http://127.0.0.1/usermanage/login,如下:

填写用户名a和密码aaa,进入show页面:



( 本文完 )