YanPHP V0.2

Guide

Documentation

这是一个为API开发而设计的高性能轻量级框架。

框架为你集成了一些常用的类库,让你开发更加便捷。

另外引入了Composer,可以让你更加轻松地管理依赖以及处理命名空间问题。

让语法更加贴近原生PHP,并且在此基础上让你实现自己的定制化功能。

因为封装程度不高,所以框架的性能十分之优秀。

目录结构

├── Application --你的代码目录

│ ├── Cgi --分层应用根目录(这里是Cgi代码)

│ │ ├── Cache --缓存

│ │ ├── Compo --自定义组件

│ │ ├── Config --配置

│ │ ├── Controller --控制器,用于编写业务逻辑

│ │ ├── Logs --日志存放

│ │ ├── Model --模型层

│ │ ├── Param --入参定义,以及参数校验

│ │ └── Util --工具类库

│ └── Server --分层应用根目录(这里是Server代码)

│ │ ├── Cache --缓存

│ │ ├── Compo --自定义组件

│ │ ├── Config --配置

│ │ ├── Controller --控制器,用于编写业务逻辑

│ │ ├── Logs --日志存放

│ │ ├── Model --模型层

│ │ ├── Param --入参定义,以及参数校验

│ │ └── Util --工具类库

├── System --框架目录

│ └── Yan

│ ├── Common

│ └── Core

│ ├── Compo

│ └── Exception

安装

环境要求

Require:

PHP >= 7.0

Composer

安装步骤

先把YanPHP从github拷贝到本地

git clone https://github.com/kong36088/YanPHP.git

然后进行框架依赖组件的安装,这里需要用到composer。请确保您的机器中已经安装了composer

composer install

完成!

hello world

首先安装YanPHP的依赖项:

composer install

来编写我们的第一个hello world

首先我们需要先新增一个控制器

新建一个控制器文件 Application/Cgi/Controller/HelloController.php

namespace App\Cgi\Controller;

use Yan\Core\Compo\ResultInterface;

use Yan\Core\Controller;

class HelloController extends Controller

{

public function index(): ResultInterface

{

return $this->succ('hello world');

}

}

紧接着到Param目录下创建我们的控制器入参规则,

Application/Cgi/Param/HelloController.ini内容如下:

[index]

用命令行重新加载composer中注册的命名空间:

composer dump-autoload

最后,用浏览器访问我们刚才编写的hello world:http://localhost/interface.php/hello/index

返回结果为以下内容

{

"code":0,

"message":"hello world",

"data":[]

}

若有新增类库文件,记得一定要运行一次 composer dump-autoload 以刷新我们的autoloader

路由

默认路由规则

默认路由寻路路径是:/interface.php/controller/method

controller代表您的控制器,method是指向的方法

自定义路由规则

当然,您也可以自定义自己的路由规则。

路由规则存放在 Application/YourLevel/Config/router.php

$config['default_method'] = 'index'; //默认方法

$config['route'] = [

'/' => [ //被映射的路径

'request_method' => ['GET','POST'], //支持的http动作,支持GET和POST

'controller' => 'App\\Cgi\\Controller\\UserController', //所映射到的控制器,需要包含命名空间,映射到Application/Cgi/Controller/UserController

'method' => 'index' //所映射到的方法,映射到UserController的index方法

],

'/user' => [

'request_method' => ['GET'], //支持的http动作,支持GET

'controller' => 'App\\Cgi\\Controller\\UserController', //所映射到的控制器,需要包含命名空间,映射到Application/Cgi/Controller/UserController

'method' => 'getUser' //映射到UserController的index方法getUser方法

],

];

配置

配置文件统一存放在 Application/YourLevel/Config 目录下

Application下的各个文件夹对应着您应用的各个分层,每一层都采用自己独立的Config配置

系统配置相关

$config['namespace'] = 'App\\Cgi';

这里用于配置你的应用层采用的命名空间,在新添加应用层后请勿忘记修改这里的配置哦。

$config['session_path'] = BASE_PATH.'/Cache/session';

$config['session_name'] = 'YAN_SESSION';

session_path 用于配置session存放的僦

session_name 用于配置session名称,即用于标识用户session id的key值

日志配置相关

几种日志等级。比如日志等级配置为INFO,则INFO及INFO以上的(NOTICE、WARING、ERROR)等等级的日志将会被记录。

/**

'DEBUG'

'INFO'

'NOTICE'

'WARNING'

'ERROR'

'CRITICAL'

'ALERT'

'EMERGENCY'

*/

$config['log_level'] = 'DEBUG';

日志存放路径

/**

* The log path

*/

$config['log_path'] = BASE_PATH . '/logs/cgi.log';

/**

* 最大存放的日志文件数量

*/

$config['log_max_file'] = 0;

/**

* 配置日志记录的格式

* "[%datetime%] %channel%.%level_name%: %message% %context%\n";

*/

$config['log_format'] = "[%datetime%]-%extra.process_id% %channel%.%level_name%: %message% %context%\n";

database

database.php

config

options

description

db_host

DB host

db_user

用户名

db_password

密码

db_port

3306/(others)

端口号

db_database

db_charset

utf8/(others)

db_driver

mysql/postgres/sqlite/sqlsrv

目前支持四种数据库类型

可以配置多个数据库连接,默认使用default进行连接

例如下面的例子:

$config['db'] = [

'default' => [

/** host */

'db_host' => 'mysql',

/** 数据库用户名 */

'db_user' => 'root',

/** 数据库密码 */

'db_password' => 'root',

/** 端口 */

'db_port' => 3306,

/** 数据库 */

'db_database' => 'yan',

/** 表名前缀 */

'db_prefix' => '',

/**

* mysql/postgres/sqlite/sqlsrv

*/

'db_driver' => 'mysql',

'db_charset' => 'utf8',

'db_collation' => 'utf8_unicode_ci'

],

'mysql1'=>[

'db_host' => '',

'db_user' => '',

'db_password' => '',

'db_port' => 3306,

'db_database' => '',

'db_prefix' => '',

'db_driver' => 'mysql',

'db_charset' => '',

'db_collation' => ''

]

];

这里我们可以对连接进行管理,其中上面的default以及mysql1是我们的连接名称,我们可以根据名称进行数据库连接的切换。

具体可以看Database/DB多连接管理

YAssert

YanPHP内嵌的断言支持。感谢beberlei/assert提供类库支持

入参和Input

用法介绍

所有入参都需要定义在应用目录路径下的Param目录,并且可以对其进行相关的参数校验操作。

下面我们会举例对该功能进行讲解。

例如我们需要请求UserController的index方法,那么我们需要创建一个入参配置文件 Param/UserController.ini

文件内容如下:

[index]

user_id="starts_with[1]|required|numeric|between[1,123]"

page="numeric"

domain="string|numeric"

arr="array"

[getUser]

“=”号左边的是需要的入参,右边的是需要验证的规则。规则都是Validator内置好的,基于Respect/Validation开发

并且只有被定义在入参配置文件中的参数才会被Input类所识别,其余参数一律丢弃。

若参数不符合规则要求,则会直接返回错误信息。

如若你需要为参数配置多个验证规则,可以用 | 进行规则分割,例子:domain="string|length[1,20]"。

在这个例子中,我们要求domain必须是字符串类型,并且长度在1-20个字符之间。

相关入参规则

规则

参数

使用说明

例子

required

参数必填

optional

参数可空

integer

整型

numeric

所有字符都是数字(不区分变量类型)

float

浮点型

string

字符型

array

数组型

ip

验证是否为一个有效的ip

json

验证是否为合法json格式

email

验证是否为合法邮箱

domain

验证是否为合法域名

regex

正则匹配

regex(/[0-9]+/)

starts_with

是否以规定的字符开头

starts_with(ab)

ends_with

是否以规定的字符结束

ends_with(ab)

between

数值在定义的范围之间

between(1,100)

min

定义最小不小于

min(1)

max

定义最大不大于

max(100)

length

定义字符串长度在定义范围内

length(1,100)

equal

入参的值必须等于定义的值

equal(123)

contain

入参是否包含给出的值

contain([ab])

获取输入参数

Input::get('user_id'); //获取参数user_id

Input::set('user_id',1); //设置参数

Database

DB方面YanPHP采用了illuminate/Database。

编码设计风格与其保持总体一致。

使用介绍

composer require "illuminate/events" required when you need to use observers with Eloquent.

Once the Capsule instance has been registered. You may use it like so:

Using The Query Builder

$users = Capsule::table('users')->where('votes', '>', 100)->get();

Other core methods may be accessed directly from the Capsule in the same manner as from the DB facade:

$results = Capsule::select('select * from users where id = ?', array(1));

Using The Schema Builder

Capsule::schema()->create('users', function ($table) {

$table->increments('id');

$table->string('email')->unique();

$table->timestamps();

});

Using The Eloquent ORM

class User extends Illuminate\Database\Eloquent\Model {}

$users = User::where('votes', '>', 1)->get();

或者使用YanPHP提供的风格

use Illuminate\Database\Eloquent\Model;

use Illuminate\Support\Collection;

class User extends Model

{

protected $table = 'user';

protected $primaryKey = 'uid';

protected $keyType = 'int';

public function getById($id): Collection

{

return $this->where([$this->primaryKey => $id])->get();

}

public function getByCond($cond): Collection

{

return $this->where($cond)->get();

}

public function updateByCond($cond, $update): bool

{

return $this->where($cond)->update($update);

}

public function deleteById($id)

{

return $this->where($id)->delete();

}

}

$UserModel = new User();

$UserModel->getById(1); // 获取user表中uid为1的用户数据信息

For further documentation on using the various database facilities this library provides, consult the Laravel database documentation.

DB多连接管理

在配置文件database.php配置我们的连接后,可以实现多个db连接实例。

下面我们将介绍如何进行连接的切换。

Model/User.php

namespace App\Cgi\Model;

use Illuminate\Support\Collection;

use Yan\Core\Model;

class User extends Model

{

protected $table = 'user';

protected $connection = 'mysql1'; //这里可以配置User Model默认使用"mysql1"连接

public function getById($id): Collection

{

//这里可以使当前实例的连接切换为"default"

$this->setConnection('default');

return $this->where([$this->primaryKey => $id])->get();

}

}

我们可以使用Model当中的$connection配置默认的连接。

另外一种方法是使用自带的$this->setConnection($name)方法进行连接的设置

Session

用法示例

use Yan\Core\Session;

Session::set('a','b'); //设置session值

$sessionVaue = Session::get('a'); //获取session中的值

Session::destroy(); //销毁所有session

Session类中有以下方法

/**

* @method static mixed get($key, $alt = null)

* @method static mixed set($key, $val)

* @method static null clear()

* @method static mixed getFlash($key, $alt = null)

* @method static null setFlash($key, $val)

* @method static null clearFlash()

* @method static mixed getFlashNext($key, $alt = null)

* @method static null setFlashNow($key, $val)

* @method static null clearFlashNow()

* @method static null keepFlash()

* @method boo null destroy()

*/

定制化

定制Result格式

可以到你的应用目录下的Compo/Result.php定制化你的Result格式

下面是Result类的示例:

namespace App\Cgi\Compo;

use Yan\Core\Compo\ResultInterface;

class Result implements ResultInterface

{

protected $code;

protected $message;

protected $data;

public function __construct(int $code, string $message, array $data = [])

{

$this->code = $code;

$this->message = $message;

$this->data = $data;

}

function getCode(): int

{

return $this->code;

}

function getMessage(): string

{

return $this->message;

}

/**

* Specify data which should be serialized to JSON

* @link http://php.net/manual/en/jsonserializable.jsonserialize.php

* @return mixed data which can be serialized by json_encode,

* which is a value of any type other than a resource.

* @since 5.4.0

*/

function jsonSerialize()

{

return ['code' => $this->code, 'message' => $this->message, 'data' => $this->data];

}

}

jsonSerialize()返回一个数组,作为结果输出

定制ReturnCode

YanPHP为你定义了一个全局的返回码,返回码的修改可以到System/Yan/Core/ReturnCode.php修改

YanPHP命名规范准则

YanPHP的所有的类文件文件名都 必须 与类名保持一致

框架的命名方式应该遵循驼峰命名法的命名规范。相关介绍可以看这里

控制器

控制器类名需要以驼峰命名法进行命名,并且以Controller作为后缀结束。

例如:UserController、TotalStatisticsController、InfoListController

Model

采用驼峰法,名字可以根据你自己的喜好进行命名。我们会推荐你根据数据库表名或相关的业务用途对model进行命名。

例如:User、Product、Price

入参配置文件(Param/*.ini)

文件名 必须 与你的控制器名称保持一致。每个控制器单独对应一个入参配置文件。

例如:UserController.ini、TotalStatisticsController.ini、InfoListController.ini

安全

重新生成SessionID

Any time a user has a change in privilege (that is, gaining or losing access

rights within a system) be sure to regenerate the session ID:

\Yan\Core\Session::regenerateId();

?>

N.b.: The regenerateId() method also regenerates the CSRF token value.

Cross-Site Request Forgery

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。

CSRF防御措施

为了防范Csrf攻击,server端的处理逻辑应该是这样的:

为每一个已经登陆了的用户的每个表单请求放置一个验证token;

确保所有通过 POST/PUT/DELETE (i.e., "unsafe") 的请求都包含上一步骤提到的token值。

N.b.: 如果我们的应用是通过GET请求方法去修改应用资源 (这

是一个错误的做法), 我们同样应该对GET方法的请求

进行CSRF token的验证,以确保用户资源的安全。

例如,我们想要生成一个CSRF token,可以参考以下做法

\Yan\Core\Session::getCsrfToken()->getValue();

当server端接收到一个请求时,我们应该对CSRF token进行以下的处理:

use Yan\Core\Session;

use \Yan\Core\Input;

/**

* @var Vendor\Package\User $user A user-authentication object.

*/

$unsafe = $_SERVER['REQUEST_METHOD'] == 'POST'

|| $_SERVER['REQUEST_METHOD'] == 'PUT'

|| $_SERVER['REQUEST_METHOD'] == 'DELETE';

if ($unsafe && $user->auth->isValid()) {

$csrf_value = Input::get('__csrf_value');

$csrf_token = Session::getCsrfToken();

if (! $csrf_token->isValid($csrf_value)) {

echo "This looks like a cross-site request forgery.";

} else {

echo "This looks like a valid request.";

}

} else {

echo "CSRF attacks only affect unsafe requests by authenticated users.";

}

?>

Nginx

我们需要把每一层应用层作为你的根目录

# 这里是你的Cgi层

server

{

listen 80;

server_name cgi.example.com;

index index.shtml index.html index.htm interface.php;

root root /path/to/root/YanPHP/Application/Cgi/;

location / {

try_files $uri $uri/ =404;

if (!-e $request_filename)

{

rewrite (.*) /interface.php;

}

}

location ~ .*\.(php|php5)?$

{

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

include fastcgi.conf;

}

access_log /var/log/YanPHP/access.log;

error_log /var/log/YanPHP/error.log;

}

# 这里是你的Server层

server

{

listen 80;

server_name server.example.com;

index index.shtml index.html index.htm interface.php;

root root /path/to/root/YanPHP/Application/Server/;

location / {

try_files $uri $uri/ =404;

if (!-e $request_filename)

{

rewrite (.*) /interface.php;

}

}

location ~ .*\.(php|php5)?$

{

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

include fastcgi.conf;

}

access_log /var/log/YanPHP/access.log;

error_log /var/log/YanPHP/error.log;

}

Apache

如果你需要进行url重写,那么你需要开启 rewrite module。

YanPHP已经为你编写好了 .htaccess 文件,并且存放在每一个应用层的目录下。

DocumentRoot "/path/to/root/YanPHP/Application/Cgi/;"

ServerName cgi.example.com

AddType application/x-httpd-php .php

Options Indexes FollowSymLinks

AllowOverride None

Require all granted

DirectoryIndex interface.php

DocumentRoot "/path/to/root/YanPHP/Application/Server/;"

ServerName server.example.com

AddType application/x-httpd-php .php

Options Indexes FollowSymLinks

AllowOverride None

Require all granted

DirectoryIndex interface.php

Tests

YanPHP编写了相关的测试用例,可以通过运行一下命令进行单元测试,同时也欢迎提交pull request进行测试用例的补充。

phpunit --configuration phpunit.xml

License

MIT

php consult用法,YanPHP: YanPHP——一个为API开发而设计的高性能轻量级框架相关推荐

  1. API开发接口设计 采用微信accessToken授权方式

    ⼀.开放接⼝设计说明: 在开发微信授权登入,访问用户信息,就会发现,在微信开发平台调用接口的流程如下: 1. 在开发平台申请到 appid 和 app_secret 2. 通过appid 和 app_ ...

  2. python实现简单的api接口-用python写一个restful API

    # -*- coding: utf-8 -*- # 作者: 煮酒品茶 """ package.module ~~~~~~~~~~~~~~ python实现的图书的一个re ...

  3. python restful api_用Python语言写一个restful API

    本文主要向大家介绍了用Python语言写一个restful API,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. """ package.modul ...

  4. 使用python的Flask实现一个RESTful API服务器端

    使用python的Flask实现一个RESTful API服务器端[翻译] 最近这些年,REST已经成为web services和APIs的标准架构,很多APP的架构基本上是使用RESTful的形式了 ...

  5. 启动服务错误5拒绝访问_【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器...

    启动一个最简单的 RESTful API 服务器 本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本 ...

  6. 一个简单可参考的API网关架构设计

    http://www.infoq.com/cn/articles/api-gateway-architecture-design 网关一词较早出现在网络设备里面,比如两个相互独立的局域网段之间通过路由 ...

  7. 一个Win32 API实例类(代码收集)

    最近看到别人代码中一个很好的功能类,该类是一个Win32 API实例类,该类功能包括:同一程序禁止启动多次:获取任意窗体:恢复窗体状态:设置窗体焦点等. 该类很实用,与大家分享一下:  1     / ...

  8. 使用PHP创建一个REST API(译)

    最近API在网络领域有些风靡,明确的说是REST的影响力.这实在没什么好惊讶的,因为在任何编程语言中,消费REST API都是非常的容易.构建它也非常的简单,因为本质上你不会用到任何那些已存在很久的H ...

  9. 【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器

    本节核心内容 启动一个最简单的 RESTful API 服务器 设置 HTTP Header API 服务器健康检查和状态查询 编译并测试 API 本小节源码下载路径:demo01 可先下载源码到本地 ...

最新文章

  1. Angular1.x入门级自定义组件(导航条)
  2. eclipse插件 --js
  3. linux学习-----开机启动项设置,ntp服务,防火墙服务,rpm服务,cron服务
  4. wcf 远程终结点已终止该序列 可靠会话出错
  5. Create new SAP DDL view and click finish in wizard
  6. 【每日算法Day 83】邻居小孩一年级就会的乘法表,你会吗?
  7. 代码管理学:功能实现,一定要与界面分开
  8. windows批处理脚本导入注册表不弹出确认框
  9. HTML零基础入门教程完整版
  10. 计算机桌面工作提醒,有什么好用的电脑桌面日程安排提醒软件?
  11. java数据流编辑 kylo,Kylo的安装
  12. STM32 USB Mass Storage 例程调试笔记
  13. 数据结构之leetcode 347题
  14. 【SAP消息号M8147】
  15. Android系统sdcard目录
  16. 从iOS切换到Android(flyme)
  17. 一加和小米哪个好 一加用技术领先树立起品牌典范
  18. Week of 2.7
  19. 血泪!pyinstaller打包文件过大的解决方法
  20. tf.layers.flatten()使用

热门文章

  1. flask模板上下文和模板继承
  2. 四年大学,说毕业就毕业了
  3. 番茄花园站长被拘幕后:微软向个人盗版开刀
  4. 5分钟包你搞懂箱形图分析!
  5. 使用BeanEditForm来创建用户表单
  6. 看WIZ110SR如何实现串口转以太网功能
  7. WaitForSingleObject 返回值为 WAIT_ABANDONED 的情况
  8. 三大攻略破TD手机节能之困
  9. 自定义切面会吃掉异常,导致事务不生效的问题。
  10. 转:车规芯片的AEC-Q100测试标准