phpmvc框架开发入门-代码审计基础学习

1 篇文章 1 订阅
本文档详细介绍了凌云PHP框架的搭建过程,包括核心类的定义、单入口文件、目录结构的创建、配置文件的加载、错误处理、类自动加载、模型类的创建以及数据库操作等。通过一系列的配置和代码编写,实现了框架的基本功能,如用户和管理员模式、配置管理、日志记录、调试模式、错误处理、模型操作等,为后续的Web应用开发提供了基础支持。
摘要由CSDN通过智能技术生成

第一阶段

定义核心类
在这里插入图片描述

在这里插入图片描述
定义单入口,创建所需要的文件夹。
在KUAIXUEPHP下创建index.php
里面载入单入口

<?php
require "./KUAIXUEAPP/KUAIXUEAPP.php";

?>

定义核心类KUAIXUEPHP.php
1.设置常量
2.创建目录
3.载入必须的文件
4.执行应用类

<?php
final class KUAIXUEPHP{
//核心run方法
	public static function run(){
	1.设置常量			self::_set_const();  //定义框架与用户的路径方便以后使用
	2.创建目录   		self::_create_dir();    //自动创建所需目录
	3.载入必须的文件		self::_import_file();   //载入框架所需函数文件和类文件
	4.执行应用类			Application::run();
	}
	
    private static function _set_const(){
        //\WWW\KUAIXUEAPP\KUAIXUEAPP\KUAIXUEAPP.php
        #var_dump(__FILE__);
        $path = str_replace('\\','/',__FILE__);
        define('KUAIXUEPHP_PATH',dirname($path));
        define('CONFIG_PATH',KUAIXUEPHP_PATH. '/Config');
        define('DATA_PATH',KUAIXUEPHP_PATH. '/Data');
        define('TPL_PATH',DATA_PATH.'/Tpl');
        define('LIB_PATH',KUAIXUEPHP_PATH. '/Lib');
        define('CORE_PATH',LIB_PATH. '/Core');
        define('FUNCTION_PATH',LIB_PATH. '/Function');

        define('ROOT_PATH',dirname(KUAIXUEPHP_PATH));
        //ROOT_PATH; D:/phpStudy/PHPTutorial/WWW/KUAIXUEAPP

        //临时目录
        define('TEMP_PATH',ROOT_PATH . '/Temp');
        //日志目录
        define('LOG_PATH',TEMP_PATH.'/Log');


        define('APP_PATH',ROOT_PATH. '/'. APP_NAME);
        define('APP_CONFIG_PATH',APP_PATH.'/Config');
        define('APP_CONTROLLER_PATH',APP_PATH.'/Controller');
        define('APP_TPL_PATH',APP_PATH.'/Tpl');
        define('APP_PUBLIC_PATH',APP_TPL_PATH.'/Public');

        define('KUAIXUEPHP_VERSION','1.0');

    }
        private  static  function _create_dir(){
        //创建一个数组,数组是之前定义的目录路径
        $arr = array(
            APP_PATH,
            APP_CONFIG_PATH,
            APP_CONTROLLER_PATH,
            APP_TPL_PATH,
            APP_PUBLIC_PATH,
            TEMP_PATH,
            LOG_PATH
    );
				//循环数组,判断文件夹是否存在,如果不存在就创建文件夹
        foreach ($arr as $v){
            is_dir($v) || mkdir($v,0777,true);
        }


    private  static function _import_file(){
        $fileArr = array(
            CORE_PATH . '/Log.class.php',
            FUNCTION_PATH . '/function.php',    //调用function函数
            CORE_PATH . '/Controller.class.php',
            CORE_PATH . '/Application.class.php'

        );
        foreach ($fileArr  as $v){
        require_once $v;   //包含文件,require去调用函数文件和类文件

		}
  	}
}
KUAIXUEPHP::run(); //入口处
?>

设置index.php和admin.php两个不同的模式,用户和管理员

admin.php

<?php


define('APP_NAME','Admin');
require "./KUAIXUEAPP/KUAIXUEAPP.php";

index.php

define('APP_NAME','Index');
require "./KUAIXUEAPP/KUAIXUEAPP.php";

APP_NAME分别对应不同的路径,当访问前台时会自动创建。

4.执行应用类

在/Lib/Core目录下创建Application.class.php
在Function目录下创建function.php

final class Application{//Application.class.php
    public static function  run(){
    	p(1);
    }
}
<?php  //function.php
function p($arr){
echo ' <pre>';
print_r($arr);
echo '</pre>';

通过加载文件来执行函数,利用框架的扩展性。

初始化框架准备之C函数

建立框架的Config.php,返回数组

<?php
return array(
    'CODE_LEN' => 4,

    'DEFAULT_TIME_ZONE' => 'PRC',
    'SESSION_AUTO_START' => true,
    'VAR_CONTROLLER'  => 'c',
    'VAR_ACTION'  =>    'a',
    'SAVE_LOG'   => true,
    //错误跳转的地址
    'ERROR_URL'   =>'',
    //错误提示的信息
    'ERROR_MSG' => '网站出错了请稍后再试'
);

建立用户Config,自动建。
核心函数c函数
1.加载配置项Config
2.读取配置项
3.临时动态改变配置项
4.读取所有配置项。

function C($var = NULL , $value = NULL){
    static $config = array();
    //数组的形式进入
    if (is_array($var)){
        $config = array_merge($config,array_change_key_case($var,CASE_UPPER)
        );
        return; //不走下面
    }


    if (is_string($var)){
        $var = strtoupper($var);
        //传递两个参数
        if(!is_null($value)){
            $config[$var] = $value;
            return;
        }


        return isset($config[$var])? $config[$var]:NULL;
    }

    if (is_null($var) && is_null($value)){
        return $config;
    }
}

初始化框架之加载配置项与时区
重新改写Application.class.php

final class Application{//Application.class.php
    public static function  run(){
    	self::_init();  //初始化框架加载配置项与时区
    	self::_set_url();  //设置外部路径
		spl_autoload_register(array(__CLASS__,'_autoload'));		//当有方法实例化时会自动调用					//自动载入
		self::_create_demo();  //创建用户所需文件
		self::_app_run();    //通过get参数实例化应用类
		}
    private static function _init(){
        //加载配置项
        C(include CONFIG_PATH . '/config.php');

        $userPath = CONFIG_INDEX_PATH . '/config.php';   //创建用户所需config文件.

        $userConfig = <<<str
<?php
return array(
    //配置项 => 配置值
);
?>
str;
        is_file($userPath) || file_put_contents($userPath, $userConfig); //判断用户是否有配置项,有就不覆盖,没有就创建。
        //加载用户配置项
        C(include $userPath);

        //设置默认时区
        date_default_timezone_set(C('DEFAULT_TIME_ZONE'));
        //开启session
        C('SESSSION_AUTO_START') && session_start();

    }
    private static function  _set_url(){  //设置外部路径,用来当css,js的变量引用。
        $path = 'http://' . $_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
        $path = str_replace('\\','/',$path);
        define('__APP__',$path);
        define('__ROOT__',dirname(__APP__));

        define('__TPL__',__ROOT__ . '/' . APP_NAME . '/Tpl');
        define('__PUBLIC__',__TPL__.'/Public');

    }


	    private static function _create_demo(){
        $path = APP_CONTROLLER_PATH . '/IndexController.class.php';
        $str = <<<str
<?php 
class IndexController extends Controller{
    public function index(){
    header('Content-type:text/html;charset=utf-8');
    echo '欢迎使用凌云框架(:';
    }
}

str;
        is_file($path) || file_put_contents($path,$str);
    }

    private static function _app_run(){
        $c = isset($_GET[C('VAR_CONTROLLER')])? $_GET[C('VAR_CONTROLLER')] : 'Index';
        $a = isset($_GET[C('VAR_ACTION')])? $_GET[C('VAR_ACTION')] : 'index';
        $c .='Controller';
        $obj = new $c();
        $obj->$a();
    }

}




day10 通过get参数来实现控制类

self::_app_run();
    private static function _app_run(){
        $c = isset($_GET[C('VAR_CONTROLLER')])? $_GET[C('VAR_CONTROLLER')] : 'Index';
        $a = isset($_GET[C('VAR_ACTION')])? $_GET[C('VAR_ACTION')] : 'index';
        $c .='Controller';
        $obj = new $c();
        $obj->$a();
    }

相当于调用不同的控制器,比如说我传入参数c=Arc
在这里插入图片描述
在这里插入图片描述

事实上我们通过控制器来操作不同的类。思想很简单.
在config.php中添加变量c和a
在这里插入图片描述

day13增加初始化方法

在Controller类下

    public function __construct()
    {
        echo '父类必须执行构造方法';
        if (method_exists($this,'__auto')){
            $this -> __auto();
        }
        if (method_exists($this,'__init')){
            $this -> __init();
        }

    }

然后让IndexController.class.php下

    public function __auto(){
        echo '应用Index方法执行';
    }

当子类对象被实例化执行时,先执行父类的__Construct方法。

day14日志函数的编写与理解

在Core文件夹下建立Log.class.php

<?php
/**
 * Created by PhpStorm.
 * User: jing
 * Date: 2021-10-26
 * Time: 20:38
 */

class Log{
    //$msg错误日志信息,$level等级,$type文件保存3,$dest目标
    static public function write($msg,$level='ERROR',$type=3,$dest=NULL){
        if (!C('SAVE_LOG')) return; //如果没有开启不走下面
        if (is_null($dest)){//路径为空的话,定义常量,在框架下建立临时目录/temp/log
                $dest = LOG_PATH . '/' . date('Y_m_d'). ".log";
        }

        if (is_dir(LOG_PATH)) error_log("[TIME]:" .date('Y-m-d H:i:s')."{$level}:{msg}\r\n",$type,$dest);
    }
}
?>

配置Config.php文件加入日志开启的参数

'SAVE_LOG'   => true,

1.定义路径
临时目录存放

//临时目录
define('TEMP_PATH',ROOT_PATH . '/Temp');
//日志目录
define('LOG_PATH',TEMP_PATH.'/Log');

2.创建目录数组中添加他们

    private  static  function _create_dir(){
        $arr = array(
            APP_PATH,
            APP_CONFIG_PATH,
            APP_CONTROLLER_PATH,
            APP_TPL_PATH,
            APP_PUBLIC_PATH,
            TEMP_PATH,
            LOG_PATH
    );

3.error_log函数写入报错信息
如果在目录下存在log文件,那么写入日志报错信息\r\n。

4.最后载入类文件

    private  static function _import_file(){
        $fileArr = array(
            CORE_PATH . '/Log.class.php',
            FUNCTION_PATH . '/function.php',
            CORE_PATH . '/Controller.class.php',
            CORE_PATH . '/Application.class.php'

        );

day15更新debug功能,防止安全隐患

在index.php目录下定义debug功能(默认开启)

define('DEBUG',TRUE);

为了只想在debug时爆错信息出现在网站上,我们增加一个boot.php来临时保存我们的核心类文件比如说Application,Controller,以及Log。所以我们在载入文件方法下增加临时的boot文件

    private  static  function  _import_(){
        //载入类文件和函数
        $file_path = array(
            _Core_. '/Log.class.php',
            _Function_ . '/function.php',
            _Core_ .'/Controller.class.php',
            _Core_ .'/Application.class.php'
        );
        $str = '';  //定义str来存放我们核心代码



        foreach($file_path  as $v){
            $str .= trim(substr(file_get_contents($v),5,-2));  //从第6个字母开始写入到$str
            require_once $v;

        }

        $str = "<?php\r\n" .$str;
        file_put_contents(TEMP_PATH.'/~boot.php',$str)||die('access not allow');    //写入boot临时文件,里面包含了我们所有的核心类
    }

然后在KUAIXUEPHP.php目录下修改类KUAIXUEPHP

final class KUAIXUEPHP {
    public static function run(){
        self::_set_path();
        defined('DEBUG') || define('DEBUG',false);
        if(DEBUG){
            self::_create_dir();   //开启debug正常执行
            self::_import_();
        }else{
            error_reporting(0);   //关闭错误报错到页面,防止安全隐患
            require TEMP_PATH . '/~boot.php';  //如果关闭debug,直接载入临时类文件,不影响程序正常运行
        }
         Application::run();
    }

当我们报错时关闭debug模式
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
没有报错信息出现在首页,防止hacker攻击
当我们开启debug时

在这里插入图片描述
在这里插入图片描述
报错会直接显现在首页,可以帮助使用者进行分析。

day16编写增强打印函数P函数和go跳转函数

重新更新p函数,防止true,null不能输出,在function.php下编写
打印函数

function p($arr){
    if (is_bool($arr)){
        var_dump($arr);
    }else if (is_null($arr)){
        var_dump(NULL);

    }else{
        echo '<pre'. print_r($arr,true).'</pre>';
    }
}

跳转函数

    function go($url,$time=0,$msg=''){  //跳转函数
        if (!headers_sent()){
            $time ==0 ? header('Location:'.$url):header("refresh: {$time};url={$url}");
            die($msg);
        }else{
            echo "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
            if (time) die($msg);
        }
    }

当使用跳转函数时一定要添加http://

day17halt函数与halt页面代码追踪

在function下添加

function halt($error,$level = 'ERROR',$type=3,$dest=NULL){
    if(is_array($error)){
        Log::write($error['message'],$level,$type,$dest);
    }else{
        Log::write($error,$level,$type,$dest);
    }
    $e = array();
    if(DEBUG){
        if (!is_array($error)){  //不是数组的情况
            $trace = debug_backtrace();
            $e['message'] = $error;
            $e['file'] = $trace[0]['file'];
            $e['line'] = $trace[0]['line'];
            $e['class'] = isset($trace[0]['class']) ? $trace[0]['class'] : '';
            $e['function'] = isset($trace[0]['function']) ? $trace[0]['function'] : '';
            ob_start();
            debug_print_backtrace();
            $e['trace'] = htmlspecialchars(ob_get_clean());


    }else{  //数组时的情况
            $e = $error;
        }
    }else{
        if($url = C('ERROR_URL')){
            go($url);
        }else{
            $e['message'] = C('ERROR_MSG');
        }
    }

    include DATA_PATH . '/Tpl/halt.html';
    die;

}

并且导入halt.html
在这里插入图片描述
在config.php下添加两个变量

  //错误跳转的地址
    'ERROR_URL'   =>'',
    //错误提示的信息
    'ERROR_MSG' => '网站出错了请稍后再试'

效果
在这里插入图片描述有thinkphp那点味了。

day18编写display函数加载index目录并且增添assign功能

首先在Tpl下创建Index/index.php

在核心类Application.class.php下加入定义
在这里插入图片描述

  define('CONTROLLER',$c);
  define('ACTION',$a);

使用print_const函数实验效果,在function.php下编写函数

function print_const(){
    $const = get_defined_constants(true);
    p($const['user']);
}

使用函数
在这里插入图片描述
在这里插入图片描述出现我们需要的变量
现在编写display方法
在核心类Controller类下建立方法

protected function display($tpl=NULL){
        if (is_null($tpl)){
            $path = APP_TPL_PATH . '/' . CONTROLLER . '/' . ACTION . '.html';
            #echo $path;
        }else{
            $suffix = strrchr($tpl,'.');
            $tpl = empty($suffix) ? $tpl . '.html' : $tpl;
            $path = APP_TPL_PATH . '/' . CONTROLLER . '/' . $tpl;
        }
        if (!is_file($path)) halt($path . '模板文件不存在');
        #p($this->ver);
        var_dump($this->ver);  //  'var' => string '草泥马' (length=9)
        //肯定是要把indexController中的var加载到这里
        //所以我们使用变量覆盖来覆盖$var

        extract($this->ver);  //变量覆盖后,相当于在display方法下定义$var = 你传入的任意数
        echo $var;
        #var_dump($this->ver);
        include $path;  //加载文件

}

运行display方法,两种情况,如果有index目录,我们直接运行出现结果,如果没有,会使用halt方法进行报错处理.

如果没有
在这里插入图片描述
但是发现我们定义的 v a r 在 i n d e x C o n t r o l l e r 下 确 实 无 法 跟 进 i n d e x . h t m l 目 录 , 根 本 原 因 是 因 为 var在indexController下确实无法跟进index.html目录,根本原因是因为 varindexControllerindex.htmlvar是局部变量,因为display方法下并没有定义$var变量,所以也就无法加载成功,例如
在这里插入图片描述所以我们需要一个方法在运行时加载var变量到display方法下
编写assign方法,在核心类Controller.class.php下
在这里插入图片描述

protected function assign($var,$value){
            $this->ver[$var] = $value;
}

然后在此文件(Controller)下增添一个数组用来接收$var
在这里插入图片描述

private  $ver = array();

思想很明确,assign方法会接收,$var我们打下断点来看一下
在这里插入图片描述
在这里插入图片描述

这里我们可以看出来数组ver里面存储着var的值是CTFer,我们可以使用extract方法来让变量覆盖,因为我们无法直接操控ver数组里面的东西让他等于var,所以我们选择变量覆盖直接覆盖调var,然后就可以直接调用$var
例如

在这里插入图片描述在这里插入图片描述

至此,我们的两个方法就编写完毕,可能变量覆盖哪里的确有点绕.
在这里插入图片描述

day19 定义IS_POST和IS_AXAJ变量

首先写一个表单来进行post登录

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src = "<?php echo __PUBLIC__ ?>/JS/jquery-1.7.2.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $('form').submit(function () {
                $.ajax({
                    url : '<?php echo __APP__ ?>',
                })
            })
        })
    </script>
</head>
<body>
    <form action = "javascript:;" method="post" >
        <input type="text" name="username" id="" />
        <br />
        <input type="password" name="password" id="" />
        <br />
        <input type="submit" value="提交" />
    </form>
</body>
</html>

导入
在这里插入图片描述
然后在IndexController.class.php下打印$_SERVER
在这里插入图片描述
然后通过REQUEST_METHOD来判断post方法还是get方法
在这里插入图片描述

定义IS_POST

define('IS_POST',($_SERVER['REQUEST_METHOD']) == 'POST') ? true : false;

通过异步来判断是否为post传递
我们先看如果是普通的调用
在这里插入图片描述并没有HTTP_X_REQUESTED_WITH这个变量在打印p($_SERVER);时
如果我们通过post点击,然后F12观看返回数据
在这里插入图片描述

出现HTTP_X_REQUESTED_WITH = XMLHttpRequest变量,那么我们就可以通过他来判断IS_AJAX变量

        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
            define('IS_AJAX',true);
            echo IS_AJAX;
        }else{
            define('IS_AJAX',false);
            echo IS_AJAX;
        }

在KUAIXUEAPP.php下添加如上两个变量。

day20创建公共文件夹

在KUAIXUEAPP.php文件中添加以下定义,并添加到_create_dir方法下


        //创建公共
        define('COMMON_PATH', ROOT_PATH . '/Common');
        //公共配置项文件夹
        define('COMMON_CONFIG_PATH',COMMON_PATH . '/Config');
        //公共模型文件夹
        define('COMMON_MODEL_PATH',COMMON_PATH . '/Model');
        //公共库文件夹
        define('COMMON_LIB_PATH',COMMON_PATH . '/Lib');
//创建应用目录
    private  static  function _create_dir(){
        $arr = array(
            COMMON_CONFIG_PATH,
            COMMON_MODEL_PATH,
            COMMON_LIB_PATH,
            APP_PATH,
            APP_CONFIG_PATH,
            APP_CONTROLLER_PATH,
            APP_TPL_PATH,
            APP_PUBLIC_PATH,
            TEMP_PATH,
            LOG_PATH
    );

day21公共配置项功能实现

 private static function _init(){
        C(include CONFIG_PATH . '/config.php'); //载入框架config

        //载入公共文件config
        $commonpath = COMMON_CONFIG_PATH . '/config.php';

        $commonConfig = <<<str
<?php
return array(
        //配置项 =>配置值
);

str;
        is_file($commonpath) || file_put_contents($commonpath,$commonConfig);
        C(include $commonpath);






        $userPath = APP_CONFIG_PATH . '/config.php';

        $userConfig = <<<str
<?php
return array(
        //配置项 =>配置值
);

str;


        is_file($userPath) || file_put_contents($userPath,$userConfig);
        //加载用户配置项
        C(include $userPath);  //载入用户config

        //设置默认时区
        date_default_timezone_get(C('DEFAULT_TIME_ZONE'));

        C('SESSION_AUTO_START')&& session_start();

    }


增添公共配置项的创建

day22用户自定义扩展功能实现

创建如下文件夹
在这里插入图片描述
在这里插入图片描述
在核心类Application.class.php下编写载入公共文件夹函数

    private  static  function _user_import(){
        $fileArr = C('AUTO_LOAD_FILE');
        if (is_array($fileArr) && !empty($fileArr)){
            foreach ($fileArr as $v){
                require_once COMMON_LIB_PATH . '/' . $v;
            }
        }
    }

在这里插入图片描述
效果就是可以使用自定义函数
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

day23-24工具类实现自动载入

在KUAIXUEAPP.php下添加目录
在这里插入图片描述

        define('EXTENDS_PATH',KUAIXUEPHP_PATH. '/Extends');
        define('TOOL_PATH',EXTENDS_PATH. '/Tool');
        define('ORG_PATH',EXTENDS_PATH. '/Org');

创建目录
在这里插入图片描述
Code类下在这里插入图片描述
然后改写载入类的代码
在这里插入图片描述

    private static function _autoload($className){

        switch (true){
            //判断是否为控制器controller控制器
            case strlen($className) > 10 && substr($className, -10) == 'Controller';
                $path = APP_CONTROLLER_PATH . '/' . $className . '.class.php';
                if (!is_file($path)) halt($path . '控制器未找到');
                include $path;
                break;

            default:
                //判断是否为其他类
                $path = TOOL_PATH .'/' . $className . '.class.php';
                echo $path;
                if(!is_file($path)) halt($path . '类未找到');
                include $path;
                break;
        }
        #echo $className;
    }

然后在IndexController下引用
在这里插入图片描述
如果控制器不存在
在这里插入图片描述
如果类不存在
在这里插入图片描述

day25~26空控制器EmptyController

在这里插入图片描述实现用户乱输入,跳转到空控制器
在类加载函数这里进行判断,如果存在则执行,不存在去判断empty是否存在,不存在就执行控制器未找到,存在就包含路径。

    private static function _autoload($className){

        switch (true){
            //判断是否为控制器controller控制器
            case strlen($className) > 10 && substr($className, -10) == 'Controller';
                $path = APP_CONTROLLER_PATH . '/' . $className . '.class.php';
                if (!is_file($path)){
                    $emptyPath = APP_CONTROLLER_PATH . '/EmptyController.class.php';
                    if (is_file($emptyPath)){
                        include $emptyPath;
                        return;
                    }else{
                        halt($path . '控制器未找到');
                    }
                }
                include $path;
                break;

            default:
                //判断是否为其他类
                $path = TOOL_PATH .'/' . $className . '.class.php';
                echo $path;
                if(!is_file($path)) halt($path . '类未找到');
                include $path;
                break;
        }
        #echo $className;
    }

在这里插入图片描述类没有找到

在这里插入图片描述如果直接包含一个没有找到的类文件,一定会爆这个类不存在,
我们可以在这个类实例化前判断类是否存在
然后改写_app_run方法(作用:(通过get参数实例化应用类))在这里插入图片描述判断$c这个类是否存在,存在执行不存在执行EmptyController方法
在这里插入图片描述

        if (class_exists($c)){   //判断c输入的控制器类是否存在,存在就执行
            $obj =  new$c();
            $obj->$a();
        }else{  //不存在就执行空控制器
            $obj = new EmptyController();

如果要是输入参数a,那么我们就需要判断两个,类存在,方法存在,所以继续改写

        if (class_exists($c)){
            $obj = new $c();
            if (!method_exists($obj,$a)){
                if (method_exists($obj, '__empty')){
                    $obj->__empty();
                }else{
                    halt($c . '控制器中' . $a .'方法不存在');
                }
            }else{
                $obj->$a();
            }
        }else{
            $obj = new EmptyController();
            $obj->index();
        }

并且在indexController.class.php下增加方法

    public function __empty(){
        echo 'empty method';
    }

当方法不存在时
在这里插入图片描述

当类不存在时
在这里插入图片描述
当方法和类都不存在时
在这里插入图片描述解决了用户输入错误的提示,使框架更美观

day27-错误处理信息之set_error_handler函数

使用set_error_handler函数来处理错误信息。
我来介绍一下什么是set_error_handler方法
例子

<?php
//error handler function
function customError($errno, $errstr, $errfile, $errline) {
    echo "<b>Custom error:</b> [$errno] $errstr<br />";
    echo "Error on line $errline in $errfile<br />";
    echo "Ending Script";
    die();
}
 
//set error handler
set_error_handler("customError");
 
$test=2;
 
//trigger error
if ($test > 1) {
    trigger_error("A custom error has been triggered");
}
?>

在这里插入图片描述
需要注意的是:

set_error_handler(“customError”) 不仅可以接受函数,还可以接受 类的方法(公开的静态方法 及 公开的非静态方法 都可以),但需要以 数组形式 传递,数组的第一值为“类名”,第二个参数为“方法名”,如下代码所示:

<?php
class App{
    //error handler function
    public  static function customError($errno, $errstr, $errfile, $errline) {
        echo "<b>Custom error:</b> [$errno] $errstr<br />";
        echo "Error on line $errline in $errfile<br />";
        echo "Ending Script";
        die();
    }
}
 
//set error handler
set_error_handler(array("App","customError"));
 
$test=2;
 
//trigger error
if ($test > 1) {
    trigger_error("A custom error has been triggered");
}
?>

在这里插入图片描述
在这里插入图片描述
他的四个参数含义:

  • $errno 错误编号
  • $errstr 错误消息
  • $errfile 错误所在的文件
  • $errline 错误所在的行

我们来尝试写这个方法,首先在核心类application下
在这里插入图片描述然后编写error方法

    public static function error($errno , $error , $file, $line){
        switch ($errno){
            case E_STRICT:
            case E_USER_WARNING:
            case E_USER_NOTICE:
            default:
                if(DEBUG){
                    include DATA_PATH . '/Tpl/notice.html';
                }
                break;
        }
    }

notice.html

<style type="text/css">
    div.hdphp_notice {
        border : 1px solid #990000;
        font-family: Monaco,Menlo,Consolas,"Courier New",monospace;
        padding-left: 20px;
        margin: 10px;
    }

    div.hdphp_notice h3{
        font-size: 18px;
        margin: 20px 0;
    }

    div.hdphp_notice p {
        font-size: 14px;
        margin: 15px 0;
    }
</style>
<div class="hdphp_notice">
    <h3 style="font-size : 18px;"><?php echo $error ?></h3>

    <p>
        Serverity: <?php echo $errno?>
    </p>

    <p>
        File: <?php echo $file ?>
    </p>

    <p>
        Line:  <?php echo $line ?>
    </p>
    <p style="coler:#099">
        KUAIXUEPHP开源框架 版本: <?php echo KUAIXUEPHP_VERSION ?>
    </p>
</div>

尝试报错,看结果
在这里插入图片描述如果是致命错误,那么这个方法也是无法执行,我们需要编写另外一个防止致命错误的方法

register_shutdown_function方法

register_shutdown_function这个函数是在PHP程序运行结束之前调用的,用这个函数可以做很多,比如调用运行发生致命错误中止的原因,或者调试程序的执行时间等。

final class Application{
    public static function  run(){
       self::_init();  //初始化框架

        set_error_handler(array(__CLASS__,'error'));
        register_shutdown_function(array(__CLASS__,'fatal_error'));
       self::_user_import();
       self::_set_url();
       spl_autoload_register(array(__CLASS__,'_autoload'));
        self::_create_demo();
        self::_app_run();


    }


    public static function fatal_error(){
    }

我们来看一下error_get_last()函数

    public static function fatal_error(){
        if ($e = error_get_last()){
            var_dump($e);
        }
    }

当发生致命错误时,结束前执行register_shutdown_function方法,然后调用
error_get_last()函数

[type] - 描述错误类型
[message] - 描述错误消息
[file] - 描述发生错误的文件
[line] - 描述发生错误的行号

在这里插入图片描述
我们改写出错方法,当致命错误时进入halt函数内。
如何来分辨什么是致命错误呢,什么是非致命错误呢???
我们根据$erron的数值也就是编号来分辨

非致命错误时,错误编号为2

在这里插入图片描述
致命错误时,错误编号为4
在这里插入图片描述
那我们重新改写error方法

    public static function error($errno , $error , $file, $line){
        switch ($errno){

            case E_ERROR:    //默认为1
            case E_PARSE:			//4
            case E_CORE_ERROR:   //8
            case E_COMPILE_ERROR:  //16
            case E_USER_ERROR:    //32
                $msg = $error . $file . "第{$line}行";
                halt($msg);
                break;



            case E_STRICT:     
            case E_USER_WARNING:    //512
            case E_USER_NOTICE:
            default:
                if(DEBUG){
                    include DATA_PATH . '/Tpl/notice.html';
                }
                break;
        }
    }

当再次进入错误方法时的四个参数如下:
在这里插入图片描述并且致命错误页面与非致命错误页面返回不同

致命错误页面:

在这里插入图片描述启用halt方法,并且计入日志
在这里插入图片描述

非致命错误页面

在这里插入图片描述不计入日志

day28-模型类之连接数据库

我们需要编写一个模型类来操作数据库,然后只需要在C函数中调用参数即可,不用修改框架。
新建Model.class.php
在这里插入图片描述

使用all函数去查询数据库里的表

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021-11-18
 * Time: 19:01
 */

class Model{
    //保存连接信息
    public static $link = NULL;
    //保存表名
    protected $table = NULL;
    //初始化表信息
    private $opt;
    //记录发送的sql
    public static $sqls = array();

    public function __construct($table=NULL){
        $this->table = is_null($table) ? C('DB_PREFIX') . $this->table : C('DB_PREFIX') .$table;
        //连接数据库
        $this->_connect();
        //初始化sql信息
        $this->_opt();
    }


    public function query($sql){
        self::$sqls[] = $sql;
        $link = self::$link;
        $result = $link->query($sql);
        if($link->errno) halt('mysql错误 ' . $link->error . '<br/>SQL:' .$sql );

        $row = array();
        while($row = $result -> fetch_assoc()){
            $rows[] = $row;
        }
        $result -> free();
        $this->_opt();
        return $rows;
    }

    public function all(){
        $sql = "SELECT " . $this->opt['field'] .  " FROM " . $this->table . $this->opt['where'] . $this->opt['group'] . $this->opt['having'] . $this->opt['order'] . $this->opt['limit'];

        return $this->query($sql);
    }


    private function _opt(){
        $this->opt = array(
            'field' => '*',
            'where' =>'',
            'group' => '',
            'having' => '',
            'order' => '',
            'limit' => ''
        );
    }

    /**
     * _connect连接
     */

    private function _connect(){
        if (is_null(self::$link)){
            $db = C('DB_DATABASE');
            if (empty($db)) halt('请先配置数据库');
            $link = new Mysqli(C('DB_HOST'),C('DB_USER'),C('DB_PASSWORD'),$db,C('DB_PORT'));
            if ($link->connect_error) halt('数据库连接错误,请检查配置项');
            $link->set_charset(C('DB_CHARSET'));
            self::$link = $link;
        }
    }

}

?>

config.php下

<?php
return array(
        //配置项 =>配置值
    'DB_CHARSET' => 'utf-8',
    'DB_HOST'    => '127.0.0.1',
    'DB_PORT'    => '3306',
    'DB_USER'    => 'root',
    'DB_PASSWORD' => 'root',
    'DB_DATABASE' => 'db2',
    'DB_PREFIX'   =>''
);

在入口处调用Model类(使用all函数去查询数据库里的表)

<?php 
class IndexController extends Controller{
    public function index(){
            $obj = new Model('account');
            $data = $obj->all();
            var_dump($data);
    }
}

当密码错误时会报错
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值