Repository: yeszao/fastphp Branch: master Commit: 99886508430c Files: 26 Total size: 22.3 KB Directory structure: gitextract_2es6sksp/ ├── .gitignore ├── .htaccess ├── .travis.yml ├── README.md ├── app/ │ ├── controllers/ │ │ └── ItemController.php │ ├── models/ │ │ └── Item.php │ └── views/ │ ├── footer.php │ ├── header.php │ └── item/ │ ├── add.php │ ├── delete.php │ ├── detail.php │ ├── index.php │ ├── manage.php │ └── update.php ├── composer.json ├── config/ │ └── config.php ├── fastphp/ │ ├── Fastphp.php │ ├── base/ │ │ ├── Controller.php │ │ ├── Model.php │ │ └── View.php │ └── db/ │ ├── Db.php │ └── Sql.php ├── index.php ├── phpunit.xml ├── static/ │ └── css/ │ └── main.css └── tests/ └── autoload.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea vendor ================================================ FILE: .htaccess ================================================ # 打开Rerite功能 RewriteEngine On # 如果请求的是真实存在的文件或目录,直接访问 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # 如果访问的文件或目录不是真事存在,分发请求至 index.php RewriteRule . index.php ================================================ FILE: .travis.yml ================================================ language: php php: - 5.4 before_script: - composer install script: - phpunit -c phpunit.xml ================================================ FILE: README.md ================================================ # FastPHP [![Build Status](https://travis-ci.org/yeszao/fastphp.svg?branch=master)](https://travis-ci.org/yeszao/fastphp) [![Latest Stable Version](https://poser.pugx.org/yeszao/fastphp/v/stable)](https://packagist.org/packages/yeszao/fastphp) [![Total Downloads](https://poser.pugx.org/yeszao/fastphp/downloads)](https://packagist.org/packages/yeszao/fastphp) [![Latest Unstable Version](https://poser.pugx.org/yeszao/fastphp/v/unstable)](https://packagist.org/packages/yeszao/fastphp) [![License](https://poser.pugx.org/yeszao/fastphp/license)](https://packagist.org/packages/yeszao/fastphp) ## 简述 **fastphp**是一款简单的PHP MVC框架,目的是方便学习《手把手编写自己的PHP MVC框架》教程的同学下载源代码,详细介绍请参考网站:http://www.awaimai.com/128.html 。 要求: * PHP 5.4.0+ ## 目录说明 ``` project 根目录 ├─app 应用目录 │ ├─controllers 控制器目录 │ ├─models 模块目录 │ ├─views 视图目录 ├─config 配置文件目录 ├─fastphp 框架核心目录 ├─static 静态文件目录 ├─index.php 入口文件 ``` ## 使用 ### 1.安装 主要介绍通过composer和git两种安装方法,选择其一即可。 **方法1**:Composer安装(推荐) ``` composer create-project yeszao/fastphp project --no-dev ``` 其中,`--no-dev`表示不安装-dev依赖包(PHPUnit)。 **方法2**:Github安装: ``` git clone https://github.com/yeszao/fastphp.git project ``` > 说明:这两个命令都会创建并将代码安装到`project`目录。 ### 2. 创建数据库 在数据库中创建名为 project 的数据库,并插入两条记录,命令: ``` CREATE DATABASE `project` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE `project`; CREATE TABLE `item` ( `id` int(11) NOT NULL auto_increment, `item_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; INSERT INTO `item` VALUES(1, 'Hello World.'); INSERT INTO `item` VALUES(2, 'Lets go!'); ``` ### 3.修改数据库配置文件 打开配置文件 config/config.php ,使之与自己的数据库匹配 ``` $config['db']['host'] = 'localhost'; $config['db']['username'] = 'root'; $config['db']['password'] = '123456'; $config['db']['dbname'] = 'project'; ``` ### 4.配置Nginx或Apache 在Apache或Nginx中创建一个站点,把 project 设置为站点根目录(入口文件 index.php 所在的目录)。 然后设置单一入口, Apache服务器配置: ``` # 打开Rerite功能 RewriteEngine On # 如果请求的是真实存在的文件或目录,直接访问 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # 如果访问的文件或目录不是真事存在,分发请求至 index.php RewriteRule . index.php ``` Nginx服务器配置: ``` location / {    # 重新向所有非真实存在的请求到index.php try_files $uri $uri/ /index.php$args; } ``` ### 5.测试访问 然后访问站点域名:http://localhost/ 就可以了。 ================================================ FILE: app/controllers/ItemController.php ================================================ search($keyword); } else { // 查询所有内容,并按倒序排列输出 // where()方法可不传入参数,或者省略 $items = (new Item)->where()->order(['id DESC'])->fetchAll(); } $this->assign('title', '全部条目'); $this->assign('keyword', $keyword); $this->assign('items', $items); $this->render(); } // 查看单条记录详情 public function detail($id) { // 通过?占位符传入$id参数 $item = (new Item())->where(["id = ?"], [$id])->fetch(); $this->assign('title', '条目详情'); $this->assign('item', $item); $this->render(); } // 添加记录,测试框架DB记录创建(Create) public function add() { $data['item_name'] = $_POST['value']; $count = (new Item)->add($data); $this->assign('title', '添加成功'); $this->assign('count', $count); $this->render(); } // 操作管理 public function manage($id = 0) { $item = array(); if ($id) { // 通过名称占位符传入参数 $item = (new Item())->where(["id = :id"], [':id' => $id])->fetch(); } $this->assign('title', '管理条目'); $this->assign('item', $item); $this->render(); } // 更新记录,测试框架DB记录更新(Update) public function update() { $data = array('id' => $_POST['id'], 'item_name' => $_POST['value']); $count = (new Item)->where(['id = :id'], [':id' => $data['id']])->update($data); $this->assign('title', '修改成功'); $this->assign('count', $count); $this->render(); } // 删除记录,测试框架DB记录删除(Delete) public function delete($id = null) { $count = (new Item)->delete($id); $this->assign('title', '删除成功'); $this->assign('count', $count); $this->render(); } } ================================================ FILE: app/models/Item.php ================================================ table` where `item_name` like :keyword"; $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, [':keyword' => "%$keyword%"]); $sth->execute(); return $sth->fetchAll(); } } ================================================ FILE: app/views/footer.php ================================================ ================================================ FILE: app/views/header.php ================================================ <?php echo $title ?>

================================================ FILE: app/views/item/add.php ================================================ 成功添加条记录,点击返回 ================================================ FILE: app/views/item/delete.php ================================================ 成功删除项,点击返回 ================================================ FILE: app/views/item/detail.php ================================================ ID:
Name:

返回 ================================================ FILE: app/views/item/index.php ================================================

新建

ID 内容 操作
编辑 删除
================================================ FILE: app/views/item/manage.php ================================================
action="/item/update/" action="/item/add" method="post">
返回 ================================================ FILE: app/views/item/update.php ================================================ 成功修改项,点击返回 ================================================ FILE: composer.json ================================================ { "name": "yeszao/fastphp", "description": "Simple and lightweight PHP framework", "type": "project", "keywords": [ "framework", "fastphp", "mvc" ], "homepage": "http://www.awaimai.com", "license": "MIT", "authors": [ { "name": "gary", "email": "galley.meng@gmail.com" } ], "require": { "php": ">=5.4.0" }, "require-dev": { "phpunit/phpunit": "~4.8.0" }, "config": { "preferred-install": "dist", "platform": { "php": "5.4" } }, "autoload": { "psr-4": { "app\\": "app" } } } ================================================ FILE: config/config.php ================================================ config = $config; } // 运行程序 public function run() { spl_autoload_register(array($this, 'loadClass')); $this->setReporting(); $this->removeMagicQuotes(); $this->unregisterGlobals(); $this->setDbConfig(); $this->route(); } // 路由处理 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); // 使得可以这样访问 index.php/{controller}/{action} $position = strpos($url, 'index.php'); if ($position !== false) { $url = substr($url, $position + strlen('index.php')); } // 删除前后的“/” $url = trim($url, '/'); if ($url) { // 使用“/”分割字符串,并保存在数组中 $urlArray = explode('/', $url); // 删除空的数组元素 $urlArray = array_filter($urlArray); // 获取控制器名 $controllerName = ucfirst($urlArray[0]); // 获取动作名 array_shift($urlArray); $actionName = $urlArray ? $urlArray[0] : $actionName; // 获取URL参数 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 . '方法不存在'); } // 如果控制器和操作名存在,则实例化控制器,因为控制器对象里面 // 还会用到控制器名和操作名,所以实例化的时候把他们俩的名称也 // 传进去。结合Controller基类一起看 $dispatch = new $controller($controllerName, $actionName); // $dispatch保存控制器实例化后的对象,我们就可以调用它的方法, // 也可以像方法中传入参数,以下等同于:$dispatch->$actionName($param) call_user_func_array(array($dispatch, $actionName), $param); } // 检测开发环境 public function setReporting() { if (APP_DEBUG === true) { error_reporting(E_ALL); ini_set('display_errors','On'); } else { error_reporting(E_ALL); ini_set('display_errors','Off'); ini_set('log_errors', 'On'); } } // 删除敏感字符 public function stripSlashesDeep($value) { $value = is_array($value) ? array_map(array($this, 'stripSlashesDeep'), $value) : stripslashes($value); return $value; } // 检测敏感字符并删除 public function removeMagicQuotes() { if (get_magic_quotes_gpc()) { $_GET = isset($_GET) ? $this->stripSlashesDeep($_GET ) : ''; $_POST = isset($_POST) ? $this->stripSlashesDeep($_POST ) : ''; $_COOKIE = isset($_COOKIE) ? $this->stripSlashesDeep($_COOKIE) : ''; $_SESSION = isset($_SESSION) ? $this->stripSlashesDeep($_SESSION) : ''; } } // 检测自定义全局变量并移除。因为 register_globals 已经弃用,如果 // 已经弃用的 register_globals 指令被设置为 on,那么局部变量也将 // 在脚本的全局作用域中可用。 例如, $_POST['foo'] 也将以 $foo 的 // 形式存在,这样写是不好的实现,会影响代码中的其他变量。 相关信息, // 参考: http://php.net/manual/zh/faq.using.php#faq.register-globals public function unregisterGlobals() { if (ini_get('register_globals')) { $array = array('_SESSION', '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'); foreach ($array as $value) { foreach ($GLOBALS[$value] as $key => $var) { if ($var === $GLOBALS[$key]) { unset($GLOBALS[$key]); } } } } } // 配置数据库信息 public function setDbConfig() { if ($this->config['db']) { define('DB_HOST', $this->config['db']['host']); define('DB_NAME', $this->config['db']['dbname']); define('DB_USER', $this->config['db']['username']); define('DB_PASS', $this->config['db']['password']); } } // 自动加载类 public function loadClass($className) { $classMap = $this->classMap(); if (isset($classMap[$className])) { // 包含内核文件 $file = $classMap[$className]; } elseif (strpos($className, '\\') !== false) { // 包含应用(application目录)文件 $file = APP_PATH . str_replace('\\', '/', $className) . '.php'; if (!is_file($file)) { return; } } else { return; } include $file; // 这里可以加入判断,如果名为$className的类、接口或者性状不存在,则在调试模式下抛出错误 } // 内核文件命名空间映射关系 protected function classMap() { return [ 'fastphp\base\Controller' => CORE_PATH . '/base/Controller.php', 'fastphp\base\Model' => CORE_PATH . '/base/Model.php', 'fastphp\base\View' => CORE_PATH . '/base/View.php', 'fastphp\db\Db' => CORE_PATH . '/db/Db.php', 'fastphp\db\Sql' => CORE_PATH . '/db/Sql.php', ]; } } ================================================ FILE: fastphp/base/Controller.php ================================================ _controller = $controller; $this->_action = $action; $this->_view = new View($controller, $action); } // 分配变量 public function assign($name, $value) { $this->_view->assign($name, $value); } // 渲染视图 public function render() { $this->_view->render(); } } ================================================ FILE: fastphp/base/Model.php ================================================ table) { // 获取模型类名称 $this->model = get_class($this); // 删除类名最后的 Model 字符 $this->model = substr($this->model, 0, -5); // 数据库表名与类名一致 $this->table = strtolower($this->model); } } } ================================================ FILE: fastphp/base/View.php ================================================ _controller = strtolower($controller); $this->_action = strtolower($action); } // 分配变量 public function assign($name, $value) { $this->variables[$name] = $value; } // 渲染显示 public function render() { extract($this->variables); $defaultHeader = APP_PATH . 'app/views/header.php'; $defaultFooter = APP_PATH . 'app/views/footer.php'; $controllerHeader = APP_PATH . 'app/views/' . $this->_controller . '/header.php'; $controllerFooter = APP_PATH . 'app/views/' . $this->_controller . '/footer.php'; $controllerLayout = APP_PATH . 'app/views/' . $this->_controller . '/' . $this->_action . '.php'; // 页头文件 if (is_file($controllerHeader)) { include ($controllerHeader); } else { include ($defaultHeader); } //判断视图文件是否存在 if (is_file($controllerLayout)) { include ($controllerLayout); } else { echo "

无法找到视图文件

"; } // 页脚文件 if (is_file($controllerFooter)) { include ($controllerFooter); } else { include ($defaultFooter); } } } ================================================ FILE: fastphp/db/Db.php ================================================ PDO::FETCH_ASSOC); return self::$pdo = new PDO($dsn, DB_USER, DB_PASS, $option); } catch (PDOException $e) { exit($e->getMessage()); } } } ================================================ FILE: fastphp/db/Sql.php ================================================ where(['id = 1','and title="Web"', ...])->fetch(); * 为防止注入,建议通过$param方式传入参数: * $this->where(['id = :id'], [':id' => $id])->fetch(); * * @param array $where 条件 * @return $this 当前对象 */ public function where($where = array(), $param = array()) { if ($where) { $this->filter .= ' WHERE '; $this->filter .= implode(' ', $where); $this->param = $param; } return $this; } /** * 拼装排序条件,使用方式: * * $this->order(['id DESC', 'title ASC', ...])->fetch(); * * @param array $order 排序条件 * @return $this */ public function order($order = array()) { if($order) { $this->filter .= ' ORDER BY '; $this->filter .= implode(',', $order); } return $this; } // 查询所有 public function fetchAll() { $sql = sprintf("select * from `%s` %s", $this->table, $this->filter); $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, $this->param); $sth->execute(); return $sth->fetchAll(); } // 查询一条 public function fetch() { $sql = sprintf("select * from `%s` %s", $this->table, $this->filter); $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, $this->param); $sth->execute(); return $sth->fetch(); } // 根据条件 (id) 删除 public function delete($id) { $sql = sprintf("delete from `%s` where `%s` = :%s", $this->table, $this->primary, $this->primary); $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, [$this->primary => $id]); $sth->execute(); return $sth->rowCount(); } // 新增数据 public function add($data) { $sql = sprintf("insert into `%s` %s", $this->table, $this->formatInsert($data)); $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, $data); $sth = $this->formatParam($sth, $this->param); $sth->execute(); return $sth->rowCount(); } // 修改数据 public function update($data) { $sql = sprintf("update `%s` set %s %s", $this->table, $this->formatUpdate($data), $this->filter); $sth = Db::pdo()->prepare($sql); $sth = $this->formatParam($sth, $data); $sth = $this->formatParam($sth, $this->param); $sth->execute(); return $sth->rowCount(); } /** * 占位符绑定具体的变量值 * @param PDOStatement $sth 要绑定的PDOStatement对象 * @param array $params 参数,有三种类型: * 1)如果SQL语句用问号?占位符,那么$params应该为 * [$a, $b, $c] * 2)如果SQL语句用冒号:占位符,那么$params应该为 * ['a' => $a, 'b' => $b, 'c' => $c] * 或者 * [':a' => $a, ':b' => $b, ':c' => $c] * * @return PDOStatement */ public function formatParam(PDOStatement $sth, $params = array()) { foreach ($params as $param => &$value) { $param = is_int($param) ? $param + 1 : ':' . ltrim($param, ':'); $sth->bindParam($param, $value); } return $sth; } // 将数组转换成插入格式的sql语句 private function formatInsert($data) { $fields = array(); $names = array(); foreach ($data as $key => $value) { $fields[] = sprintf("`%s`", $key); $names[] = sprintf(":%s", $key); } $field = implode(',', $fields); $name = implode(',', $names); return sprintf("(%s) values (%s)", $field, $name); } // 将数组转换成更新格式的sql语句 private function formatUpdate($data) { $fields = array(); foreach ($data as $key => $value) { $fields[] = sprintf("`%s` = :%s", $key, $key); } return implode(',', $fields); } } ================================================ FILE: index.php ================================================ run(); ================================================ FILE: phpunit.xml ================================================ ./tests/ ================================================ FILE: static/css/main.css ================================================ html, body { margin: 0; padding: 10px; font-size: 20px; } input { font-family:georgia,times; font-size:24px; line-height:1.2em; } a { color:blue; font-family:georgia,times; line-height:1.2em; text-decoration:none; } a:hover { text-decoration:underline; } h1 { color:#000000; font-size:41px; border-bottom:1px dotted #cccccc; } td {padding: 1px 30px 1px 0;} ================================================ FILE: tests/autoload.php ================================================