前言 抽空了解了一下PDO预编译和MVC结构基础东西,记录一下。
PDO 简介 PDO是PHP的一个轻量级的接口,使得访问和操作数据库得以简便。它使得访问多种数据库(除了mysql)可以用相同的方法。
同时正确使用它的预编译,可以有效防止sql注入。它的基本使用语法也比较简便。
语法 在使用PDO之前,应该需要做相应的配置(这个配置方法可以自行百度),这里简单对PDO的常见语法做一个梳理。
创建PDO对象
1 2 3 4 5 6 7 8 9 10 11 <?php $dsn ='mysql:dbname=test;host=127.0.0.1;charset=utf-8' ;$user ='root' ;$password ='root' ;try { $pdo =new PDO ($dsn ,$user ,$password ); } catch (PDOException $e ){ echo 'Connection failed: ' .$e ->getMessage (); }
常用方法
exec()方法 –执行sql语句,并返回被修改或者被删除的SQL语句影响的行数(int)
1 2 3 4 <?php $sql ="INSERT INTO USER (id,name) VALUES (1,'My0n9s')" ;$rel =$pdo ->exec ($sql );
query()方法 –执行SQL语句,但是返回的是一个结果集对象(PDOstatement)
1 2 3 <?php $sql ="SELECT * FROM user ORDERY BY id DESC" ;$rel =$pdo ->query ($sql );
fetch()方法 – 从结果集中获取一行,并向下移动指针
1 2 3 4 5 6 7 <?php $sql ="SELECT * FROM user ORDER BY id DESC" ;$stmt =$pdo ->query ($sql );while ($rel =$stmt ->fetch (PDO::FETCH_ASSOC )){ var_dump ($rel ); }
fetchALL()方法–返回一个结果集的所有数组
1 2 3 4 5 <?php $sql ="SELECT * FROM user ORDER BY id DESC" ;$stmt =$pdo ->query ($sql );$rel =$stmt ->fetchALL (PDO::FETCH_ASSOC );var_dump ($rel );
预编译 概念 PDO有两种模式,一种是本地预处理,一种是模拟预处理,模拟预处理用于数据库不支持预编译的情况,其实它并没有做到真正的预编译,其本质也是转义用户输入的数据,如果编码设置不规范,就存在宽字节注入的风险,而本地预处理,只要使用规范,可以从本质上去防止SQL注入。
浅谈原理 预编译为什么能做到防注入?
从预编译的运行机制说起,通常,以Mysql为例,一条SQL语句从传入到执行经历一下几个过程:
检查缓存
规则验证
解析器解析为语法树
预处理器进一步优化语法树
优化SQL
生成执行计划
执行
PDO完成预处里需要的步骤
提取相同结构的sql部分(把数据部分,可变部分进行去除)
编译相同的结构,并把编译结果保存
把不同的数据部分进行替换
执行sql
提取相同结构的sql语句
在sql语句中,使用命名参数和问号参数,来代替可变的数据
使用占位符“:value”和”?”来代替可变的数据
来看两条语句:
select * from user where id=1 和 select * from users where id=2 ,这两条语句语法结构是差不多的,区别只在于后面的id的字段值,预编译就是把相同的语法部分拿过去先编译,构建语法树,最后再去传字段值,做到数据和代码进行了一个分离。 从而有效的防止了SQL注入
语法 简单的Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php $dsn ='mysql:dbname=test;host=127.0.0.1;charset=utf8' ; $user ='root' ; $password ='root' ; try { $pdo =new PDO ($dsn ,$user ,$password ); $sql ="INSERT INTO USER(id,name)VALUES(:id,:name)" ; $stmt =$pdo ->prepare ($sql ); $stmt ->bindValue (':id' ,1 ) $stmt ->bindValue (':name' ,'My0n9s' ); $rel =$stmt ->execute (); } catch (PDOException $e ){ echo "Connection faile:" .$e ->getMessage (); echo "错误行号:" .$e ->getCode (); echo "错误行号:" .$e ->getLine (); }
MVC 写在前面 很早就听说MVC,并且在AWD中也接触到了MVC结构的框架,然后一直都是一头雾水,好吧,其实包括现在对MVC的理解也没有很透彻,不过大抵是比之前要好些了。这里参考了feng师傅发给我的一篇文章。
简介 MVC是编程的一种架构,一种规范,使得业务逻辑、数据、视图三者做到了一个分离,后期也便于扩展。
M指的是Model(模型),这里主要是对数据进行处理,和数据库进行一个交互。
V指的是View (视图),最后呈现给用户的界面,一般来说,视图是依据模型数据创立的。
C指的是Controller(控制器),处理和用户交互的部分,个人觉得像是一个指挥官的角色。
关于三者的关系,有一个图很形象的进行了呈现:
小型的MVC框架 然后就是对一个轻便级的MVC框架进行了一个初步的了解:
框架整个的一个结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 project --app *controllers **ItemController.php *models **ItemModel.php *views **item ***add.php ***delete.php ***index.php ***manage.php ***update.php **footer.php **head.php --config *config.php --fastphp *base **Controller.php **Model.php **View.php *db **Db.php **Sql.php *Fastphp.php --static --.htaccess --index.php
分析一个框架找到它的入口是很重要的,这个框架的入口是index.php:
1 2 3 4 5 6 7 8 9 10 11 <?php define ('APP_PATH' ,__DIR__ .'/' );define ('APP_DEBUG' ,true );require (APP_PATH.'fastphp/Fastphp.php' );$config =require (APP_PATH.'config/config.php' );(new fastphp\Fastphp ($config ))->run ();
可以看到它主要是加载和实例化框架(这里是调用fastphp\Fastphp这个类),这是框架的一个核心类,我们来看看Fastphp的部分内容:
1 2 3 4 5 6 7 8 9 public function run ( ) { spl_autoload_register (array ($this ,'loadClass' )); $this ->setReporting (); $this ->removeMagicQuotes (); $this ->unregisterGlobals (); $this ->setDbConfig (); $this ->route (); }
这里就是调用各种函数,主要我们来看一下这个route():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public function route ( ) { $controllerName = $this ->config['defaultController' ]; $actionName = $this ->config['defaultAction' ]; $param = array (); $url = $_SERVER ['REQUEST_URI' ]; $position = strpos ($url , '?' ); $url = $position === false ? $url : substr ($url , 0 , $position ); $url = trim ($url , '/' ); if ($url ) { $urlArray = explode ('/' , $url ); $urlArray = array_filter ($urlArray ); $controllerName = ucfirst ($urlArray [0 ]); array_shift ($urlArray ); $actionName = $urlArray ? $urlArray [0 ] : $actionName ; array_shift ($urlArray ); $param = $urlArray ? $urlArray : array (); } $controller = 'app\\controllers\\' . $controllerName . 'Controller' ; if (!class_exists ($controller )) { exit ($controller . '控制器不存在!' ); } if (!method_exists ($controller , $actionName )) { exit ($actionName . '方法不存在' ); } $dispatch = new $controller ($controllerName , $actionName ); call_user_func_array (array ($dispatch , $actionName ), $param ); }
这里主要是对URL做一个分隔,然后调用相应的Controller和Actionname,然后传入相应的参数,类似 /controllername/actionname/params 这种形式。
然后fastphp\base目录下是 控制器,视图,模型的一个基类,后面具体一个类型的控制器只需要继承这个基类就好,这样避免了代码重用,也使得层次很清晰,每一个功能对应一个Controller。比如后面的app文件夹下的ItemController直接继承了base下的Controller基类,然后单独负责一个功能板块。db文件下的Db.php和Sql.php主要是对数据库操作的一个封装。Db.php的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Db { private static $pdo = null ; public static function pdo ( ) { if (self ::$pdo !== null ) { return self ::$pdo ; } try { $dsn = sprintf ('mysql:host=%s;dbname=%s;charset=utf8' , DB_HOST, DB_NAME); $option = array (PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); return self ::$pdo = new PDO ($dsn , DB_USER, DB_PASS, $option ); } catch (PDOException $e ) { exit ($e ->getMessage ()); } } }
可以看到这里是直接返回了一个PDO对象。
然后就是Sql.php,对数据库进行抽象层的交互。增删改查等操作
然后Model这个基类继承了Sql,ItemModel则是进一步进行继承,负责搜索功能,(依据keyworld的值)
config就是一些默认的参数配置,view就主要是进行一个页面的渲染。
每一个模块各司其职,最后都把力使到app这个目录下的controller , view , model 。
小结 对PDO的基础概念和使用语法做了一个简单的了解,其具体底层机制还有待挖掘。
同时对MVC一个执行流程做了一个简单的了解,记录的文字感觉还是不太通俗,也似乎只有我自己知道自己在写些啥。。。
后面随着对MVC的加深应该会改把。。
又水完了一篇文章233333