123

下载

prain: v1.3.3 prainv1.3.3

环境要求

PHP版本: PHP: 7.4+ PHP7.4+ 推荐PHP: 8.0+ 推荐PHP8.0+

安装

1. 服务器:推荐使用阿里云服务器,比较稳定,传送阵:阿里云服务器,本链接可领取9折优惠券

2. 环境部署:推荐使用宝塔面板来安装,一键PHP环境部署,传送阵:宝塔服务器面板,一键全能部署

3. 将下载的程序代码解压到你的网站根目录,直接运行你的网站,会自动跳转到安装页面

4. 在安装页面输入相关信息和登录密码,点击提交后会进入首页

警告:本程序严禁用于非法用途,请遵守相关法律法规,使用者因违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。

升级

进入后台,点击网站首页按钮,可查看系统的当前版本号,如果当前版本较低时,会自动弹出新版本更新提示窗,点击更新即可,升级前请做好网站备份,避免升级造成不必要的数据损失。

提示1:系统同步也是更新的一种,会与官网最新的核心文件同步,从而达到系统版本的更新。

提示2:数据库版本同步指的是你当前的数据库版本将与官方最新版本同步,这里的版本主要指的是数据字段结构,系统升级有时候会增加数据库字段,一般在线更新的时候会自动更新,这里的数据库版本并不是指的数据库数据同步哦,官网并不会收集你数据库的数据。

文件结构

┌─index.php 首页入口

├─db 数据库

│ ├─article 文章列表数据

│ ├─comment 文章评论数据

│ ├─upload 文章上传数据

│ ├─article.php 文章列表

│ ├─conf.php 网站配置

│ ├─error.php 错误日志列表

│ ├─ini.php 用户配置

│ └─list.php 数据库字段列表

├─ext 扩展

├─lib 函数类库

│ ├─admin 后台管理页面

│ │ ├─article.create.php 文章创建页

│ │ ├─article.editor.php 文章编辑页

│ │ ├─article.php 文章管理页

│ │ ├─category.php 分类设置页

│ │ ├─error.php 错误日志页

│ │ ├─ext.php 扩展管理页

│ │ ├─footer.php 模板尾部文件

│ │ ├─header.php 模板头部文件

│ │ ├─index.php 后台首页

│ │ ├─install.php 系统安装页

│ │ ├─link.php 友情链接页

│ │ ├─login.php 后台登录页

│ │ ├─navbar.php 后台登录页

│ │ ├─prompt.php 提示页

│ │ ├─setting.php 基础设置页

│ │ └─tpl.php 模板管理页

│ │

│ ├─style 公共样式

│ │ ├─admin.css 后台样式

│ │ ├─fk.css fk样式

│ │ ├─common.js 公共脚本

│ │ └─logo.svg LOGO图标

│ │

│ ├─common.php 公共方法

│ ├─file.util.class.php 文件操作类

│ ├─fk.class.php fk标记语言类

│ ├─function.php 函数方法集合

│ ├─tpl.class.php 模板编译类

│ ├─upload.class.php 上传类

│ └─vcode.class.php 验证码类

└─tpl 主题模板

└─default

├─style 样式文件夹

│ └─main.css 样式

├─conf.php 模板配置文件

├─footer.php 模板尾部文件

├─header.php 模板头部文件

├─icon.png 模板缩略图

├─index.php 首页

├─page.php 详情页

├─prompt.php 提示页

├─search.php 搜索页

├─category.php 分类页

├─sidebar.php 模板侧栏文件

└─tag.php 标签页

主题模板开发

说明

  • 主题模板用于定制清雨的界面,为其提供布局效果及样式
  • 主题模板在tpl文件夹下

文件结构

default 主题模板文件夹,名称不能包含中文,不能为纯数字,应放在tpl文件夹中

│-----------------------------------------------------------

├─style 样式文件夹,存放css、js等文件(非必须)

├─img 图片文件夹,存放图片文件(非必须)

│-----------------------------------------------------------

├─conf.php 模板配置文件(必须)

├─icon.png 模板缩略图(必须)

├─index.php 首页(必须)

├─page.php 详情页(必须)

├─prompt.php 提示页(必须)

├─header.php 模板头部文件(非必须)

├─footer.php 模板尾部文件(非必须)

├─login.php 登录页(非必须)

├─search.php 搜索页(非必须)

├─category.php 分类页(非必须)

├─tag.php 标签页(非必须)

├─sidebar.php 模板侧栏文件(非必须)

├─install.php 安装文件(非必须)

└─uninstall.php 卸载文件(非必须)

开发规范

  • 引用的css、js等文件应统一放在style文件夹中
  • 图片文件应统一放在img文件夹中
  • 尾部文件footer.php中应注明清雨的版权,指定链接为:https://prain.cn

模板文件说明

除了文件结构中标注的必须文件,其它的非必须文件不一定要存在,看你如何开发了。

  • category.phptab.phpsearch.php不存在时,将默认调用index.php模板
  • login.php不存在时将默认调用/lib/admin/login.php
  • sidebar.php属于页面引用的侧栏公共文件,如果你的模板并不存在侧栏,也无需创建

install文件说明

该文件可有可无,如果存在该文件,install安装文件会在使用新主题的时候执行一次,一般用于提前创建好数据库之类的操作。

uninstall文件说明

该文件可有可无,如果存在该文件,uninstall卸载文件会在使用新主题的时候执行一次,一般用于清除旧主题造成的数据垃圾。

conf配置文件说明

<?php

// 配置文件

return array (

'id' => '主题模板的ID',

'type' => '应用类型,主题为tpl,扩展为ext',

'author' => '作者,开发者的账号',

'name' => '主题模板的名称',

'intro' => '主题模板的简述',

'price' => '主题模板价格,0为免费,仅支持2位小数',

'home' => '主题模板的主页',

'version' => '版本号,格式为1.0.0',

'limit' => '限制清雨的最低版本号,格式为1.0.0',

'depend' => '依赖的应用ID,空格隔开'

);

?>

自定义页面和URL链接

如果清雨提供的默认页面并不能满足你的需求,那么你可以通过main.php文件来设置更多的页面,main.php在主题模板中可有可无,如果存在的话,它会被当做公共文件引入到系统中,不管进入任何页面,都会优先执行main.php的代码,所以main.php中不但可以设置更多的页面,引入更多的自定义类库,你甚至可以完全覆盖prain自身的页面业务逻辑。

如何编写main.php中的代码呢?我们举个例子,当你需要设置某个自定义的页面时,例如一个demo页面,你想访问的链接是:https://example.com/demo,这个时候demo的页面名称可以通过$page来获得,$page是个全局变量,可以获得网址/后面的第一个参数(prain中的url参数是通过/来分割的),有了$page就可以很方便的写demo页面的逻辑,以及引用模板中的demo.php页面,示例如下:

main.php文件

<?php

// demo页面

if($page == 'demo'){

$info = [

'title' => '静默的流年',

'content' => '站在青春的夕阳下,感受着过往,留下浅浅的笑靥,或许这就是青春的流逝吧!'

];

include $tpl->view('demo');

}

?>

demo.php文件

<h3> {$info.title} </h3>

<p> {$info.content} </p>

上面的示例是不是很简单?main.php很强大,可以内置任何你想要的功能或页面,上面我们说到了$page这个变量,默认它获取的是URL第1个参数,如果你需要获取第2个、第3个参数,那么你可以通过get()这个方法来获取,在prain中,get()用来获取url上的参数,post()用于获取form表单提交过来的参数,这两个方法能帮助你便捷的处理表单操作。

这两个方法位于lib/function.php中,function.php包含了开发者常用的封装函数,具体请查阅该文件,也可以查阅本文档中的【函数列表】

主题模板也继承了扩展的开发方式,支持main.phpcommon.php文件的编写,具体可参考本文档【扩展应用开发】

主题中的标签说明

上面的demo.php示例中我们用到了花括号来输出变量内容,这是prain内置的模板编写能力,{$info.title}等同于<?php echo $info'title';?>,当然你也可以将{$info.title}写成{$info'title'}(我想没人会这么费力不讨好),具体请看下面的模板语法。

编写模板时我们常常使用花括号来输出内容,它的工作原理是将你的主题模板编译成php原生格式,编译后的文件会放入当前主题模板的compile文件夹中,所以我们在开发主题模板时不要使用compile文件夹来存放主题文件。

下面是关于模板标签的一下用法。

主题模板语法

标题语法说明

变量

{$example}

$为前缀

输出其它内容

{#EXAMPLE}

{#time()} {# time()}

{#$example > 10 ? '真' : '假'}

#为前缀,后面可以为常量、方法或php原生语句,#代表输出,会被编译成echo,后面是echo的内容。

插入url链接

{url admin}

{url admin/article}

{url admin/article/editor/$article.id}

url为前缀,后面为网址链接(网站链接前面不能为斜杠),网址中支持使用变量(只能使用变量,不支持常量),这种方式支持伪静态。

举例:{url admin}如果伪静态开启,则链接实际为/admin,伪静态关闭,则链接实际为/?admin

IF判断

{if $example > 10} 内容1 {/if}

{if $example > 10} 内容1 {else} 内容2 {/if}

{if $example > 10} 内容1 {elseif $example > 25} 内容2 {else} 内容3 {/if}

{if $example > 10 ? '内容'}

{if $example > 10 ? '小明' : '小红'}

{if $example > 10 : 内容}

{if $example > 10 : 小明 : 小红}

简单的if语句无需使用括号,多条件判断可以使用。

{if 条件 ? 为真内容 : 为假内容}三元运算,使用PHP原生写,字符串需要使用引号包裹,变量随意,支持$user.avatar这种写法。

{if 条件 : 为真内容 : 为假内容}与问号写法的不同是输出语句可以直接为字符串,不需要用引号,支持内嵌变量,

{if 条件 : 为真内容}与上面一样,只是没有为假的内容输出

循环遍历

{foreach $articleList}

<p> 条目:{$index} </p>

<p> KEY:{$key} </p>

<p> {$item.title} </p>

<p> {$item.intro} </p>

{/foreach}

{foreach $articleList as $article}

<h3> {$article.title} </h3>

<p> {$article.intro} </p>

{/foreach}

{foreach $articleList as $name => $article}

<h3> URL的名称:{$name} </h3>

<h3> {$article.title} </h3>

<p> {$article.intro} </p>

{/foreach}

支持这三种遍历方式,这里请注意,只有第一种foreach方式内置三个变量,分别如下:

$index 表示当前条目,从0开始递增

$key 表示当前数组的Key

$item 表示当前数组的Value

引入模板

{include header}

{include bbs/list}

{include tpl header}

{include admin header}

include 指令常用于引入模板,一处编写,多处引用,降低开发成本。

header 表示为当前目录中的header.php文件。

bbs/list 表示当前目录中bbs文件夹下的list.php文件。

tpl headertpl前缀,表示当前主题模板根目录下的header.php文件,常用于开发前端扩展中的页面编写。

admin headeradmin前缀,表示后台模板主题根目录下的header.php文件,常用于开发后端扩展中的页面编写。

原生语句

{{

$info = [

'title' => '静默的流年',

'content' => '留下浅浅的笑靥,或许这是青春的流逝!'

];

$info'author' = '闫立峰';

echo $info'title';

echo $info'content';

echo $info'author';

}}

{{

$info = [

'title' => '静默的流年',

'content' => '留下浅浅的笑靥,或许这是青春的流逝!'

];

$info.author = '闫立峰';

echo $info.title;

echo $info.content;

echo $info.author;

}}

当我们需要在模板文件中编写很长的php原生代码时,我们可以用两个花括号来写,当然你也可以继续使用原生的<?php ?>来写。

但是,上面的$info.title会被编译成$info'title',所以说双花括号中写php更加方便,形式更好。

标签:全局常量

标签返回类型说明

V

string

系统版本号

ROOT

string

根目录的绝对路径

HOME

string

根目录的相对路径

URL

string

根目录的相对路径与伪静态结合

DB

string

数据目录的绝对路径

EXT

string

扩展目录的绝对路径

LIB

string

类库目录的绝对路径

TPL

string

当前主题模板的相对路径

TPLPATH

string

当前主题模板的绝对路径,包含项目的整个路径

TPL_STYLE

string

当前主题模板的style相对路径

TPL_IMG

string

当前主题模板的img相对路径

LIB_STYLE

string

公共style相对路径

LOGIN

bool

登陆状态,true为登录 false为未登录

DEBUG

string

0:线上模式(无错)1:调试模式(无错+日志)2:开发模式(报错+日志)

标签:全局变量

标签返回类型说明

$host

string

博客网址

$conf

array

网站配置信息

$tpl

Class

模板类

$util

Class

文件操作类

$ini

array

用户配置

$method

string

请求方式:POST、GET

$url

string

当前地址

$ajax

bool

是否为Ajax请求

$page

string

当前页面(index、category、tag、search、page、prompt、admin)

$extList

array

已安装的扩展列表

$articleList

array

文章列表

$categoryList

array

分类列表

$tagList

array

标签列表

$navbarList

array

导航菜单列表

$linkList

array

友情链接列表

$settingPage

string

当前应用的设置页,存在为设置页路径,不存在为空字符串

标签:网站配置

标签返回类型说明

{$conf.title}

string

网站的title标题

{$conf.name}

string

网站头部标题

{$conf.intro }

string

网站描述

{$conf.mood}

string

心情记录

{$conf.key}

string

SEO网站关键字

{$conf.desc}

string

SEO网站描述

{$conf.brief}

int

新建文章时的描述限制字数

{$conf.password}

string

网站登录密码

{$conf.tpl}

string

主题模板

{$conf.compile}

bool

模板自动编译

{$conf.debug}

int

等同于全局变量DEBUG

{$conf.rewrite}

bool

伪静态

{$conf.article.paging}

int

文章分页设置,每页数量

{$conf.article.count}

int

文章总数量

{$conf.comment.restrict}

int

评论限制设置,每日限制的条数

{$conf.comment.paging}

int

评论分页设置,每页数量

{$conf.comment.count}

int

评论总数量

{$conf.vcode.open}

bool

验证码开启

{$conf.vcode.width}

int

验证码宽度

{$conf.vcode.height}

int

验证码高度

{$conf.vcode.length}

int

验证码字符串数量

{$conf.icp}

string

ICP备案号

{$conf.prn}

string

公安备案号

{$conf.views}

int

网站浏览量

{$conf.blacklist}

string

IP黑名单

{$conf.tag}

array

标签集合

{$conf.ext}

array

扩展集合

{$conf.category}

array

分类集合

{$conf.navbar}

array

导航菜单集合

{$conf.link}

array

友情链接集合

{$conf.js}

string

JS脚本代码

{$conf.install}

bool

系统是否已安装

{$conf.db.version}

string

系统db版本

标签:首页

标签返回类型说明

{$pageNum}

int

当前页码,默认为1

{$pageSize}

int

文章每页条数

{$article.count}

int

文章总数量

{$article.list}

array

文章列表,字段详情请看下面的【文章详情页】

{$article.paging.html}

string

文章分页的HTML

{$article.paging.count}

int

文章分页的文章总条数

{$article.paging.currentPage}

int

文章分页的当前页面

{$article.paging.countPage}

int

文章分页的总页码

{$article.paging.pageSize}

int

文章分页的每页条数

标签:分类页

标签返回类型说明

{$cid}

string

分类ID

{$category}

array

分类对象,字段详情请看下面的【分类】

{$pageNum}

int

当前页码,默认为1

{$pageSize}

int

文章每页条数

{$article.count}

int

文章总数量

{$article.paging}

string

文章分页的HTML

{$article.list}

array

文章列表,字段详情请看下面的【文章详情页】

{$article.paging.html}

string

文章分页的HTML

{$article.paging.count}

int

文章分页的文章总条数

{$article.paging.currentPage}

int

文章分页的当前页面

{$article.paging.countPage}

int

文章分页的总页码

{$article.paging.pageSize}

int

文章分页的每页条数

标签:标签页

标签返回类型说明

{$tab}

string

标签名

{$pageNum}

int

当前页码,默认为1

{$pageSize}

int

文章每页条数

{$article.count}

int

文章总数量

{$article.paging}

string

文章分页的HTML

{$article.list}

array

文章列表,字段详情请看下面的【文章详情页】

{$article.paging.html}

string

文章分页的HTML

{$article.paging.count}

int

文章分页的文章总条数

{$article.paging.currentPage}

int

文章分页的当前页面

{$article.paging.countPage}

int

文章分页的总页码

{$article.paging.pageSize}

int

文章分页的每页条数

标签:文章详情页

标签返回类型说明

{$article.id}

string

文章ID

{$article.cid}

string

分类ID

{$article.category}

array

分类对象,字段详情请看下面的【分类】

{$article.title}

string

文章标题

{$article.intro}

string

文章描述

{$article.img}

string

文章中的第一张图片

{$article.content}

string

文章内容

{$article.isTop}

bool

文章是否置顶

{$article.isPrivate}

bool

文章是否为私密

{$article.isComment}

bool

文章是否可以评论

{$article.isFk}

bool

文章内容是否使用的FK标记语言

{$article.comments}

int

文章评论数

{$article.views}

int

文章浏览数

{$article.tag}

array

文章标签对象,字段详情请看下面的【标签】

{$article.time}

string

文章创建时间,通createTime

{$article.updateTime}

string

文章更新时间

{$article.createTime}

string

文章创建时间

{$article.url}

string

文章的URL链接

{$article.prev}

array

上一篇文章,存在时为文章对象,包含$article的当前所有字段,不存在时为false

{$article.next}

array

下一篇文章,存在时为文章对象,包含$article的当前所有字段,不存在时为false

{$comment.count}

int

当前文章的评论总数

{$comment.list}

array

当前文章评论列表,字段详情请看下面的【评论板页】

{$comment.html}

string

当前文章评论列表的HTML

{$comment.paging.html}

string

评论分页的HTML

{$comment.paging.count}

int

评论分页的文章总条数

{$comment.paging.currentPage}

int

评论分页的当前页面

{$comment.paging.countPage}

int

评论分页的总页码

{$comment.paging.pageSize}

int

评论分页的每页条数

标签:分类

标签返回类型说明

{$category.id}

string

分类ID

{$category.name}

string

分类名称

{$category.intro}

string

分类简介

{$category.count}

int

分类下的文章数量

{$category.url}

string

分类的链接

标签:标签

标签返回类型说明

{$tag.name}

string

标签名称,多标签以空格分割

{$tag.html}

string

标签html列表,a标签列表,包含url跳转

{$tag.list}

array

标签列表对象,包含:name、html、url字段

标签:评论区

标签返回类型说明

{$comment.id}

string

评论ID

{$comment.pid}

string

父级评论的ID,默认为0

{$comment.admin}

bool

是否为管理员的评论

{$comment.content}

string

评论内容

{$comment.ip}

string

评论IP

{$comment.time}

string

评论时间

主题模板中的hook

<!DOCTYPE html>

<html lang="zh-Hans">

<head>

<!-- hook.head_header -->

<meta http-equiv="Content-Type" content="text/html" charset="UTF-8"/>

<title>{$conf.title}</title>

<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>

<meta name="keywords" content="{$conf.key}"/>

<meta name="description" content="{$conf.desc}"/>

<!-- hook.meta -->

<link rel="shortcut icon" href="{#LIB_STYLE}logo.png"/>

<link rel="stylesheet" href="{#LIB_STYLE}fk.css"/>

<link rel="stylesheet" href="{#TPL_STYLE}main.css"/>

<!-- hook.css -->

<script src="{#LIB_STYLE}common.js"></script>

<!-- hook.script -->

<!-- hook.head_footer -->

</head>

<body>

<!-- hook.body_header -->

<!-- hook.body_footer -->

</body>

</html>

开发主题模板过程中,页面请务必保留这几个扩展标签,它以html的注释形式存在,前缀为hook.,它的作用是提供扩展机制的支持,每个扩展标签的位置如上面代码所示,说明如下:

<!-- hook.head_header --> 放在head标签中的最上面。

<!-- hook.meta --> 放在head标签中meta标签的下面。

<!-- hook.css --> 放在head标签中link标签的下面。

<!-- hook.script --> 放在head标签中script标签的下面。

<!-- hook.head_footer --> 放在head标签中的最下面。

<!-- hook.body_header --> 放在body标签的最上面。

<!-- hook.body_footer --> 放在body标签的最下面。

扩展应用开发

说明

  • 扩展用于定制 prain 的功能
  • 扩展在ext文件夹下

文件结构

default 扩展文件夹,名称不能包含中文,不能为纯数字,应放在ext文件夹中

├─conf.php 配置文件(必须)

├─icon.png 扩展的图标,300*300(必须)

├─main.php 扩展入口文件(非必须)

├─common.php 扩展公共文件(非必须)

├─setting.php 设置页面文件(非必须)

├─install.php 安装文件(非必须)

└─uninstall.php 卸载文件(非必须)

开发规范

  • 代码中的变量、函数名使用小驼峰命名法,例如:userPassword
  • 保持格式的整洁,Tab缩进4个字符
  • 做好代码的注视,能更方便的查阅代码

conf配置文件说明

<?php

// 配置文件

return array (

'id' => '扩展的ID',

'type' => '应用类型,主题为tpl,扩展为ext',

'author' => '作者,开发者的账号',

'name' => '扩展的名称',

'intro' => '扩展的简述',

'price' => '扩展的价格,0为免费,仅支持2位小数',

'home' => '扩展的主页',

'version' => '版本号,格式为1.0.0',

'limit' => '限制清雨的最低版本号,格式为1.0.0',

'depend' => '依赖的应用ID,空格隔开'

);

?>

main文件说明

该文件可有可无,与tpl中的main.php一个概念,用于配置页面路由和业务逻辑,不同的是该文件的权重要高于tplmain.php权重,在prain系统中,我们推荐开发独立的功能使用扩展,如果你只是为了丰富页面的多样化,那么建议写在tpl中。

common文件说明

该文件可有可无,common是扩展的公共文件,如果存在该文件,则每个页面都会引用,一般用于操作hook,例如后台添加菜单,那么应当写在common中,而不是main中,这是唯一与main有区别的地方,common的权重要高于main,common适合写hook,main适合写页面路由以及业务逻辑。

setting文件说明

该文件可有可无,setting是扩展的配置页面文件,如果存在该文件,扩展管理中的该扩展中会有设置按钮,点击按钮进入该setting页面,一般用于扩展功能所需要配置的设置页面,当然,你也可以直接通过main来自定义页面和路由。

install文件说明

该文件可有可无,如果存在该文件,install安装文件会在扩展安装的时候执行一次,一般用于提前创建好数据库之类的操作。

uninstall文件说明

该文件可有可无,如果存在该文件,uninstall卸载文件会在扩展卸载的时候执行一次,一般用于清除扩展造成的数据垃圾。

后台添加一个自定义页面

通常页面的开发就是引入当前主题的header.phpfooter.php文件,这样打开的页面与主题风格会更加贴近,用户体验更好,那么你的页面中可以这么写:

main.php文件

//实例化模板编译

$demoTpl = new Tpl([

'path' => '/ext/demo/',

'name' => 'view',

]);

//demo页面

if($adminPage == 'demo'){

$content = '上善若水';

include $demoTpl->view('manage');

}

demo.php文件,位于文件夹:/ext/demo/view/

{include admin header}

<div class="title">demo页面</div>

<article>{$content}</article>

{include admin footer}

前台添加一个自定义页面

同样利用上面的方式来做,唯一不同的是demo.php文件中include后面的admin改为tpl,如下:

{include tpl header}

<div class="title">demo页面</div>

<article>{$content}</article>

{include tpl footer}

hook钩子的基本使用

扩展应用的是hook钩子机制,具体hook钩子位置请查看lib/admin视图文件的注视标签,以hook为前缀,例如<!-- hook.admin_index_header--><!-- hook.admin_model_link--><!-- hook.model_index--><!-- hook.css-->,该标签你可以这样来理解,hook为前缀的说明是扩展的hook,点后面的admin_index_header为hook名称。

hook名称多语言以下划线分割,具体含义如下所示:

admin前缀表示后台视图层钩子,用于插入html

admin_model前缀表示后台业务层钩子,用于业务上的操作

model前缀前面无admin,表示前台业务层钩子,用于业务上的操作

其它表示前台视图层钩子,用于插入html

使用hook之前,先了解一下hook函数吧!

hook函数

语法:hook($name, $html)

  • 功能说明:钩子操作

$name string 必填 hook名称

$html string|function html或业务处理方法

hook示例:插入css样式

//common.php文件

<?php

//前端页面添加a1样式文件

hook('css','/ext/demo/style/a1.css');

//后端页面添加a2样式文件

if($page == 'admin'){

hook('admin_css','/ext/demo/style/a2.css');

}

?>

hook示例:后台添加菜单

<?php

//后台侧栏菜单添加一个新菜单

hook('admin_sidebar_menu_3','<a href="/admin/demo">新菜单一</a>');

//也可以通过function来插入一个新菜单

hook('admin_sidebar_menu_3',function(){

return '<a href="/admin/demo">新菜单二</a>';

});

?>

hook示例:文章列表添加字段

业务层hook钩子,这里需要看index.php文件中的钩子位置,结合当前的环境变量通过global来处理数据。

<?php

//首页文章列表,添加一个序号字段,前端模板的文章列表就可以使用这个字段

//当前环境变量有$article(文章对象)

hook('model_index',function(){

global $article;

//遍历文章列表,添加order字段

$order = 1;

foreach($article'list' as $key => &$value){

$value'order' = $order++;

}

});

?>

配置页开发

说明

无论是开发扩展应用还是主题模板,当需要保存配置信息的时候,我们可以使用ini函数来保存或获取配置信息,接下来是关于ini函数的介绍。

ini函数

语法:ini($name, $key, $value)

  • 功能说明:获取或保存扩展中的配置

$name string 必填 唯一名称,一般为扩展或主题的id

$key string|array 获取或保存的key

$value mix 需保存的数据

  • 传参说明

//设置a=1

ini('demo','a',1);

//如果第二个参数为数组,则以追加的方式设置b=2,c=3

ini('demo','b'=>2,'c'=>3);

//设置d=4,e=5,与上面不同的是如果第三个参数为true,则先清空再设置

ini('demo','d'=>4,'e'=>5,true);

//获取demo中的所有数据

ini('demo');

//获取demo中的a数据

ini('demo','a');

//删除demo

ini('demo',false);

  • 前端调用

//ini('demo','title','上善若水');

{$ini.demo.title}

//ini('demo','config','name'=>'濛濛细雨','intro'=>'没有什么不同');

{$ini.demo.config.name}

{$ini.demo.config.intro}

ini函数使用示例

ini函数一般用在install.php、uninstall.php或main.php中,例如我们开发的主题模板中有广告图,后台需要拥有一个广告图设置功能,那么我们就需要将上传的图片链接保存起来,如下:

第一步:安装时需要增加一个img字段,install.php文件:

<?php

//为你的主题demo增加img轮播图调用字段,用于存储图片列表

ini('demo','img','/tpl/demo/img/1.jpg');

?>

第二步:卸载时需要删除主题demo用到的所有字段,避免数据垃圾的产生,uninstall.php文件:

<?php

//参数为false的时候会清空demo的所有字段

ini('demo',false);

?>

第三步:安装和卸载已经做好img字段的处理,这一步做配置页的表单操作,main.php文件:

<?php

//判断是否为设置页

if($settingPage'demo'){

//POST表单处理

if($method == 'POST'){

//接收由前端传过来的img参数数据

$img = post('img');

if($img){

//保存配置

ini('demo','img',$img);

//如果前端通过ajax提交的,返回数据一般用到 msg(返回成功消息)、err(返回错误消息)、ret(返回数据消息) 这三个函数

msg('保存成功');

}

err('请上传图片');

}

}

?>

第四步:后台配置页面,setting.php文件:

<?php exit('404');?>

{include admin header}

<div class="title">广告图设置</div>

<div id="imgSetting">

<input type="hidden" name="img" value=""/>

<img src="{$ini.demo.img}" alt="广告图"/>

<div class="btn" onclick="uploadImg">上传</div>

<input type="submit" value="提交"/>

</div>

<script>

function uploadImg(){

sx.upload({

success(res){

sx('#imgSetting input').val(res0);

sx('#imgSetting img').attr('src',res0);

}

})

}

function submit(){

sx.ajax('{$url}','#imgSetting').then(res => {

sx.pop(res.message)

})

}

</script>

{include admin header}

数据库操作

prain中的数据库操作只需要记住db()、dbSave()、dbDelete()、dbUpdate()这四个方法,以下是这些方法的使用说明。

db 查询

语法:db($name, $cond = ], $orderby = [, $page = 0, $pagesize = 0)

  • 功能说明:查询数据
  • 查询成功:如果该数据为数组,则返回数组格式,如果为纯文本,则返回纯文本
  • 查询失败:返回空数组

$name string 必填 表名

$cond array 选填 条件查询

$orderby array 选填 排序

$page int 选填 页数

$pagesize int 选填 每页条数

如果该数据库为二维数组,可通过以下条件查询来获取相应的数据

//我们用article表(位于db文件夹中的article.php文件,存放着文章列表数据)来说明db()的用法

//返回文章的所有数据

db('article');

//返回所有被置顶的文章

db('article', 'top' => 1);

//返回url名称为fk的这篇文章

db('article', 'name' => 'fk');

//返回所有的文章,并先按照最新的时间排序,再按照置顶排序

db('article', ], ['time' => 1, 'top' => 1);

//返回文章的第2页数据,条数为30,并先按照最新的时间排序,再按照置顶排序,

db('article', ], ['time' => 1, 'top' => 1, 2, 30);

//相信以上条件查询可以满足大多数业务了,但仍然无法体现到db()方法的优秀,接下来我们玩玩更高级的$cond查询方式

//

//搜索文章标题有雨烟两字的所有数据

db('article', 'title' => ['LIKE' => '雨烟']);

//查询文章浏览量大于100的所有数据,支持> < >= <= ==这五种判断

db('article', 'views' => ['>' => 100]);

//查询文章拥有笔记标签的所有数据,说白了就是针对三维数组的查询,tag字段存储的是数组,而上面的LIKE是用于字段为字符串类型的查询

db('article', 'tag' => ['IN' => '笔记']);

//返回置顶的文章,且浏览量大于100的所有数据

db('article', 'top' => 1, 'views' => ['>' => 100]);

dbSave 保存

语法:dbSave($name, $data)

  • 功能说明:保存数据
  • 保存成功:返回写入数据库的字符数
  • 保存失败:返回false

$name string 必填 表名

$data string|array 必填 保存数据

$arr = [

[

'title' => '半载浮生',

'content' => '既不回头,何必不忘。既然无缘,何须誓言。今日种种,似水无痕。明夕何夕,君已陌路。'

],

[

'title' => '静默的流年',

'content' => '站在青春的夕阳下,感受着过往,留下浅浅的笑靥,或许这就是青春的流逝吧!'

]

];

//如果product表不存在,则会创建

dbSave('product',$arr);

dbInsert 新增

语法:dbInsert($name, $data, $index=true)

  • 功能说明:插入新数据
  • 新增成功:返回true
  • 新增失败:返回false

$name string 必填 表名

$data string|array 必填 插入的新数据

$index bool 选填 是否根据索引新增数据

$arr = [

'title' => '半载浮生',

'content' => '既不回头,何必不忘。既然无缘,何须誓言。今日种种,似水无痕。明夕何夕,君已陌路。'

];

//在product表中插入一条新数据

dbInsert('product', $arr);

dbDelete 删除

语法:dbDelete($name, $cond=[])

  • 功能说明:删除数据
  • 删除成功:返回true
  • 删除失败:返回false

$name string 必填 表名

$cond array 选填 条件删除,使用方式参考db()的$cond参数

$index bool 选填 是否重新索引,数组的key从0开始,默认不重新索引

//删除整个product表数据

dbDelete('product');

//删除product表id字段为1的这条数据

dbDelete('product', 'id' => 1);

dbUpdate 修改

语法:dbUpdate($name, $cond, $data)

  • 功能说明:修改数据
  • 修改成功:返回true
  • 修改失败:返回false

$name string 必填 表名

$cond array 必填 条件更新

$data string|array 必填 更新数据

$arr = [

'title' => '半载浮生',

'content' => '既不回头,何必不忘。既然无缘,何须誓言。今日种种,似水无痕。明夕何夕,君已陌路。'

];

//更新product表id字段为1的这条数据

dbUpdate('product', 'id' => 1, $arr);

//更新product表所有数据的top为1

dbUpdate('product', ], ['top' => 1);

如果数据表demo为一维数组,例如为这样的数据格式

[

'title' => '这是标题',

'content' => '今生有缘'

];

那么更新demo表的title字段就可以这样做,第二个参数不再是条件查询,而是指定字段数据更新,第三个参数勿传

dbUpdate('demo', 'title' => '不错,这就是标题');

前端函数库

介绍

common.js的sx是一个快速、简洁的JavaScript框架,它封装了JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互,如果你很熟悉jQuery的话,那么本文档对你来说是非常易懂的。

核心特性可以总结为:

  • 具有高效灵活的元素选择器
  • 具有灵活的链式语法,减少代码量
  • 封装了常用的功能方法,简单易用

在jQuery中选择器用$,为了避免冲突,清雨使用sx,例如给某个元素添加一条class,jQuery中:$('.title').addClass('.light'),那么在清雨中:$('.title').addCss('.light'),有些方法名称是与jQuery一样的,有些则不同,下面介绍一下公共方法。

sx 选择器

语法: sx(string,object)

说明: 使用方式与jQuery一样,支持各种组合方式,方法返回文档中匹配指定CSS选择器的所有元素,例如:

//选择器-具体也可参照原生的querySelectorAll

sx('a',object) //获取object对象下的所有a标签对象

sx('.test') //类选择器

sx('#test') //ID选择器

sx('#test span') //组合选择器

sx('#test .demo') //组合选择器

sx('.demo span') //组合选择器

sx('#test .demo a') //组合选择器

sx('div.item') //获取文档中所有 class="item" 的div元素

sx('divdata-active') //获取文档中包含 "data-active" 属性的div元素

sx('divdata-active="1"') //获取文档中包含 "data-active=1" 属性的div元素

sx('inputtype=text') //获取文档中type类型为text的input元素

sx('inputname=demo') //获取文档中name类型为demo的input元素

sx('div > p') //获取每个父元素为div里的p元素

sx('div,p,span') //获取所有的div,p,span元素

//加载完成-页面加载完成后,执行该方法,等同sx.ready()方法!

sx(function(){

console.log('hello world!');

})

each 遍历

语法: sx(selector).each(function(index,element,elementAll,length))

index {int} 选择器的 index 位置

element {node} 当前的元素(也可使用 "this" 选择器)

elementAll {node} 当前遍历的元素集合

length {int} 元素集合的总长度

提示: function的this指的遍历的当前对象

sx('.demo p').each(function(i,el){

//i 为当前对象的索引值

//el 为当前对象,等同于this

//给第三个p元素下的span元素添加点击事件

if(i == 2){

//此时的this为当前的p元素对象

sx('span',this).click(funciton(){

//此时的this为当前的span元素对象,不要混淆哦!

console.log(this);

});

}

});

i 获取指定索引的对象

语法: sx(selector).i(index)

//获取第三个p元素的html

sx('.demo p').i(2).html();

val 获取或设置对象的值

语法: sx(selector).val(value)

提示: 元素的值是通过 value 属性设置的。该方法大多用于 input 元素。但也支持select和textarea!

//获取值

sx('#input').val();

//设置值

sx('#input').val('hello world');

html 获取或设置html

语法: sx(selector).html(content)

提示: 获取集合中第一个匹配元素的HTML内容 或 设置每一个匹配元素的html内容。

//获取该对象的html内容

sx('.demo').html();

//设置该对象的html内容

sx('.demo').html('<div>hello world</div>');

//设置该对象的html内容,可传入动态创建的DOM

var div = sx.c('div');

div.innerHTML = 'hello world';

sx('.demo').html(div);

form 获取表单内容

语法: sx(selector).form()

<div id="demo">

<input type="text" name="title" value="标题"/>

<textarea name="content" rows="3" cols="20">内容</textarea>

</div>

<script>

console.log(sx('#demo').form());

//结果返回json格式对象

//{

// title: "标题",

// content: "内容"

//}

</script>

append 内部尾部插入内容

语法: sx(selector).append(content)

sx('.demo').append('<div>hello world</div>');

prepend 内部头部插入内容

语法: sx(selector).prepend(content)

sx('.demo').prepend('<div>hello world</div>');

before 前面插入内容

语法: sx(selector).before(content)

sx('.demo').before('<div>hello world</div>');

after 后面插入内容

语法: sx(selector).after(content)

参数: content {string|object} DOM元素,文本节点,HTML字符串

sx('.demo').after('<div>hello world</div>');

page 获取距离窗口偏移量

语法: sx(selector).page()

sx('.demo').page();

getCss 获取style样式属性

语法: sx(selector).getCss(attr)

//获取该对象的左外边距

sx('.demo').getCss('marginLeft');

del 删除对象

语法: sx(selector).del()

<div class="demo">

<p>我爱php</p>

<p>我爱java</p>

<p>我爱c++</p>

</div>

//删除class为demo元素下的第二个p

sx('.demo p').s(1).del();

//删除class为demo元素下的所有p

sx('.demo p').del();

offset 获取距离屏幕偏移量

语法: sx(selector).offset()

返回: object格式 {left:x, top:y}

css 设置或获取对象style

语法: sx(selector).css(name, value)

attr 设置或获取对象Attribute

语法: sx(selector).attr(name, value)

delAttr 删除Attribute属性

语法: sx(selector).delAttr(name)

delCss 删除对象class

语法: sx(selector).delCss(name)

clone 元素克隆

语法: sx(selector).clone(fn)

click 添加点击事件

语法: sx(selector).click(fn)

on 添加事件

语法: sx(selector).on(type, fn, bool)

find 查询后代元素

语法: sx(selector).find(selector)

children 查询所有直接子元素

语法: sx(selector).children(selector)

childrens 查询所有子元素

语法: sx(selector).childrens()

siblings 查询兄弟节点

语法: sx(selector).siblings(selector)

prev 获取上一个兄弟节点

语法: sx(selector).prev(selector)

next 获取下一个兄弟节点

语法: sx(selector).next(selector)

parent 查找当前的祖先元素

语法: sx(selector).parent()

返回: 所有的祖先元素

parents 查找所有的祖先元素

语法: sx(selector).parents()

返回: 所有的祖先元素

addCss 给对象添加class

语法: sx(selector).addCss(name)

hasCss 判断对象是否存在class

语法: sx(selector).hasCss(name)

hasStyle 判断对象是否存在style

语法: sx(selector).hasStyle(name)

toggleCss 存在删除,不存在则创建

语法: sx(selector).toggleCss(nameA,nameB,fnA,fnB)

show 显示对象

语法: sx(selector).show()

hide 隐藏对象

语法: sx(selector).hide()

fadeIn 动画:淡入效果

语法: sx(selector).fadeIn(speed, callback)

fadeOut 动画:淡出效果

语法: sx(selector).fadeOut(speed, callback)

fadeToggle 动画:淡出显示隐藏

语法: sx(selector).fadeToggle(speed, callback)

slideDown 动画:向下滑动显示

语法: sx(selector).slideDown(speed, callback)

slideUp 动画:向上滑动隐藏

语法: sx(selector).slideUp(speed, callback)

slideToggle 动画:滑动显示隐藏

语法: sx(selector).slideToggle(speed, callback)

sx.c 创建节点

语法: sx.c(tagName)

sx.sp 阻止冒泡

语法: sx.sp(event)

sx.pd 阻止默认行为

语法: sx.pd(event)

sx.data 获取或设置数据缓存

语法: sx.data(name,value)

提示: 本方法利用sessionStorage存储数据数据,生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就会被清空。

本方法的设计初衷是为了更加方便的使用,同时最主要的是打破sessionStorage的存储方式界限,可以存储类型的值,而不在是单纯的字符串,可以为number数字,array数组,object对象,function方法,请看下面使用示例:

/**

  1. 重要提示:赋值完全等于取值,如果赋值数字类型,那么取值时也为数字类型
  2. 如果赋值为json对象,那么取值也为对象,array数组和function方法同理

*/

//获取整个sessionStorage

sx.data();

//获取t1值

sx.data('t1');

//设置t1值

sx.data('t1',123);

//设置t1值,也可以为function方法,任何数据类型都支持

sx.data('t1',function(e){

console.log(e)

});

sx.data('t1')('我是function'); //打印出:我是function

//设置t1值,获取后也是该对象,不是字符串哦,如果你设置字符串类型的json,那么获取到的也是字符串类型的json

sx.data('t1',{t2:123,t3:456});

//同时设置t1、t2、t3值,

sx.data({t1:123, t2:456, t3:789});

sx.localData 获取或设置数据缓存

语法: sx.localData(name,value)

提示: 本方法利用localStorage存储数据数据,生命周期是永久的,无时间限制,除非用户手动清除本地缓存。

使用方式同sx.data,数据存储方式也一样的。

sx.isMobile 是否为移动端

语法: sx.isMobile()

sx.obj2str 对象转为字符串

语法: sx.obj2str(object)

sx.ready 加载完毕后执行

语法: sx.ready(fn)

sx.ajax 异步请求

语法: sx.ajax(json)

/**

  1. json说明:
  2. url:请求地址
  3. type:请求类型,默认为post,可选值:post,get
  4. timeout:网络超时,默认为15000毫秒
  5. async:是否异步请求,默认为true
  6. header:请求头设置
  7. form:用于绑定需要提交表单的容器,传class或id,默认绑定id:form
  8. 如果该参数存在,无需使用data传参
  9. data:要求为Object或String类型的参数,发送到服务器的数据。
  10. json:是否将请求过来的数据自动转为json对象,默认为true,
  11. success:请求成功之后的回调函数
  12. error:请求失败之后的回调函数
  13. complete:不管请求成功还是失败,都会调用

*/

//第一种方式

sx.ajax({

url:'login',

data:{password:1234},

success(res){

if(res.error){

sx.pop(res.message);

}else{

sx.jump('admin');

}

}

});

//第二种方式,支持Promise,推荐使用

sx.ajax('login',{password:1234}).then(res=>{

if(res.error){

sx.pop(res.message);

}else{

sx.jump('admin');

}

});

sx.pjax 页面无刷新

语法: sx.pjax(json)

/**

  1. json说明:
  2. el:容器
  3. url:请求地址
  4. type:请求类型,默认为post,可选值:post,get
  5. loading:加载动画
  6. success:请求成功之后的回调函数
  7. error:请求失败之后的回调函数
  8. complete:不管请求成功还是失败,都会调用

*/

sx.pjax({el:'#pjax-content'});

sx.scroll 获取滚动条偏移量

语法: sx.scroll(pos)

返回: {x,y}

sx.scrollAni 平滑滚动到对象位置

语法: sx.scrollAni(el, offset, duration)

sx.keydown 按键回调

语法: sx.keydown(key, callback)

//第一种方式,监听指定的按键

sx.keydown(13,function(){

console.log('我按了回车键');

})

//第一种方式也可以这么来

function hi(a=11){

console.log('我是'+a);

}

sx.keydown(13,hi);

sx.keydown(13,'hi(123)');

//第二种方式,监听所有的按键

sx.keydown(function(key){

console.log('我按了键盘,键盘码为:',key);

})

sx.jump 跳转网页

语法: sx.jump(url)

sx.setDisplay 设置默认display

语法: sx.setDisplay(el)

sx.getDisplay 获取默认display

语法: sx.getDisplay(el)

sx.pop 提示框

语法: sx.pop(options, time = 2000)

sx.alert 弹窗

语法: sx.alert(options, yes, no)

sx.prompt 顶部对话框

语法: sx.prompt(options, yes, no)

sx.confirm 确认窗

语法: sx.confirm(url, text)

sx.upload 文件上传

语法: sx.upload(options)

accept:限制的文件类型

url:请求地址,默认为官方的/upload

name:文件名称,默认为时间戳+序号命名

path:上传的路径,默认为/db/upload

absolutePath:返回的路径是否为绝对路径,默认true

success:请求成功之后的回调函数

error:请求失败之后的回调函数

complete:不管请求成功还是失败,都会调用

sx.delArticle 删除文章

语法: sx.delArticle(id)

后端函数库

upload 文件上传

语法:upload($arr)

inputName string 选填 input控件的name值,如果为多文件上传,name后面要加[],默认为:file

path string 选填 上传路径,默认为:db/upload/当前年月/

nameType string 选填 上传成功后的命名方式,可选值为name(以文件名称命名)、time(时间戳命名),默认为:time

name string|bool 选填 上传成功后指定命名,默认为:false

size int 选填 限制文件大小上传,默认为:100

ext string|bool 选填 限制文件类型上传,多类型用|分割,默认为:false

domain bool 选填 上传成功后返回的文件路径是否带网址,默认为:true

imgThumb array 选填 如果上传的文件为图片,是否生成缩略图,默认为:false

imgThumb'width' int 选填 缩略图的宽,默认为:300

imgThumb'height' int 选填 缩略图的高,默认为:300

imgThumb'clip' bool 选填 是否裁剪,true:裁剪缩略 false:全图等比例缩略,默认为:true

//例如上传图片,前端图片上传的URL地址为:https://xueluo.cn/uploadImage

//后端:你的应用中main.php可以这些来接收图片的上传:

if($page == 'uploadImage'){

$arr = upload([

'name' => 'logo.jpg', //上传的文件命名为logo.jpg,不传该参数将以时间戳命名

'ext' => 'jpg', //限制上传类型为jpg文件

'path' => 'ext/demo/img', //上传到服务期的文件路径,不传该参数默认上传到db/upload中

'imgThumb' => [ //生成缩略图,裁剪缩略

'width' => 300,

'height' => 300

],

]);

exit(type($arr,'json'));

}

//前端:你的应用中setting.php中可以这样写

<script>

//上传图片函数,给按钮添加点击事件,执行upload()即可

function upload(){

sx.upload({

url:'uploadImage', //请求地址,不传默认为upload

success(e){ //上传成功的回调

console.log(e)

}

})

}

</script>

imgThumb 生成缩略图

语法:imgThumb($imgUrl, $width=300, $height=300, $clip=true, $pre='thumb_')

$imgUrl string 图片的完整路径

$width int 缩略图宽度

$height int 缩略图高度

$clip bool true:裁剪缩略 false:全图等比例缩略

$pre string 缩缩略图前缀

$thumb = imgThumb('/db/upload/20230822155724.jpg', 100, 100);

echo $thumb; //生成的缩略图地址为: /db/upload/thumb_20230822155724.jpg

type 类型获取与转换

语法:type($data,$type)

$data mixed 必填 数据

$type string 非必填 转换类型,有效值:str|string|int|int|float|object|array|bool|json|stripTags|trim|urlencode|urldecode

//获取类型

type($data);

//数据转为字符串类型

type($data,'str');

//数据转为数字类型

type($data,'int');

get 获取URL参数

语法:get($key,$type,$def)

$key mixed 必填 字段

$type string 非必填 转换类型,同上type的$type参数

$def mixed 非必填 数据为空时设置的数据

print_r(get());

/**

  1. 例子:http://xxx.xxx/index/page.html?a=1&b=2
  2. 返回
  3. array(
  4. 0 => index,
  5. 1 => page,
  6. a => 1,
  7. b => 2,
  8. )

*/

//返回index

get(0);

//返回1,默认为字符串类型

get(a);

//返回参数a的值,并转为int类型

$num = get('a','int');

//返回参数c的值,并转为int类型,如果改参数不存在,则返回3

$num = get('c','int',3);

post 获取post参数

语法:post($key,$type,$def)

使用方式同get(),只不过接收的是post表单提交过来的数据

$key mixed 必填 字段

$type string 非必填 转换类型,同上type的$type参数

$def mixed 非必填 数据为空时设置的数据

save 数据覆盖保存

语法:save($path,$data)

$path string 必填 文件路径,不存在则创建

$data mixed 必填 要保存的数据

ajax 打印消息

语法:ajax($error, $data)

$error bool 必填 是否报错

$data mixed 必填 打印消息

check 正则验证

语法:check($str,$type,$min,$max)

$str bool 必填 字符串

$type mixed 必填 类型

$min bool 非必填 最小值

$max mixed 非必填 最大值

//示例

if(check($str,'str',5,12)){

echo '不是一个5-12的字符串';

}

type:

str //字母数字 - 支持字符的长度限制

num //纯数字 - 支持字符的长度限制

en //纯字母 - 支持字符的长度限制

zh //中文 - 支持字符的长度限制

name //中英文数字 - 支持字符的长度限制

length //字符串长度 - 支持字符的长度限制

ip //ip

date //日期

url //网址

pc //邮编

mail //邮箱

mp //手机号

tel //座机号

idCard //身份证号

isMobile 判断是否为移动端

语法:isMobile()

isHttps 判断是否为HTTPS

语法:isHttps()

getUrl 获取完整的URL地址

语法:getUrl()

jump 页面跳转

语法:jump($url)

$url string 非必填 页面地址

pages 分页

语法:pages($url, $total, $page, $pagesize)

例如:pages('user/list/{page}.html', 100, 10, 5);

$url string 必填 分页链接 {page}为页码

$total int 必填 数据总数

$page int 必填 当前页

$pagesize int 非必填 每页显示多少条数据

dates 格式化时间

说明:返回格式为 2018-11-02 19:01:13

语法:dates($timestamp)

$timestamp int 非必填 时间戳

humanDate 友好显示时间

说明:返回格式为 30秒前、10分钟前、2天前、1个月前,3年前

语法:humanDate($timestamp)

$timestamp int 必填 时间戳

humanSize 友好显示字节大小

说明:返回格式为 4.21M

语法:humanSize($size)

$size int 必填 字节大小

downFile 下载文件

语法:downFile($path)

$path string 必填 文件路径

randStr 随机字符串

语法:randStr($len)

$len int 必填 字符长度

ip 获取用户IP

语法:ip()

arrSort 数组多字段排序

语法:arrSort($arr, $key, $desc = true)

$arr array 必填 数组

$key int|string 必填 1:一维数组降序,0:一维数组升序,根据指定key排序

$desc string 非必填 正序倒序

arrWhere 数组条件查找

说明:对数组进行查找,排序,筛选,支持多种条件排序

语法:arrWhere($arr, $cond = ], $orderby = [, $page = 0, $pagesize = 0)

$arr array 必填 数组

$cond array 必填 条件

$orderby array 非必填 排序

$page int 非必填 当前页

$pagesize int 非必填 每页数据条数

curl 发起请求

语法:curl($url, $params = [], $method = 'POST', $cookie = '')

$url array 必填 网络地址

$params array 必填 参数

$method array 非必填 请求类型

$cookie int 非必填 Cookie

︿