《HongCMS开发者手册》–二次开发指南

一、前言:
说实在的,很怕写文档,特别是这种开发文档,无法知道别人需要什么样或者说什么程度的描述,自己高兴的事别人未必开心。所以,这个文档总的想法是将重点介绍清楚,让用户了解系统脉络,细枝末节的技术google就行了。

前些日子因参与其它公司的项目,研究了些PHP开发框架,如CI, ThinkPHP等这些,觉得这些小型框架对我来说很不爽,因为本人一直
喜欢4S的开发理念,即:Safe, Simple, Small, Stable (安全,简单,小巧,稳定),不刻意追求大而全的东西,认为简单是最美的。

这和性格有关,也很难改变。就拿CI来说吧,前台游客只要一进入网站,就有至少1个数据库写入及1个session生成,一个session在服务器就要写入一个文件,试想如果网站同时来了1万个用户访问,文件IO开销巨大,说得不好听点,服务器可能就死球了。对于框架,业内一直有这么一句话:学之者生,用之者死。本人觉得这句话很值得琢磨一下。

如今没有几个公司不要求程序员有MVC的开发理念,MVC确实有好处,本人也喜欢,但也不去刻意追求. 当然也有反对MVC的, 包括PHP创始人。HongCMS开发中有V和C,M基本没有,因为不需要或者说使用M编程反而累了,但完全可以使用Model,系统框架已经为它设计好了,程序包models/目录下有实例。特别是后台admin/models/目录下的admin.php, 它就是后台用户(管理员)的模型。说白了,模型就是一些类啦。

HongCMS系统框架APP.php非常小巧,仅5K大小,再加上XTpl超小模板引擎,HongCMS核心非常小巧、快速和高效。有基础的朋友,如果对HongCMS进行二次开发,或是参考其中的理念,足可以开发出大型系统来。

这些思想,加上多年做双语企业网站的经验,同时有朋友要我开发一个中英双语的小型企业网站,于是HongCMS出生了。对于一些从事网站开发的朋友来说,我想HongCMS更适合成为你的工具,像很多使用weenCompany的用户能赚钱一样,使用HongCMS当然能赚钱,同时在技术上会有更大的提高。对于一般用户,HongCMS是中英文网站系统,对于懂程序的朋友来说,它是小型开发框架,开发由你。

二、目录布局与重要文件介绍

视图文件路径:public\templates\Default
1. 根目录下的几个文件
.htaccess:  此文件是apache服务器下的伪静态规则文件,另外此文件还限制了浏览器可以访问或进入哪个目录或文件夹,增强了系统安全性。如果你添加了一个目录如blog,这个目录下独立安装了另一个blog系统,那么需要修改htaccess文件,以便允许浏览器访问blog目录。

index.php:  HongCMS是单入口系统,所有前台页面的访问均从index.php进入。

robots.txt:   此文件列举了一些目录,禁止SEO进入。基本上HongCMS除index.php文件夹都不希望SEO进入,因为SEO在其它目录或文件上抓不到有用的信息,但如果进入的话,反而可能会增加网站负担。

2. Admin目录:  后台管理目录, 里面存放的是后台管理入口文件,控制器和模型,也就是说,基本上后台管理的功能由其中的文件来完成。3.0.0版本开始, 后台管理有自己独立的入口文件index.php,同时后台管理目录可以任意修改。后台管理相当于一个独立的模块。

3. Cache目录:  此目录动态保存模板的缓存文件,一般不需要手动管理其中的文件。

4. Config目录:  系统配置目录,此目录下的config.php保存数据库连接信息等;settings.php保存网站基本设置信息,可以在后台管理中设置其中的信息,当然也可以手动直接修改其中的内容。

5. Controllers目录:  前台控制器文件目录,基本上前台的功能由此目录下的文件完成。

6. Images目录:  此目录为预留目录,在.htaccess中已经设置好了浏览器可以进入此目录,方便用户上传一些图片等,然后在文章内容中直接显示。

7. Includes目录:  此目录存放函数库文件或系统加载的核心文件,在core.php中对系统加载进行基本配置,functions.admin.php后台管理的函数库文件,functions.common.php前台需要使用的函数库文件,functions.global.php里面是前后台都需要使用的函数库文件。

8. Install目录:  系统安装目录,在浏览器中进入此目录安装HongCMS。

9. Medels目录:  前台模型文件目录。

10. Public目录:  此目录存放前台模板文件,后台模板文件,前后台的JS文件等。

11. System目录:  系统框架核心目录,其中的backup目录用于保存后台管理中的数据库备份文件,errors目录中是系统出错时显示的错误信息页面。plugins目录的是系统需要使用的一些类文件,如前后台的基础类文件,数据库类文件,JSON类文件,XTpl模板引擎类等等。system目录中的APP.php文件最重要,它是系统框架的核心类文件。可以这么说,系统的MVC开发模式由它确定。有兴趣的朋友可以仔细地分析一下此文件,有利于理解框架。

12. Uploads目录:  很明显,此目录将保存的是后台管理中各种上传文件,包括编辑器中上传的各种文件。

三、core.php系统加载配置核心文件
上面介绍了HongCMS为单入口网站系统,基本上所有的动态功能或动作均由根目录下的index.php文件引导完成。打开index.php文件,我们看到引入了includes/core.php,可见core.php文件在系统加载方面起作核心作用。

core.php需要仔细了解一下,其中最重要的是__autoload自动加载魔术函数,这个函数作用巨大,它允许实例化扩展类或模型类时,不需要在程序中加载相应的类文件,PHP服务器会自动加载相应的类文件,所以说它是魔术函数。这个自动加载函数主要是配合核心框架文件system/APP.php工作的。APP.php是核心框架文件,它的主要工作是对URL进行路由,简单地说就是把URL中的各种参数解释成相应的PHP程序文件去执行相关动作。APP.php文件的工作机制,有兴趣的朋友可以分析它,此文件很小仅5K,但它是框架的核心。

然后,在core.php文件中定义了一些前后台公共的常量,判断前台语言。再就是实例化数据库类,为后面的工作做准备。做二次开发的话,此文件一定要比较熟悉,因为它为系统加载运行做了最开始的一些准备工作。

四、URL路由及动作控制
APP.php核心框架文件的主要工作是解释URL中传递的各种参数到相应的程序中,然后由程序中的动作来完成相关功能,也就是说APP.php行使的路由功能。下面,我们来看几个具体的实例:

例1:www.xxx.com / admin/ index.php / products / save
网址 / 模块 / 入口文件 / 控制器 / 动作

上例中,admin是指admin模块,HongCMS按模块来保存关联的程序,后台管理的控制器和模型程序放在admin目录下,我们称admin为后台模块。

products指示APP系统需要调用哪个控制器,由admin和products组合确定了需要加载admin/controllers/products.php文件,这是由APP.php框架决定的。打开admin/controllers/products.php文件,其中可以看到,这是一个类文件,类名为c_products,由SAdmin后台管理基类扩展而来。类名c_products中的”c_”表示它是一个控制器, 为什么不直接使用products作为类名呢?这是为了同模型类区分开来,以便APP框架能自动识别。控制器的类名做了如此约束后,模型类的类名就可以自由书写了,达到互不冲突的目的。这里SAdmin基类我们稍后介绍。

save指admin/controllers/products.php文件中的save()函数,这个函数来完成产品信息的保存功能,看似就像做了某个动作,不难理解。参数可以通过URL来传递,如 www.xxx.com / admin / index.php / products / save / ?id=1, 也可以这样写 …. save?id=1,当然也可以传递多个参数。

例2:www.xxx.com加载哪个控制器呢?
首先它肯定是访问根目录下的index.php文件,由于在URL中没有指定控制器和动作,APP框架默认解释为index / index,系统将加载根目录下controllers目录的index.php文件,并执行此文件中的index()函数,此函数显示首页的相关内容。也就是说,如果URL中未指定控制器时为index控制器,未指定动作时为index动作。

可以看出www.xxx.com相当于:www.xxx.com / index.php / index / index,如果希望APP完成默认的路由,必须由后至前的方式来省略书写URL。比如 www.xxx.com / index.php / news就解释成了news控制器的index动作。

五、伪静态及URL处理函数
现在的搜索引擎(SEO)已经非常厉害了,即使是动态页面也能很好地抓取其中的内容。当然伪静态更有利于SEO,同时URL也更简单。如上面www.xxx.com/admin/index.php/products/save,开启了伪静态后,则可以写成:www.xxx.com/admin/products/save。

有时用户的服务器或空间不支持伪静态,有时又支持,HongCMS后台基本设置中有一个开关,当服务器支持伪静态时,可以开启伪静态功能,不支持时可以关闭。那么我们在页面或程序里URL的写法就不能固定,需要随着伪静态功能的开关而相应变化。因而HongCMS默认有2个伪静态处理函数,前台URL()和后台BURL()。这2个函数分别保存在functions.global.php和functions.admin.php文件中。

以前台URL处理函数URL()为例,我们在程序中或模板页面中如何写URL呢?有了这个函数,可以说非常简单了。如上index.php/news/index如何写呢?前台PHP程序中这样写: URL(‘news’),index.php文件名肯定不需要写了(index动作也不需要写,因为没有指定动作时默认为index动作),URL()这个函数会根据伪静态是否开启自动加上index.php。传送参数也容易,如:URL(‘news/index?id=888&name=someone’)

前台模板中如何调用URL函数呢?很简单,在需要显示URL的地方使用花括号(这是模板语法,请参阅: /bbs/?thread-index-fid-1-tid-19.htm)上例中,如果写在模板里,这样写:{echo URL(‘news/index?id=888&name=someone’)}, 呵呵,echo输出并加一个花括号而已。

为了方便在模板文件中输出(显示)URL,系统前台函数库文件functions.common.php有这么个函数PURL,P就是print的意思,意为直接输出URL。那么,在模板里,就这可以这样写URL:{PURL(‘news/index?id=888&name=someone’)}

六、SAdmin后台基类和SWeb前台基类
这两个基类的类文件均保存在system/plugins/目录下,此目录下还有一些其它的类文件或插件,其中类的命名规则是必须是大写S开头(意思为系统类),这是为了让autoload自动加载函数能识别某个类是基础类(插件类)还是模型类。

admin目录下的后台控制器类都是由SAdmin后台基类继承而来,这样,在SAdmin基类中就可以完成一些后面管理页面中都需要的功能,比如页头、页尾、后台授权等。这个类因为是后台控制器的基类,所以需要做得尽可能的小。在SAdmin基类中,我们实例化了admin管理员用户模型,那么用户验证,权限,登录与退出等均由admin模型来完成,模型文件保存在: admin/models/admin.php

系统根目录下controllers目录保存的是前台控制器类,同理均由SWeb前台基类继承而来,但与SAdmin基类稍有不同。因为前台页面输出时都需要加载模板引擎,所以设计成SWeb基类由STpl模板引擎类继承而来,同时在SWeb基类中对STpl模板引擎类进行基本的设置,让其符合前台页面输出的要求,这样在编写前台控制器程序时就非常方便省事了。默认情况下,HongCMS系统前台是没有用户权限控制的,如果需要的话,前台的用户权限控制可以加在SWeb前台基类中。

总结一下,如果某些功能或者设置在前台或者后台总是出现,那么就要考虑将其代码写在SWeb前台或SAdmin后台两个基础类中,这是为了减少代码重复,提高程序效率。比如,前台的产品多级分类功能在所有的页面中均显示,那么我们就在SWeb前台基类中实现它,并将它的内容赋值给一个模板变量,在模板页面中调用就可以了。

如果我想给系统添加一个blog功能,该如何做呢?
给网站添加一个简单的blog功能,可以直接在controllers下添加一个blog控制器来实现。如果这个blog相当复杂, 也可以参考admin模块做一个独立的blog模块来实现。

七、后台Ajax介绍
首先说明一下,后台ajax同前台ajax稍有不同,这一节先说说后台ajax。在后台管理中,我们做ajax时不能输出页头,页尾,也不能输出数据库访问错误,因为这些信息返回后,js无法识别。同时,后台ajax也需要权限认证,否则是非法的,这几项都是基本要求。

一般地,后台ajax的URL这样写: BURL(‘language/ajax?action=delete’),看完上面的介绍后我们知道:language指控制器,也就是要执行admin/controllers/language.php程序文件;ajax指language控制器中的ajax动作。这样约定后,与控制器相关的ajax动作可以写到对应的控制器文件里,而不需要做一个独立的ajax文件,便于管理。如果某个控制器有多个ajax,我们可以通过参数action来确定执行哪个ajax。

打开system/plugins/SAdmin.class.php文件,我们看这个后台基类的构造函数,在这里决定了当动作名称为ajax时,禁止输出数据库错误,也不输出页头和页尾,同时实例化admin模型时加了一个参数$this->admin = new admin(1),这个1告诉admin模型,这是进行ajax操作,请做适合ajax相关的权限认证。打开admin/models/admin.php模型文件,可以看出在ajax授权时没有登录框的输出,只返回是否有权限的admin。

在SAdmin.class.php文件中,我们可以看出ajax返回三个变量的JSON数据:
$this->ajax[‘s’]   s=status 表示ajax状态,1表示操作成功,0表示操作失败
$this->ajax[‘i’]    i 指提示信息,ajax成功或失败都可以通过它返回一条信息
$this->ajax[‘d’]   d 指实际返回的ajax数据,如果有数据的话,供后续的JS处理。

再打开public/admin/admin.js文件,我们对jquery的ajax做了一个简单的封装:ajax(url, send_data, callback)函数,了解ajax的朋友看一下就清楚了。

在后台管理中,使用ajax的地方相对还是较多的,特别是一些小功能的处理上,使用ajax后比较简单方便完成。打开admin/controllers/目录下的文件,搜索一下ajax,如果存在,说明这个控制器中有ajax操作,详细的使用请参照这些ajax代码,应该比较容易。

八、前台Ajax介绍
上一节中后台ajax是后台控制器中的ajax动作,而由于前台ajax不需要加载模板引擎,所以它不能是前台控制器的动作,因为前台控制器从SWeb基类扩展而来,并且自动加载了模板引擎。由于这些原因,我们将前台ajax做成控制器,它从SAjax系统扩展类中继承而来,也就是说我们为前台ajax独立写了一个基类SAjax,这个基本同SWeb基类相似,只是不需要加载模板引擎且去掉一些不必要的系统配置,满足ajax的需要就可以了。详细可参阅system/plugins/SAjax.php文件。

前台ajax既然是一个控制器,那么它的写法基本和前台其它控制器相似,只是它由SAjax扩展而来,详细看一下controllers/ajax.php文件。具体的ajax操作,由这个控制器的动作来完成。

前台ajax的URL可以这样写:PURL(‘ajax/delete?id=88’),它将执行ajax控制器中的delete函数。

HongCMS默认安装后,前台没有使用ajax,用户如果需要做前台ajax,可根据上面的介绍,并参考后台相关ajax的代码来写。

九、如何修改后台管理目录admin?
HongCMS安装后,后台管理目录为admin,建议修改成自己喜欢而别人不容易猜出的名称,以提高系统的安全性。
修改后台管理目录很容易,使用FTP工具直接修改admin文件夹的名称或者在未安装前手动修改。修改后还需要做以下工作:

1. 使用editplus,DW等工具打开根目录下的.htaccess文件
RewriteCond $1 !^(index\.php|public|uploads|install|images|admin|ajax\.php)

上面一行中的admin表示浏览器可直接进入admin目录,将admin替换成修改后的后台管理目录名称。

2. 同上打开根目录下的robots.txt文件,将admin替换成修改后的后台管理目录名称。

十、静态成员变量的调用(商业版)

HongCMS商业版3.2.0对核心框架(system/APP.php)做了小幅改进,即增加了几个静态成员变量,方便在程序或函数中调用,而不必再使用global方法。
打开APP.php文件,你将看到:

/**
* 当前控制器对象, 静态成员对象
* @var object
*/
public static $C; //调用时注意是大写C

/**
* 数据库访问对象, 静态成员对象
* @var object
*/
public static $DB;

/**
* 系统设置数组, 静态成员数组
* @var array
*/
public static $_CFG;

也就是说核心框架类文件中增加了三个静态成员:APP::C、APP::DB、APP::_CFG,下面我们说说这三个静态成员。APP::DB、APP::_CFG在core.php系统核心文件中进行了赋值,分别表示数据库访问对象和系统设置数组,那么在includes/functions.common.php文件中的函数内调用数据库访问类或系统设置数组时,就可以这样写:
function xxxx(){

APP::DB->getOne(……..);

$xxx = APP::_CFG[‘siteTimezone’];
}

虽然在core.php定义了全局的$DB对象,$_CFG数组,如果不改进APP.php, 那么上面这个函数需要这样写:
function xxxx(){
global $DB, $_CFG;

$DB->getOne(……..);

$xxx = $_CFG[‘siteTimezone’];
}

接下来我们说说APP::C这个静态成员,它比较有意思。我们知道,HongCMS前台或后台的功能基本上由控制器来完成,即由controllers目录下的控制器文件来完成。

APP::C就是指当前这个控制器对象,根据上面几节的说明,我们知道前台的控制器类由SWeb基类扩展而来,而且SWeb基类又从模板类STpl类中扩展而来。现在打开includes/functions.common.php文件,找到Error函数,看看它是如何写的:

function Error($errors, $title = ”, $time = 0) {
……..

//设置类成员变量
APP::C->display_allowed = false; //错误发生时返回到前一个页面, 因此不允许加载其它的模板文件(只需要页头和页尾)
APP::C->system_info = “…..”;

APP::C->assign(‘system_info’,  APP::C->system_info);

……..
}

display_allowed, system_info是SWeb类的成员变量,assign是STpl类的成员函数,上面的代码表明:在公共的函数库中能方便地调用控制器的成员变量和成员函数。

商业版3.2.0对系统核心框架APP.php这个细小的改进,让程序员更加方便和灵活地编写需要的程序代码。改动虽小,改进很大。

十一、如何修改.htaccess文件,允许浏览器直接访问网站目录?

在apache服务器(加载了Rewrite模块)下安装的HongCMS, 特别是将HongCMS放在网站的根目录下,那么,由于HongCMS根目录下的.htaceess文件的作用,浏览器是不能随便进入网站中的目录的。比如: xuduowei.com/downloads/目录下有一个文件需要提供给用户直接下载,但是浏览器无法直接访问些目录,其下的文件当然无法形成链接。

要实现这个直接下载的链接,如:http://www.xuduowei.com/downloads/xxxx.rar, 那么必须要修改.htaccess文件。打开这个文件,我们看一下这个文件中关键的两行:

RewriteCond $1 !^(index\.php|public|uploads|install|images|admin|ajax\.php)
RewriteRule ^(.*)$ index.php/$1 [L]

第一行允许浏览器可以访问HongCMS根目录下哪些文件或目录,包括:index.php, ajax.php文件;以后plulic、uploads、admin等等几个目录。当然ajax.php文件不存在,这里只是给用户一个示例。那么根据上面的需要,要允许浏览器直接访问downloads目录,怎么办呢?或者,网站下有了个bbs/目录安装了其它系统,如:http://www.xuduowei.com/bbs/, 我们这样改第一行,添加两个允许的目录就可以了:

RewriteCond $1 !^(index\.php|public|uploads|install|images|admin|downloads|bbs|ajax\.php)

当然,你也可以将这一行整个删除,那么apache将不限制浏览器访问任何文件或目录,安全性自然就下降了。

第二行是HongCMS伪静态的控制语句,请勿删除,否则伪静态功能失效,开启伪静态功能将导致网站无法正常运行。

SQL语句的并集UNION,交集JOIN(内连接,外连接),交叉汇总

1.

a. 并集UNION
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2
提示:

union与union all

union :自动去除重复的数据,然后合并结果集

union all :不去除重复的数据,直接合并结果集

b. 交集JOIN
SELECT * FROM table1 AS a JOIN table2 b ON a.name=b.name
c. 差集NOT IN
SELECT * FROM table1 WHERE name NOT IN(SELECT name FROM table2)
d. 笛卡尔积
SELECT * FROM table1 CROSS JOIN table2
SELECT * FROM table1,table2相同
2. SQL中的UNION
UNION与UNION ALL的区别是,前者会去除重复的条目,后者会仍旧保留。
a. UNION
SQL Statement1
UNION
SQL Statement2
b. UNION ALL
SQL Statement1
UNION ALL
SQL Statement2
3. SQL中的各种JOIN
SQL中的连接可以分为内连接,外连接,以及交叉连接
(即是笛卡尔积)
a. 交叉连接CROSS JOIN
如果不带WHERE条件子句,它将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积;
举例
SELECT * FROM table1 CROSS JOIN table2
等同于
SELECT * FROM table1,table2
一般不建议使用该方法,因为如果有WHERE子句的话,往往会先生成两个表行数乘积的行的数据表然后才根据WHERE条件从中选择。
因此,如果两个需要求交际的表太大,将会非常非常慢,不建议使用。
b. 内连接INNER JOIN
如果仅仅使用
SELECT * FROM table1 INNER JOIN table2
没有指定连接条件的话,和交叉连接的结果一样。
但是通常情况下,使用INNER JOIN需要指定连接条件。
— 等值连接(=号应用于连接条件, 不会去除重复的列)
SELECT * FROM table1 AS a INNER JOIN table2 AS b on a.column=b.column
— 不等连接(>,>=,<,<=,!>,!<,<>)
例如
SELECT * FROM table1 AS a INNER JOIN table2 AS b on a.column<>b.column
— 自然连接(会去除重复的列)
c. 外连接OUTER JOIN
首先内连接和外连接的不同之处:
内连接如果没有指定连接条件的话,和笛卡尔积的交叉连接结果一样,但是不同于笛卡尔积的地方是,没有笛卡尔积那么复杂要先生成行数乘积的数据表,内连接的效率要高于笛卡尔积的交叉连接。
指定条件的内连接,仅仅返回符合连接条件的条目。
外连接则不同,返回的结果不仅包含符合连接条件的行,而且包括左表(左外连接时), 右表(右连接时)或者两边连接(全外连接时)的所有数据行。
1)左外连接LEFT [OUTER] JOIN
显示符合条件的数据行,同时显示左边数据表不符合条件的数据行,右边没有对应的条目显示NULL
例如
SELECT * FROM table1 AS a LEFT [OUTER] JOIN ON a.column=b.column
2)右外连接RIGHT [OUTER] JOIN
显示符合条件的数据行,同时显示右边数据表不符合条件的数据行,左边没有对应的条目显示NULL
例如
SELECT * FROM table1 AS a RIGHT [OUTER] JOIN ON a.column=b.column
3)全外连接
显示符合条件的数据行,同时显示左右不符合条件的数据行,相应的左右两边显示NULL

union和left join的应用区别

union为增加行;left join为增加列

1. union

union关联两张表时,增加行,两张表的字段必须相同。(增加表数据的条数)

例: 表A ( 列  a b c) 共6行数据;表B(列 a b c)共4行数据;

select  * from  A        union       select *  from B      : 查询结果为表C  :为 a b c 3列,后共6+4=10行;

2. left join

left join关联两张表时,增加列,两张表必须有相关联的字段。(增加表数据的列数)

例: 表A ( 列  a b c ) 共4行数据;表B(列  b d e f g)共6行数据;

select  * from A  left join B  on A.b = B.b        :  查询结果为表C  :为 a  b  c  b1 d  e  f  g 共 8列,共4行(表A的行数)

window服务器下定时执行php页面,以实现信息的抓取;bat执行(php)接口文件。作者:徐老师,徐多蔚,xuduowei

 

@echo off
rem 关闭回显
start “C:\Program Files\Internet Explorer\iexplore.exe” “这里写上你接口url1”
start “C:\Program Files\Internet Explorer\iexplore.exe” “这里写上你接口url2”

rem 使用浏览器打开url地址,5秒后自动关闭ie
ping 127.0.0.1 -n 5 >nul
taskkill /im iexplore.exe /f

 

针对window系统,如何定时执行这个bat文件,以定时执行接口文件呢?

以win7服务器为例:

1、开始–控制面板–管理工具–计划任务

2、在“任务计划程序库”上右键–创建基本任务

3、具体操作步骤

提示:若是需要重启启动电脑,如下:

程序脚本:C:\Windows\System32\shutdown.exe

参数:-r -f -t 0

https://jingyan.baidu.com/article/e6c8503c55529be54f1a18d1.html

similar_text()计算相似度、basename得到文件名【不要扩展名】,项目中有时候需要得到文件名和数据库中的字段进行匹配,整理:徐老师,徐多蔚,xuduowei

项目中有时候需要得到文件名和数据库中的字段进行匹配。我们就可以按若下2个函数作为核心函数进行业务逻辑处理。

similar_text() 函数计算两个字符串的匹配字符的数目。

该函数也可以计算两个字符串的相似度(以百分比计)。

代码如下:

similar_text(‘你好啊,早上好’, ‘你好啊’, $percent);
echo $percent;
die;

//得到文件名【不要扩展名】
$f=”aaaa.gif”;
$ext_arr=explode(“.”,$f);
$extString=$ext_arr[count($ext_arr)-1];
echo basename($f, “.”.$extString);

作者:徐多蔚【徐老师】 xuduowei.com

计算两个字符串的相似度mysql 自定义函数:Levenshtein_mysql

1、功能描述:

mysql 自定义函数。用来计算字符A转换成字符串B所花费的代价,数值越小,代价越低。(换句话来说,就计算两个字符串的相似度,值越小相似度越高)。

该实现采用了编辑距离算法,详见:http://baike.baidu.com/link?url=EhmqDIoInSurOWI8VfR5bdmwxuYjPGKgqET2oNyv9–zDREhTUe5sYdxWLxS4v3tdK1PJVOFaOy9c6uHoElBSK

2、使用方法:

使用源代码的话,从第1步开始。如果是直接使用二进制发布包的话,直接从第4步开始即可。

1)下载本代码

2)安装mysql开发包。

mysql主分支文件名类型:libmysqlclient15-dev mariaDB分支文件类似:MariaDB-10.0.21-centos7-x86_64-devel

3)编译源代码:

g++ -shared -fPIC -I /usr/include/mysql -o lev_distance.so lev_distance.cpp

4)将so文件复制到mysql插件目录

cp lev_distance.so /usr/lib64/mysql/plugin

5)创建mysql自义函数。

CREATE FUNCTION levenshtein RETURNS INTEGER SONAME ‘lev_distance.so’;

6)完成。

7)测试:

SELECT levenshtein(‘abc’,’dbca’)

项目主页:http://www.open-open.com/lib/view/home/1440302113917

文章来源:http://www.genshuixue.com/i-cxy/p/11592035

 

tp3快速上手笔记-徐多蔚

文件夹及文件【控制器,模型】命名才用驼峰法[首字母大写]
URL:
url访问方式:
index.php?m=home&c=index&a=abc
m:模块;  默认模块是home
c:控制器;默认控制器是index
a:方法。 默认方法是index
tp采用的是单入口文件!
tp3.2.3版本中支持以下4种格式。其中有2种是最最重要。
URL模式 URL_MODEL设置
普通模式 0
PATHINFO模式 1 [标准] =============重要。
REWRITE模式 2
兼容模式 3
配置文件中:’URL_MODEL’=>1, //0:普通模式;1:pathinfo模式【默认的】
I(‘post.’)     //所有的值
I(‘post.name’)
 
 
 
 
I(‘get.’) //所有的值
I(‘get.name’)
get方式传值:
index.php?m=home&c=news&a=newslist&abc=1&cde=2
index.php/home/news/newslist/?abc=1&cde=2
index.php/home/news/newslist/abc/1/cde/2
get方式取值:
方法一:
$_GET[‘abc’];
方法二:
I(‘get.’);数组类型
I(‘get.变量名’); 得到的就是具体的变量值
视图的渲染:
$this->display(‘/视图文件名’);//注意没有扩展名
格式:$this->display(‘/视图文件名’); //找View视图文件夹下的 视图文件名
============================================
格式:$this->display(‘视图文件名’); //默认找View视图文件夹下,和控制器同名的文件夹中的视图文件名
如何定义模板变量且赋值?
{$xdw}
针对数组的定义和引用!
控制器文件code:
$arr=array(‘a’=>2,’b’=>3,’c’=>4);
$this->assign(“xdw”,$arr);
视图文件code:
{$xdw.b} 或者  {$xdw[‘b’]}  //比smarty更智能。
tp3.2.3视图中,如何循环数组?
<foreach name=”xdw” item=”vo” key=”k” >
{$k}|{$vo} <br/>
</foreach>
提示:xdw 就是定义的模板变量名,vo就是循环值,k就是索引下标值或键名。
===========================================
在视图文件中,如何调用系统函数和自定义函数?
调用系统函数:
1、系统函数;
格式如:{$list.abc|substr=1,1}
或 {$list.abc|substr=###,1,1}
提示:若###省略,则把对应的变量值做为第一个参数值传递。
2、自定义函数
a、在哪里定义
   函数可以放到
ThinkPHP\Common\functions.php
ThinkPHP\ThinkPHP.php
b、如何引用 借鉴 系统函数引用方法。
==========================================
数据库如何操作?
tp3.2.3中配置文件有2种类型;1、全局配置文件;2、模块配置文件。
1、全局配置文件:
App\Common\Conf\config.php   有效于全部模块
2、模块配置文件:
App\Home\Conf\config.php     仅有效于当前模块
增、删、改、查
 
$obj=M();//若用query方法执行一个完整的sql,则这里可以M()。
$arr=$obj->query(“select * from obj_liuyan_cs”);
print_r($arr);
查:
增加:
$obj=M(“表名”);
$obj->add($arr);//返回值是增加后的主索引值,如:id值。
修改::==============================================
return $obj->where($where)->save($arr);//返回的值是实际更新的记录数。
删除::==============================================
return $users->where($where)->delete();//返回值是删除的真实记录数。
查询:
$obj=M(‘表名’);
$obj->query($sql); //$sql为完全自定义的sql。
$users=M(“ceshi”);
$arr=$users->where(“id=2”)->find();//结果是1维数组;只能是一条。
$arr=$users->where(“id=2”)->select();//结果是2维数组;
多表查询格式,也可以套用到单表中。
$rs=$obj->table(‘users u’)
->field(‘u.id,u.username’)
->order(‘id desc’)
->where()
->limit(1,1)
->select();
===============================
左右连接,子查询:
$obj=M();
$rs=$obj->table(‘users u’)
->field(‘u.sfzid,c.cardnum,(select pay from pays where cardid=c.id) as pay’)
->join(‘left JOIN cards as c ON c.uid=u.id’)
->select();
==================2018/1/10
php开发中,有3类元素是不可以重名的。
1、常量;
2、方法【函数】;
3、类。
命名空间:1、全局空间;2、子空间
命名空间就是帮助我们解决重名问题!
在php中如何声明命名空间呢?
我们可以用namespace来定义命名空间。
注意:namespace前方不可以有输出,否则报错!
page.php code:
function abc(){
echo ‘2’;
}
=========================
include(“page.php”);
function abc(){
echo ‘1’;
}
结果报错,提示重复定义abc();
我们可以在开头定义命名空间,如下:
namespace a;
include(“page.php”);
function abc(){
  echo ‘1’;
}
这就不会报错了,原因是,page.php被include包含进来,page.php中的内容在全局空间中。
namespace a;
include(“page.php”);
function abc(){
  echo ‘1’;
}
abc();//结果是1,默认执行的是当前命名空间里的方法。
如果要执行全局空间的,怎么办?
\abc();//结果是2
访问当前命名空间元素有2种方式:
方式一:直接引用,如abc();
方式二:完整路径引用,如\a\abc();
我们可以声明命名空间的时候,进行多级创建。
如 namespace a\a1;
完整的引用路径:\a\a1\abc();
注意:namespace 一定要放在页面开头,前方不可以有任何的输出!
命名空间中常量特殊!
需要用const 定义。
=====================================
导入类到命名空间中的顺序:
include(“page.php”);
use xdw3;
================================
一个页面中可以定义多个命名空间的!!
namespace xdw\xdw1{
}
namespace xdw\xdw2{
}
提示::一个页面中若定义了多个命名空间,则{}之外不可以有任何代码的执行。
tp3.2.3框架中如何创建模型及如何使用?
创建模型的方法:
页面命名:UsersModel.class.php
内容如下:
namespace 模块名\Model;
use Think\Model;
class UsersModel extends Model {
    public function index(){
 echo 1234;
    }
}
模型在控制器中的引用:
方法一:
$obj=new \模块名\Model\UsersModel(…)
$obj->index();
$obj=new \模块名\Model\UsersModel
$obj->index();
方法二:
先导入,后直接实例化:
use \Admin\Model\UsersModel;
$obj=new UsersModel();
$obj->index();
提示:模型的命名即表名,配置的默认库中要有这个表才可以。否则会报错的。因为模型存在的意义就是对表的操作。表都没有,创建模型有啥意义呢?
模型中主要是进行值的返回!输出动作在控制器里操作!
切记:模型不可以直接被访问,只能通过控制器间接的访问操作。
V
C
M
项目构架!
项目中一般分前端模块[Home]和后端模块[Admin]
__PUBLIC__
表单提交的动作页面,不推荐使用:
?m=admin&c=index&a=checklogin
也不推荐使用
/admin/index/checklogin
{:U(‘admin/index/checklogin’)}
admin:模块名;
index:控制器名;
checklogin:方法名。
I(“post.”);
tp中内置的页面跳转方法:
$this->success(‘success’, U(‘index/succ_page’),$time);
$this->error(‘error’, U(‘index/index’),$time);
提示:$time的单位是秒。
$time可省略,若省略,则调用默认时间。
默认success时间是 1s;error时间是3s。
9:21 2018/1/11
U方法可以传递参数:
 
{:U(‘index/page?filename=pass&t=2’)}
取值:
方法一【内置自动取值,函数参数名和U传递过来的变量名一致】:
function page($filename,$t){
   echo $filename;
}
方法二【手动通过I(‘get.’)取值】
function page(){
   echo I(“get.filename”);
}
tp3.2.3中用户信息的跟踪【会话机制】
session在tp3.2.3中默认已经开启了,所以不需要再次开启
可直接使用
$_SESSION[‘session名’]=值;
tp3.2.3中,内置了session处理。
定义:
session(‘name’,’value’);  //设置session
取值:
$value = session(‘name’);
删除单个:
session(‘name’,null); // 删除name
删除所有:
session(null); // 清空当前的session
MODULE_NAME 当前模块名
CONTROLLER_NAME 当前控制器名
ACTION_NAME     当前方法名
========================================
tp3.2.3中使用框架验证码。
使用方法,打开手册,搜索验证码。
1、
复制
$Verify = new \Think\Verify();
$Verify->entry();
到我们自定义的控制器方法中。
如下:
//生成验证码
function CreateYzm(){
$Verify = new \Think\Verify();
$Verify->entry();
}
2、
使用
打开对应的视图文件,如login.html
{:U(‘index/CreateYzm’);}把这个作为src的属性值。
3、
判断正误
使用内置方法进行判断。
// 检测输入的验证码是否正确,$code为用户输入的验证码字符串
function check_verify($code, $id = ”){
$verify = new \Think\Verify();
return $verify->check($code, $id);
}
在对应的控制器中使用此方法判断正确true与失败false
$this->check_verify(‘表单传值’);
实现登录页面刷新验证码技术:::
document.getElementById(‘imgyzm’).src=”yzm.php?”+new Date().getTime();
onclick=”this.src=this.src+’?'”
我们如何使用自己定义类的验证码呢?
1、自定义类为切入点。【怎么定义自定义类】
www\tp1214\ThinkPHP\Library\Think
创建一个文件,格式 类名.class.php
类文件内容格式:
namespace Think;
class Yzm{
function CreateImg(){
echo 666;
}
}
验证码有2种解决方案。
1、tp内置验证码技术
2、diy验证码技术。
2、如何使用自定义类。
提示:若我们在登录页面对应的控制器中设置了防跳墙方法。则对应的方法如:【index,验证码方法,判断登录方法】要进行过滤。
9:03 2018/1/12
提示:tp项目开发中,建议:每一个功能块都对应一个控制器。
修改密码流程:
1、/*判断2次输入的新密码一致*/
2、//新密码和老密码不能一样
2.1 判断时间
3、/*要先判断老密码输入正确后,才能进行新密码的修改。*/
扩展:我们需要实现一个功能,如:1天内最多只允许修改3次
密码。
select unix_timestamp();得到当前的时间戳的。
select count(id) as cc from obj_users_log where uid=1 and type=2 and unix_timestamp(updatetime)>(unix_timestamp()-3600*24)
========================================
tp3.2.3中分页类的使用。
$obj=M(‘users’);
$num=3;
$count=$obj->count();
$Page= new \Think\Page($count,$num);
分页样式的修改:
$arr=$obj->order(‘id desc’)->limit(“$Page->firstRow,$Page->listRows”)->select();
$Page->setConfig(‘prev’,’上一页’);
//一定要放到$Page->show();之上才有效!
$Page->setConfig(‘next’,’下一页’);
$show= $Page->show();// 分页显示输出
$this->assign(‘show’,$show);
$this->assign(‘arrlist’,$arr);
$this->display(“/list”);
搜索分页:
注意事项:
$arra[‘keywords’]=$keywords;
//$Page->parameter=$arra;  //$Page->parameter,放到show之上
 $Page->parameter = array_map(‘urlencode’,$arra); //若不这样,搜索的时候若有’将报错的。
$show= $Page->show();// 分页显示输出
完整sql:
select count(a.id) from obj_users_group_role a,obj_users_role b where a.groupid=2 and b.mokuai=’Admin’ and b.kongzhiqi=’Users’ and b.fangfa=’index’ and a.roleid=b.id
echo “模块名是:”.MODULE_NAME.”控制器是:”.CONTROLLER_NAME.”方法是:”.ACTION_NAME;
select a.*,b.groupid from obj_users_role a left join  obj_users_group_role b on a.id=b.roleid
魔术方法:
function _empty(){
echo ‘errordddddddddd’;
}
EmptyController.class.php  空控制器执行文件。
 tp3.2.3视图中条件的判断:
<if condition=”$v.groupname eq ” “>无分组<else />{$v.groupname}</if>
<if condition=”($name eq 1) OR ($name gt 100) “>
value1
<elseif condition=”$name eq 2″/>value2<else /> value3
</if>
在condition属性中可以支持eq等判断表达式,同上面的比较标签,但是不支持带有”>”、”<”等符号的用法,因为会混淆模板解析,所以下面的用法是错误的:
<if condition=”$id < 5 “>value1
    <else /> value2
</if>
必须改成:
<if condition=”$id lt 5 “>value1
<else /> value2
</if>
tp3.2.3中借助大 U方法传递参数:如:id
<?php echo U(‘users/del/?id=’.$v[‘id’]);?>
或者 <?php echo U(‘users/del?id=’.$v[‘id’]);?> 多个参数用&分割
<a class=”button border-red” href=”<?php echo U(‘users/del/?id=’.$v[‘id’]);?>” ><span class=”icon-trash-o”></span> 删除</a>
tp3.2.3中的缓存:
支持的缓存类型众多,常见常用的文件缓存设置方式:
1、页面静态缓存;
全局配置中
'HTML_CACHE_ON'     =>    true, // 开启静态缓存
'HTML_CACHE_TIME'   =>    60,   // 全局静态缓存有效期(秒)
'HTML_FILE_SUFFIX'  =>    '.html', // 设置静态缓存文件后缀
	'HTML_CACHE_RULES'  =>     array(  // 定义静态缓存规则
	 // 定义整个Users控制器 生成的路径App/html/Users/  html会自动生成
	'Users:'      =>       'Users/{:action}_{id}',
)

参考:https://www.cnblogs.com/chinalorin/p/5855254.html

2、局部数据缓存

会按照缓存初始化时候的参数进行缓存数据,也可以在缓存设置的时候改变参数,例如:

// 缓存数据300秒
S(‘name’,$value,300);
甚至改变之前的缓存方式或者更多的参数:

// 采用文件方式缓存数据300秒
S(‘name’,$value,array(‘type’=>’file’,’expire’=>300));
如果你在缓存设置的时候采用上面的数组方式传入参数的话,会影响到后面的缓存存取。

缓存读取
// 读取缓存
$value = S(‘name’);
缓存读取的是前面缓存设置的值,这个值会受缓存初始化或者缓存设置的时候传入的参数影响。 如果缓存标识不存在或者已经过期,则返回false,否则返回缓存值。

缓存删除
// 删除缓存
S(‘name’,null);
删除缓存标识为name的缓存数据。

实战项目部分案例:
方案一:
if(S('Users_index')){
			$arr=S('Users_index');
		}else{
			$arr=$obj->table(C("DB_PREFIX")."users as a")
				->field("a.*,b.groupname")
				->where($tj)
				->join('left JOIN '.C("DB_PREFIX").'users_group as b ON b.id=a.gid')
				->limit($Page->firstRow.','.$Page->listRows)
				->select();
			S('Users_index',$arr,array('type'=>'file','expire'=>10));
		}


或者直接按如下写法:
方案二:推荐使用,效果和方案一一样的,但是写法更简单。
$arr=$obj->table(C("DB_PREFIX")."users as a")
				->field("a.*,b.groupname")
				->where($tj)
				->join('left JOIN '.C("DB_PREFIX").'users_group as b ON b.id=a.gid')
				->limit($Page->firstRow.','.$Page->listRows)
				->cache('Users_index',10)
				->select();

 

提示:生成的文件缓存存储在:App\Runtime\Temp 目录中。

 提示:若同时开启了页面静态缓存和局部数据缓存,则以页面缓存优先!

php原生态php文章管理系统-适合初学者学习;功能开发作者:徐多蔚,xuduowei,徐老师

前端效果:http://www.xuduowei.com/tc/php1

后台登录:http://www.xuduowei.com/tc/php1/admin888

后台功能模块预览:

登录成功后,首先看到的是开发信息和基本设置。

基本设置中有个网站设置及网站设置-增加变量,这个主要是更方便参数的修改和扩展,比如网站的名称,网站的关键字,网站的描述,网站的联系人电话,地址,qq,email,网站备案号等。

基本设置中有个缩略图管理,这个主要是管理文章记录缩略图多余的情况,比如修改文章缩略图了,或者删除文章记录了,有可能其对应的缩略图文件还在。这个时候,我们就需要对多余的缩略图进行删除操作。

 

栏目管理:主要是cms内容列表查看,增加,修改,删除,以及分类的管理【实现无限极分类】。如下图:

用户管理:查看用户,添加用户,如下图:

单页管理:重点是单页业务处理,如:关于我们,服务流程,公司简介。如下图:

 

权限思路分析:

分析权限设置的核心:
需要对分组id进行权限的分配而不是指定的用户!!
我们需要给用户表增加一个新字段,字段名:groupid tinyint型
我们事先声明号:
1为超级管理员【拥有所有的,全部的操作权限】;
2为信息发布员,只希望让他有增加文章的操作。其他权限不给!
要模拟设置好2个用户【??? 为超级管理员】;
【???为信息发布员】
我们考虑在登录验证登录后写入$_SESSION[‘groupid’]=$rs[‘groupid’];
我们考虑在哪个页面实现所谓的权限判断?safecheck.php
非数据库方式进行“权限”的验证,首先要想到的就是用数组来定义!!!!!!!
我们要考虑到分组可能有很多个?这个时候若要用数组的方式定义对应的权限,我们首先考虑到的应该是2维数组。
2维数组中,要方便根据我们的分组ID快速找到对应的权限。
$arr=array(
“2”=>array(
“权限1″,”权限2”
)
)