Prain清雨博客系统开发文档

下载

prain: v1.3.0 prainv1.3.0

环境要求

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

安装

1. 服务器:推荐使用阿里云服务器,比较稳定,传送阵:阿里云服务器

2. 环境部署:推荐使用宝塔面板来安装,一键PHP环境部署,送你10850元礼包,点我领取

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(res[0]);
                sx('#imgSetting img').attr('src',res[0]);
            }
        })
    }
    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('div[data-active]')     //获取文档中包含 "data-active" 属性的div元素
sx('div[data-active="1"]') //获取文档中包含 "data-active=1" 属性的div元素
sx('input[type=text]')     //获取文档中type类型为text的input元素
sx('input[name=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方法,请看下面使用示例:

/**
* 重要提示:赋值完全等于取值,如果赋值数字类型,那么取值时也为数字类型
* 如果赋值为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)

/**
* json说明:
* url:请求地址
* type:请求类型,默认为post,可选值:post,get
* timeout:网络超时,默认为15000毫秒
* async:是否异步请求,默认为true
* header:请求头设置
* form:用于绑定需要提交表单的容器,传class或id,默认绑定id:form
*       如果该参数存在,无需使用data传参
* data:要求为Object或String类型的参数,发送到服务器的数据。
* json:是否将请求过来的数据自动转为json对象,默认为true,
* success:请求成功之后的回调函数
* error:请求失败之后的回调函数
* 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)

/**
* json说明:
* el:容器
* url:请求地址
* type:请求类型,默认为post,可选值:post,get
* loading:加载动画
* success:请求成功之后的回调函数
* error:请求失败之后的回调函数
* 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());
/**
 * 例子:http://xxx.xxx/index/page.html?a=1&b=2
 * 返回
 * array(
 *    0 => index,
 *    1 => page,
 *    a => 1,
 *    b => 2,
 * )
*/

//返回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
评论留言
验证码
一共12条留言
  • 101.93.6.308月前回复

    12123123

  • 219.232.77.1059月前回复

    这个程序的亮点不就是不用数据库吗…

  • 游客 (101.65.24.54)2023年前回复

    有关于excerpt的么,主页想弄个摘要

    • 作者2023年前回复

      每篇文章都有摘要,字段是使用的字段是intro,首页可以放置摘要的,

      • 游客 (36.112.3.129)2023年前回复

        程序非常好

  • 游客 (39.171.143.66)2023年前回复

    扩展性很强

  • 游客 (113.247.129.233)2023年前回复

    数据量负载有多大?有mysql版本吗

    • 游客 (27.128.186.150)2023年前回复

      目前负载量没有限制,只要你的内存够大就行。

  • 游客 (106.57.115.79)2022年前回复

    666

  • 游客 (60.16.48.46)2022年前回复

    遇见晚了,哎哎,不然我铁定折腾一波。

    • 游客 (27.128.186.150)2022年前回复

      趁现在年轻,在折腾折腾吧

    • 游客 (42.93.119.208)2022年前回复

      找寻多年终于找到一款简洁明了的系统,加油

︿