前段时间在整理一个PHP函数代码审计的项目,所以文章也是围绕PHP的代码审计来写,如果有写的不对的地方,还请大佬们指正。文章开始前,我们先来了解一下PHP是什么。
0x01 PHP是什么
根据百度百科的描述,PHP是一种在服务器端执行的通用开源脚本语言,主要适用于Web开发。
既然是网站编程语言,自然需要一款工具辅助程序员高效编程。PhpStorm就是一款PHP集成开发工具,可以随时帮助程序员对代码进行调整、运行单元测试、且提供可视化debug功能。
当然也可以使用其他工具对PHP程序进行调试,比如Xdebug,一款开放源码的PHP debug工具,用来跟踪、调试和分析PHP程序的运行状况。
大家可以通过学习这个实验,掌握PhpStorm环境搭建和Xdebug工具的安装和配置:
留言或私信获取实验地址哦~
网传这么一个段子:如何让一个论坛的人吵起来?答:PHP是世界上最好的语言。这个梗出自PHP的官方文档,最早出现在2001年7月的PHP文档中。虽然有PHP是世界上最好的语言这种说法,但是也有一些因为弱类型语言的安全性问题出现,这就需要安全人员通过代码审计来检查PHP程序的安全性。
0x02 代码审计又是什么
代码审计,顾名思义就是检查源代码中的安全缺陷。通过自动化工具或人工审查的方式,对程序源代码逐条进行检查和分析,发现源码缺陷引发的安全漏洞,有时还需要提供代码修订措施和修复建议。
软件的源代码、程序缺陷可能导致严重的安全漏洞,要消除代码中的漏洞、减少不必要的补丁升级,就需要进行源代码的安全审计。源代码审计是对代码库和软件架构的安全性、可靠性进行全面的安全检查。人工审查已经成为软件源码设计、开发和应用的最佳保障,因此做好代码审计就是从安全的角度对整个代码质量进行评估。安全人员需要在黑客发现系统漏洞之前,找出应用的安全隐患,并提供相应的安全报告和修复方法,从而提高应用系统的安全性。
除了人工审查的方式,还可以通过一些自动化工具进行代码审计,下面简单介绍两种代码审计利器:
1、 Seay源代码审计系统
这是一款针对PHP代码安全审计的系统,基于C#语言开发,主要运行于Windows系统上。这款软件能够发现SQL注入、代码/命令执行、文件包含、文件上传、拒绝服务、XSS、信息泄露、任意URL跳转等漏洞。关于Seay源代码审计系统工具的使用,可以通过下面的实验进行学习:
实验地址留言或私信获取哦
2、 RIPS
RIPS通过标记和解析所有源代码文件,自动检测PHP应用程序中的漏洞。RIPS能够将PHP源代码转换为程序模型,检测程序流期间用户输入可能污染的敏感接收器,即潜在易受攻击的函数。RIPS工具的使用参考下面的实验:
实验地址留言或私信获取哦
学习了代码审计的常用工具,相信大家会对代码审计的方法和步骤有一定的了解,那么接下来简单总结一下代码审计的流程:
① 通读全文代码:更好地了解程序的架构及业务逻辑,挖掘更多高质量的漏洞;
② 通读敏感功能点:快速挖掘某种漏洞;
③ 正向追踪可控变量;
④ 敏感关键字回溯参数传递过程。
下面进入文章的重点部分——PHP函数的代码审计,通过具体实例分析PHP部分函数,包括in_array函数、filter_var函数、escapeshellarg与escapeshellcmd函数、parse_str函数及addslashes函数,学习上述函数缺陷引发的漏洞及利用方式,结合CTF练习掌握PHP函数漏洞审计流程。
0x03 PHP函数的代码审计
这里我们根据《PHP函数漏洞审计》课程顺序进行学习。
一、PHP代码审计之in_array函数
既然是对in_array函数进行具体分析,我们先来了解一下in_array函数的相关定义:
注:后面说到的函数定义均来自PHP手册,手册地址:
$needle变量表示待搜索的值,$haystack表示待搜索的数组。in_array函数用法为:在$haystack数组中搜索$needle变量的值,检查值是否存在。如果第三个变量$strict的值为true,则in_array函数会进行强检查,检查$needle的类型是否和$haystack数组中的相同。
in_array函数为什么会存在漏洞呢,原因是程序员在使用in_array函数进行数据处理时,未使用第三个参数进行严格匹配,比如Piwigo软件2.7.1版本就是因为in_array函数的不安全使用,导致SQL注入漏洞发生。
查看源码/picture.php文件可以发现,当$_GET[‘action’]为rate时,会调用文件/include/function_rate.inc.php文件中的rate_picture方法,漏洞就存在于这个方法中:
而在rate_picture方法中,使用了in_array函数对$rate变量进行检测,判断$rate是否在$conf['rate_items']中:
由于functions_rate.inc.php文件中没有将in_array函数的第三个参数设置为true,所以会进行弱比较,可以将$rate的值设置成1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#进行绕过。
那么SQL语句就变成:
INSERT INTO piwigo_rate(user_id,anonymous_id,element_id,rate,date) VALUES (2,'192.168.2',1,1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#,NOW())
这样就可以进行盲注了。直接利用sqlmap进行漏洞利用:
python sqlmap.py -u "http://10.1.1.79/piwigo/picture.php?/1/category/1&action=rate" --data "rate=1" --dbs
还可以用sqlmap获取目标数据库的表及敏感数据。总结一下in_array函数的审计流程:
大家可以访问合天网安实验室,学习in_array函数缺陷引发的相关漏洞及其利用方式
二、PHP代码审计之filter_var函数
filter_var函数定义:
$variable变量表示待过滤的变量(变量的值在过滤前,会被转换成字符串),$filter变量表示要应用的过滤器的ID,$options变量代表一个选项的关联数组或按位区分的标识。filter_var函数返回过滤后的数据,过滤失败则返回false。
这里以一个CTF练习介绍filter_var函数缺陷引发的漏洞可以怎么利用,题目考察filter_var函数的绕过与远程命令执行。题目源码为:
程序使用exec函数来执行curl命令,很容易让人联系到命令执行。可以看到用于拼接命令的$site_info变量是从用户传来的url参数,经过filter_var和parse_url两个函数过滤而来。之后又规定当url参数的值以hetianlab.com结尾时,才会执行exec函数。
这就需要绕过filter_var和parse_url函数,并且需要满足$site_info['host']的值以hetianlab.com结尾,然后通过执行系统命令获取flag。
Payload为/ctf/index.php?url=demo://%22;ls;%23;hetianlab.com:80/
直接用cat f1agi3hEre.php命令过不了filter_var函数检测,因为包含空格,使用如下payload获取flag:/ctf/index.php?url=demo://%22;cat<f1agi3hEre.php;%23;hetianlab.com:80/
总结一下filter_var函数的审计流程:
快去合天网安实验室搜索实验--PHP代码审计之filter_var函数
三、PHP代码审计之escapeshellarg与escapeshellcmd函数
先看一下两个函数的相关定义,escapeshellarg函数:
$arg变量表示需要被转码的参数,函数返回值为转码之后的字符串。escapeshellcmd函数:
$command变量代表要转义的命令,函数返回值为转义后的字符串。以一个由PHP内置函数mail,结合escapeshellarg与escapeshellcmd函数所引发的命令执行漏洞为例,代码如下:
第4行代码的作用是确保只使用有效的电子邮件地址$email,filter_var函数用于使用特定是过滤器过滤一个变量。PHP的mail函数在底层实现中,调用了escapeshellcmd函数,对用户输入的邮箱地址进行检测。即使存在特殊符号,也会被escapeshellcmd函数处理转义,无法达到命令执行的目的。第6行代码的作用是处理$email传入的数据,而escapeshellarg和escapeshellcmd两个函数一起使用,会造成特殊字符逃逸,导致远程代码执行。
PHPMailer命令执行漏洞(CVE-2016-10033)也是利用escapeshellarg和escapeshellcmd两个函数结合使用,导致了单引号逃逸。具体的漏洞分析和利用过程可以去合天网安实验室搜索下面这个实验进行学习:
总结一下escapeshellarg与escapeshellcmd函数的审计流程:
四、PHP代码审计之parse_str函数
同样先了解parse_str函数的相关定义:
$encoded_string变量代表输入的字符串,如果设置了第二个变量result,变量将会以数组元素的形式存入数组,作为替代。下面简述parse_str函数缺陷引发的变量覆盖漏洞,代码如下:
由于第22行parse_str()调用,其行为非常类似于注册全局变量,通过提交类似config[dbhost]=127.0.0.1这样的数据,因此可以控制getUser()中第6到第9行的全局变量$config。如果目标存在登录验证的过程,就可以通过变量覆盖的方法,远程连接我们自己的MySQL服务器,从而绕过登录验证进行下一步攻击。一个简单的例子:
直接覆盖了原有的变量$b。
parse_str函数还有一个有意思的CTF练习,首先利用PHP哈希比较缺陷,构造请求参数,使其经过哈希之后,值是以’OE’开头。缺陷就是如果两个不同的密码经过哈希之后,其哈希值都是以'OE'开头,PHP将会认为它们结果都为0。请求后页面会出现‘flag is here’,点击跳转至flag.php。题目真正的考察点在于flag.php存在一个refer判断,判断refer是否存在,如果存在则展示上传页面,否则返回‘you can not see this page’。接下来的部分存在时间竞争问题,需要在写入too slow之前访问之前写入的文件,才能获取flag。
此题的解法是开burp的200线程不断发包,在start attack之前写一个脚本不断请求写入文件的路径,是变量覆盖与竞争条件漏洞的结合利用。
CTF练习地址:合天网安实验室搜索相关实验
总结一下parse_str函数的审计流程:
五、PHP代码审计之addslashes函数
addslashes函数相关定义:
$str表示要转义的字符,当我们要往数据库中输入数据时,例如将名字O’reilly插入到数据库中,就需要对其进行转义。以一个用户登录程序为例,考察通过SQL注入绕过登录验证,代码如下:
第29行通过POST方式传入user和passwd两个参数,通过isValid函数判断是否合法。isValid函数主要功能代码在第10~20行,调用sanitizeInput方法对user和passwd进行相关处理。sanitizeInput方法主要功能代码在第22~25行,针对输入的数据调用addslashes函数进行处理,然后对处理后的内容进行长度判断,长度大于20则只截取前20个字符。
这道题已经过滤了单引号,正常情况是没有注入了,为什么还能导致注入呢?原因实际上出在第24行substr函数这里,下面简单看一下substr函数的定义:
substr函数的参数说明:string表示输入的字符串(至少有一个字符),如果start为非负数,返回的字符串从string的start位置开始,从0开始计算;如果start为负数,返回的字符串从string结尾处向前数,从第start个字符开始。
注:如果string的长度小于start,将返回false。
length:如果length为正数,返回的字符串将从start处开始,最多包括length个字符(取决于string的长度);如果length为负数,string末尾处的length个字符将会被省略(若start是负数则从字符串尾部算起);如果length为0、false或null,则返回一个空字符串;如果没有提供length,返回的字符串将从start位置开始,直到字符串结尾。关于substr函数一个简单的例子:
substr中的参数0代表从位置为0的字符开始计算,2代表返回的字符串将从0(start)处开始最多包括2(length)个字符。
再回到题目中,我们知道反斜杠可以取消特殊字符的用法,而注入想要通过单引号闭合,必然会引入反斜杠。将官方提供的payload带入题目中,拼接第15~17行代码中的SQL语句:select count(p) from user u where user = ’1234567890123456789\’ AND password = ‘$pass’
这里的SQL语句由于反斜杠的原因,user=’1234567890123456789\’最后这个单引号会失去它的作用,我们让password=or 1=1#,那么最后的SQL语句为:select count(p) from user u where user = ’1234567890123456789\’ AND password = ‘or 1=1#’
此时user值为1234567890123456789\’ AND password =,可以保证带入数据库执行的结果为true,就能顺利地通过验证。因此使用形如user=1234567890123456789’&passwd= or 1=1#的payload即可逃逸出\(反斜杠)注入。
苹果CMS视频分享程序8.0版本也曾爆出过SQL注入漏洞,程序调用addslashes函数对反斜杠进行转义处理,但是对用户请求的参数又会进行url解码,因此可以使用双url编码绕过addslashes函数,触发漏洞。
具体的漏洞分析过程可以通过下面的实验进行学习:
总结一下addslashes函数的审计流程:
0x04 总结
除了上面提到的,PHP还有很多常见危险函数,合天网安实验室也有相关的实验方便大家了解PHP常见的危险函数,以及使用这些函数可能导致的漏洞。
代码审计重在分析、重在坚持。文章看到最后,相信大家对代码审计这个名词不再陌生,学习完上述所有的实验,再上GitHub找几个代码审计的案例源码练练手,差不多就算入门了。安全学习贵在实践、贵在总结,还记得文章一共提到了哪些实验吗,还等什么,搜索前往合天网安实验室进行学习啊!
暑假来啦
你以为暑假就是
空调WIFI西瓜
世界杯煲剧沙发
当然不是
那只是普通青年的玩法
对于有为青年
一定是有自己的暑假目标
正值毕业季
求职季
于大学生而言
为自己的职场“镀金”是当务之急
毕竟如果没有一技之长
很难突破重围,拿下满意的offer
雅腾教育助力大学生高薪就业
特开设PHP软件开发暑期实战班
采用小班现场面授
技术总监手把手辅导
注重学员理论与企业项目实战能力培养
提升企业项目开发经验
(2018php暑假班实战班开班现场照片)
本期暑假班学员来自江西各大高校
有东华理工大学
南昌工程学院
江西科技学院
江西制造学院
北京交通大学
......
专业有
软件工程
电子商务
机电一体化
模具
工商管理
......
有14级应届毕业生
有15级在校大三学生
更有16级在校大二学生
最终目的都一样
让自己拥有职业技能
提升职场竞争力
最终实现高薪就业
衷心祝愿
雅腾教育php暑期实战班圆满成功
学有所获
满载而归
梦想成真
前言
静态变量用的不多,但是静态的类属性、类方法,则是工作中必不可少的一个知识点。
基础语法
先看代码,下面逐一进行解释。
“::” 是什么?
它是两组冒号,调用静态资源专属语法,基本功能接近 ->。
定义静态方法、属性
在属性、方法前加 static 关键字,就可以将其定义为静态。
调用静态属性
必须通过 类::$属性名 的形式,不能使用 $this->属性名。
调用静态方法
可以通过 类::方法名() 的形式,也可以通过 $this->方法名() 的形式。
关于 $this 伪变量
因为静态调用没有 new 类() 的过程,所以 $this 不存在,调用就报错(参考代码16行)需改为 self::$属性(参考11行)
实战意义
不用 new,用起来省事,这是表面上最容易看到的优点。
除此之外,看一个例子
下面的代码,执行结果是什么?
会报错!因为 $x 是局部变量,离开函数后就销毁了。
看另一个例子
执行后会怎样?(SoDevel 这个类来自第一段代码)
不会报错,可以正常使用。
为什么会这样?
普通局部变量,一旦函数执行完毕就销毁,但是静态变量不会。
静态类属性就更牛了,不光不会销毁,还可以被其他局部环境所调用。(静态变量虽然没有销毁,但是只能在定义它的函数内使用)
这样有什么意义?
意义大了。
在面向对象编程中,我们主要代码都在局部环境(也就是类方法里),而在方法中定义的变量,都是局部变量。就算使用 $this->var 定义成类属性,也只能在类的内部使用。
而 静态类属性 可以无视所有规则,在任何地方都能随时进行赋值、读取操作。
你用过MVC结构的框架吗?
在控制器里定义变量,都需要用 $this->assign() 或者类似的语法,传递给模板。
如果使用静态类属性,就可以免去这个过程,模板拿来即用。
那为什么框架不这样做?
因为某些特定情况不好处理,并且会导致性能下降(静态资源直到程序执行完毕才释放)
总结
昨天少说了一句话,在PHP中 所有全局变量都存储于静态内存区(但他们并不是静态变量)。
所以,你知道全局变量在什么时候销毁吗?
预报:明天给大家讲 单例模式,它是基于静态特性实现的。
前言
Facade 也是一种设计模式,中文称为:外观模式,实际意义是:对复杂的接口进行一次包装,使其更容易使用。在实际开发中,能够帮助我们提高代码的简洁性、接口的易用性,以及更简单有效的测试途径。
如何使用它?
目前主流的几个框架:ThinkPHP5.1、Laravel、yii 都有它的影子(其他框架可能也有,未关注)。ThinkPHP5.1起开始提供Facade,但实现的比较简单,用官方的话说:降低上手门槛,让框架易用,是他们一贯的原则。
如果你基于上述几个框架,那么恭喜你,可以跟着框架文档学习使用即可。
Facade 的代码结构
图片为转载,来自CSDN。
又见“中间商”模式
经常看我文章的同学应该能注意到,这又是“中间商”模式。在应用程序和接口中间加了一层,就是:facade。在实际开发的过程中,我们会频繁利用“中间商”来解决问题,比如多层控制器、中间件等等。
中间商类的设计模式,具备普遍的优缺点:
优点,通过中间商来统一、简化代码行为缺点,增加代码的架构复杂度(还会稍稍降低执行效率)Facade 实现原理
接下来是给大家写的演示代码。
代码解析
Facade类
此为外观模式的管理类,负责外观模式的运转。如果你使用框架,这个类都是框架预先写好的。
App
实际想调用的目标类,我只实现了一个非静态方法:get,App::get() 这样的调用会报错。 实际开发中,所有的业务代码都写在这里。
AppFacade
App的外观类,它继承自 Facade,里边有一个方法 getFacadeAccessor(),负责指向到目标类。
使用
我们可以通过 AppFacade::get() 这样的语法,就能执行App类的get()方法,效果是一样的。
重点是:用静态语法调用了非静态方法,这也是 PHP中 Facade 模式的显著特点。
总结
就算你不知道它有什么用,但至少语法简单了,对吧。
前言
工欲善其事,必先利其器。当你使用PHP编程,就需要对它的运行状况有所了解,否则事倍功半。
从今天起,和大家聊一聊 phpinfo() 函数所展示的信息含义。
phpinfo() 有什么用
它是一个系统函数,你可以直接编写代码 <?php phpinfo();?>,然后通过网页访问它,就能看到一个类似于这样的网页。
该网页包含了当前PHP的各种配置信息、扩展模块的信息等。以前有一种软件叫“探针”,专门用来探测服务器当前的PHP相关信息,现在随着虚拟主机的没落,已经越来越少人用啦。
如何阅读 phpinfo 的信息?
整个网页内容非常多,但主要分为四个部分
基本信息,也就是最顶部的内容。配置信息(Configuration)各种模块的信息PHP Credits,荣誉名单,记录对PHP语言有帮助的人PHP License 版权许可说明
基本配置
本文和大家说说基本信息中,各项内容的含义。(以我当前使用的PHP版本为例)
PHP 版本
最顶端:PHP Version 7.2.3,就是我们当前PHP的版本。
System
Darwin mac.local 17.5.0 Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64 x86_64
运行此PHP的操作系统信息(我是mac机)
Build Date
Mar 19 2018 11:50:19
编译时间
Configure Command
'./configure' '--prefix=/usr/local/opt/php723' '--exec-prefix=/usr/local/opt/php723/' '--enable-debug' '--enable-fpm' '--with-iconv=/usr/' '--with-config-file-path=/usr/local/etc/php723' '--with-openssl=/usr/local/opt/openssl' '--enable-bcmath' '--with-curl' '--enable-exif' '--with-gd' '--with-mysqli' '--with-pdo-mysql' '--enable-zip' '--with-libzip' '--enable-mysqlnd' '--enable-sockets' '--enable-mbstring' '--enable-soap' '--with-freetype-dir=/usr/local/opt/freetype' '--with-xmlrpc' '--with-jpeg-dir=/usr/local/opt/jpeg' '--with-png-dir=/usr/local/opt/libpng' '--with-libxml-dir=/usr/local/opt/libxml2' '--without-gmp'
编译时,使用的各项配置信息。
Server API
FPM/FastCGI
当前采用的服务模式为 FCGI(快速通用网关接口协议),实现该协议的服务为 FPM(也就是PHP-FPM),与 NGINX 搭配的时候,基本都是通过它来进行通讯的,以后有机会和大家细聊。
Virtual Directory Support
disabled
虚拟目录支持,目前是禁用状态(disabled)也就是不支持。
Configuration File (php.ini) Path
/usr/local/etc/php723
PHP.ini 的所在目录。
Loaded Configuration File
/usr/local/etc/php723/php.ini
php.ini 所在的完整文件路径。
Scan this dir for additional .ini files
(none)
Additional .ini files parsed
(none)
PHP API
20170718
PHP核心版本,一般大版本变更时,此日期会随之变化(应该是核心版本的发布或编译日期)
其他
剩下的就不一一说明了,需要额外提醒的是,此处出现的 zend 是PHP解释器名字,你也可以认为它就是PHP核心,除此之外还有 zend框架、zend代码混淆、zend代码编辑器,注意不要把自己弄混了。
总结
今天先和大家介绍下基本信息,其中像PHP版本、configure的编译配置、php.ini的路径、php api 的版本等几项,是我们日常开发中需要用到的。其余的,大家有兴趣可以自己行了解。
明天开始,介绍第二部分:各种扩展库。
小程序入局者越来越多,微信小程序第一个开发,相当于确立了非官方标准,之后的支付宝小程序俨然改了一个名字版的微信小程序存在,再到之后的百度智能小程序,开发框架及标准都是一样的。
一张图集齐bat小程序三家小程序除了三个文件,app.json,app.js,app.wxss,index.wxml叫法不同外,其他近乎一样
app.json 对应的是配置文件
app.js 三家一样的,都是javascript文件,前后端同学应该都懂
app.wxss 这个叫法不一样,但是都是css的超集[支持css的绝大部分语法,基本可以理解就是css]
index.wxml 这个就是对应就是网页三剑客的html了,只是有一些稍微的区别而已。
对于入门phper来讲,最简单也最高效的开发框架非tp(thinkphp)莫属了,为啥呢?有中文文档,国人开发,清晰的文档及国人高效论坛的支持。进化到thinkphp 5版本的tp以api接口为定义,更加符合现在小程序的开发逻辑, 也更贴合现在前端环境的MVVM架构。
在开发小程序环境下,对于传统的mvc架构,砍掉了v,只剩下mc。小程序端相当于v。
thinkphp5开发将主要着重于mc方面的开发
在接下来的课程中,我们将基于thinkphp5+wepy的方式讲解价值百万小程序商城的开发。
欢迎关注我门的百家号,持续更新小程序商城开发系列
路由是开发过程中比较重要的一环,在ThinkPHP5.1版本后路由默认开启,并且不可以关闭,足以可见它的重要性。下面我们来具体的说一下;
注意事项
1、默认开启、不可关闭;
2、优先匹配、多模式支持;
3、匹配成功,不再继续匹配;
4、默认支持数字、字母、下划线,不支持中文及特殊符号;
PHP主要作用
1、URL链接更加规范、美观,更加适合SEO优化;
2、隐式传入额外请求参数;
3、请求方式拦截,区分GET、POST等请求方式;
4、绑定请求数据;
5、处理请求缓存,优化程序响应时间;
6、路由中间件支持(V5.1.6+版本以上支持);
SEO优化路由定义
1、定义位置:route/route.php文件内,可以在route目录内多文件定义,最终框架会进行路由整合,建议采用域名+分组模式定义路由。
2、定义方式:
Route::get('new/:id','News/read');// 定义GET请求路由规则Route::post('new/:id','News/update');// 定义POST请求路由规则Route::put('new/:id','News/update');// 定义PUT请求路由规则Route::delete('new/:id','News/delete');// 定义DELETE请求路由规则Route::any('new/:id','News/read');// 所有请求都支持的路由规则
请注意:
1、路由匹配成功后,原链接访问方式会失效;
2、完全匹配需在尾部添加$ ;
3、变量可有可无使用[] 包裹变量;
变量规则
系统默认的变量规则设置是\w+,只会匹配字母、数字和下划线字符,并不会匹配特殊符号和中文,需要定义变量规则或者调整默认变量规则。
1、局部配置(仅在当前路由有效)
*定义GET请求路由规则 并设置name变量规则
Route::get('new/:name','News/read')->pattern(['name'=>'\w+']);
2、全局配置(全部路由有效)
*设置name变量规则(采用正则定义)
Route::pattern('name','\w+');
*支持批量添加
Route::pattern(['name'=>'\w+','id'=>'\d+',]);
3、组合变量
*组合变量的优势是路由规则中没有固定的分隔符,可以随意组合需要的变量规则和分割符
Route::get('item-<name>-<id>','product/detail')->pattern(['name'=>'\w+','id'=>'\d+']);
PHP框架路由地址
闭包支持
实际开发过程中不常用,是一种简单直接的定义模式;
Route::rule('hello/:name',function(Request $request, $name){$method = $request->method();return'['. $method .'] Hello,'. $name;});
路由参数
互联网开发路由缓存
在定义大量的路由时,强烈建议使用路由缓存,注意仅在部署模式下有效,开启该缓存可以明显提升路由解析性能。
开启方式,在应用配置文件app.php中设置开启:
'route_check_cache'=>true,
开启后,会自动对每次的路由请求的调度进行缓存,第二次如果是相同的请求则无需再次经过路由解析,而是直接进行请求调度。
清除命令:
>php think clear --route
跨域请求
如果某个路由或者分组需要支持跨域请求,可以使用如下代码:
Route::get('new/:id','News/read')->ext('html')->allowCrossDomain();
注解路由
此方式不建议使用,缺点路由分散不方便管理,同时书写规则要求较为严格。
代码路由分组
强烈建议使用,下面书写一种比较完善的路由分组写法:
Route::group(['method'=>'get','ext'=>'html'],function(){Route::group('blog',function(){Route::rule('blog/:id','blog/read');Route::rule('blog/:name','blog/read');});})->pattern(['id'=>'\d+','name'=>'\w+']);
MISS路由
如果希望在没有匹配到所有的路由规则后执行一条设定的路由,可以注册一个单独的MISS路由,总结来说,可以应用于404页面,防止程序找不到路由而报错(一旦设置了MISS路由,相当于开启了强制路由模式);
Route::miss('public/miss');
资源路由
实际开发过程中不常用,不做描述。
快捷路由
此方式要求在控制器层面定义方法名称较为严格,简单做一下描述,不建议使用。
*给User控制器设置快捷路由
Route::controller('user','index/User');<?php namespace app\index\controller;class User{public functiongetInfo(){ }}
代码路由别名
路由别名不支持变量类型和路由条件判断,单纯只是为了缩短URL地址,并且在定义的时候需要注意避免和路由规则产生混淆。设置操作方法的请求类型:
*user 别名路由到 index/user 控制器
Route::alias('user','index/user',['ext'=>'html','allow'=>'index,save,delete','method'=>['index'=>'GET','save'=>'POST','delete'=>'DELETE'],]);
路由绑定
把当前的URL绑定到模块/控制器/操作,最多支持绑定到操作级别,例如在路由配置文件中添加:
*绑定当前的URL到 index模块
Route::bind('index');
*绑定当前的URL到 index模块的blog控制器
Route::bind('index/blog');
域名路由
支持完整域名、子域名和IP部署的路由和绑定功能,同时还可以起到简化URL、加快匹配的作用。
Route::domain(['blog','admin'],function(){Route::rule('new/:id','index/news/read');});
URL生成
支持路由URL地址的统一生成,并且支持所有的路由方式,但是不建议使用,直接在页面中手动设置,减少模板解析时间。
可以使用助手函数url,不需要继承框架基础控制器类即可使用,示例如下:
url('index/blog/read','id=5&name=thinkphp');
解析后为:/index.php/blog/5/name/thinkphp.html
其他配置方式不做过多讲解。请移步官方文档查看。
ThinkPHP框架常用的是MVC模式,M是模型、V是视图,C是控制器。通过MVC模式将数据从数据库中查询出来,然后传递到页面中。下面我们来说一下具体的情况;
程序一、视图渲染
模板定位规则:当前模块/view/当前控制器名(小写)/当前操作(小写).html。在5.1.6版本后系统会以简洁模式定位模板文件位置,规则如下:当前模块/view/当前控制器(小写)_当前操作(小写).html
1、Fetch方法
fetch方式是渲染模板时最常用的方法,在使用此方法的前提是控制器类需要继承系统控制器基础类。使用方式如下:
(1)、不需要传递任何参数,框架会自动定位到模板文件;
return $this->fetch();
(2)、传递一个参数,框架会定位至当前控制器下的参数一模板文件;
return $this->fetch('edit');
(3)、传递两个参数,框架会定位至参数一控制器下的参数二模板文件;
return $this->fetch('member/read');
注意事项:在书写参数时请不要书写任何后缀,参数只是目录名称或文件名称而已。
(4)、视图根目录下文件
如果想把view文件夹内的单独文件进行渲染,可以在参数位置进行如下书写:
return $this->fetch('/menu');
(5)、特殊模板文件或特殊位置文件
如果项目中存在特殊模板文件,又不想移动位置,可以通过如下方式进行调用:
return $this->fetch('./template/menu.html');
上面书写的目录位置是相对于当前项目入口文件位置(public目录),模板文件后缀无固定要求,可以为html、php、tpl等格式
PHP代码2、助手函数方式
如果控制器未继承系统基础控制器类,同样可以实现视图模板的输出,框架提供了助手函数view(),可以使用如下命令:
return view();
可传递参数及数据,常见的使用方式如下:
return view('模板文件路径','数据');
3、直接解析模板方式
项目中某些页面可能通过直接解析模板的方式就可以实现功能,那么我们可以通过最简单的方式对模板文件进行输出。使用如下命令:
return $this->display();
此方式会直接渲染内容,同样模板标签在视图中可以正常使用。
HTML模板二、视图赋值
1、assign方法
在继承系统基础控制器类后可以通过如下命令进行视图赋值:
$this->assign("名","值");
批量赋值方式:
$this->assign(['名'=>'值','名'=>'值']);
2、方法传入参数方式
此方式在进行视图渲染中提及到了,通过设置模板文件位置时携带数据。命令如下:
$this->fetch('path',['名'=>'值','名'=>'值']);$this->display('path',['名'=>'值','名'=>'值']);
3、助手函数赋值方式
这种方式是项目开发过程中最常见的模式,助手函数无需继承基础控制类,相对而言代码更加精简、可读性更高。命令如下:
return view('path',['名'=>'值','名'=>'值']);
4、公共模板变量赋值方式
可以使用视图类的share静态方法进行全局公共模板变量赋值。命令如下:
use think\facade\View;// 赋值全局模板变量View::share('name','value');// 或者批量赋值View::share(['name1'=>'value','name2'=>'value2']);
视频过滤三、视图过滤
1、局部过滤
在单独方法内进行视图过滤操作。命令如下:
// 使用视图输出过滤return $this->filter(function($content){returnstr_replace("\r\n",'<br/>',$content);})->fetch();
2、全局过滤
如果进行全局过滤方式,需要在初始化方法中进行设置。命令如下:
protected functioninitialize(){$this->view->filter(function($content){returnstr_replace("\r\n",'<br/>',$content); });}
总结:视图过滤方式可以理解过对视图模板中内容进行了替换操作,可以通过此方式减少代码空行,无用的缩进。减少代码体积。
四、模板引擎
框架中内置了模板引擎,默认可以忽略对此进行设置,同时框架支持自定义引擎模式。在配置目录(config目录)下的template.php文件中可进行配置。
默认提供了两种扩展引擎:think-angular、twig(都不是很完美,不建议使用
4、)
五、扩展
如果只想获得解析文件而不进行渲染,如果生成静态HTML文件,采用纯静态化模式。可以使用如下命令:
$html = $this->fetch()->getContent();
此方式返回字符串,可以继承文件创建方式,批量生成HTML静态文件,便于网站优化。
六、总结
1、依据场景,选择不同的渲染方式;
2、合理的进行模板赋值;
3、牢记特殊模板文件位置是基础项目入口文件位置;
4、模板文件配置目录为:config/template.php文件;
在开发过程中,我们需要写控制器、模型、验证代码。最后要写模板代码,如果是前后端分离项目则不用写模板了。直接在接口中返回数据就可以了。模板代码包含了很多知识,下面举例介绍一下;
代码变量输出
1、常见的输出方式是使用大括号({ })的形式,里面写入变量名称。在runtime/temp目录下可以看到编译后的文件,括号解析成了<?php ?>的形式,并且里面包含htmlentities。命令如下(注意$ 和 { 之间不能存在空格):
{$data}
2、原样解析,如果解析富文本内容时使用,使用示例:
{$data|raw}
3、默认值,使用示例:
{$data|default='这是一个默认值'}
4、系统变量输出,主要是获取用户昵称,使用示例:
{$Think.session.name}
5、常量输出,使用示例:
{$Think.PHP_VERSION}
6、配置输出,主要是获取基础网址,使用示例:
{$Think.config.default_module}
PHP使用函数
1、框架内置规则:
2、应用方式:
2.1、单函数应用,使用示例:
{$data.name|md5}
2.2、多函数应用,使用示例:
{$name|md5|upper|substr=0,3}
互联网开发运算符
1、常见运算符
2、三元运算符
2.1、默认写法
{$status?'正常':'错误'}
2.2、简单写法,表示有则输出,无则输出默认值
{$name ??'默认值'}
2.3、为真写法,表示为真的时候才输出默认值
{$name?='默认值'}
2.3、真假写法、表示为真输出值,否则输出默认值
{$name ?:'NO'}
2.4、表达式写法,表达式为真则输出值一,否则输出值二
{$a==$b ?'yes':'no'}
程序代码原样输出
原样输出使用较少,如果想让输出内容不被模板标签所解析,使用如下命令进行输出:
{literal} Hello,{$name}!{/literal}
模板注释
模板注释和代码注释是两种方式,模板注释不会在页面上查看到被注释的代码,而代码注释则可以查看的到。使用方式如下:
{/* 这是模板注释内容*/} 或 {// 这是模板注释内容 }
模板布局
模板布局总结来说就两点:配置和模板;
配置分为模块配置和应用配置,一般情况下后台多应用模板布局方式,在后台模块config/template.php文件内(默认不存在,需手动创建)设置如下代码:
'layout_on'=>true, //开启布局模式'layout_name'=>'layout', //布局文件名称,可设置为 'index/layout'目录形式'layout_item'=>'{__REPLACE__}' //输出替换变量
模板继承
在实际项目开发过程中使用较少,主要是因为继承过于麻烦。
包含文件
在实际项目开发过程中,前端页面使用较多,使用方式较为单一;
1、使用模版文件,多个文件使用逗号分隔;
{include file="public/header,public/menu"/}
2、传入参数,此方式需注意模板中变量值必须存在;
{include file="Public/header" keywords="开源WEB开发框架"/}
开发代码输出替换
1、配置,在应用或模块配置目录下的template.php文件中进行如下代码配置:
'tpl_replace_string'=>['__STATIC__'=>'/static','__JS__'=>'/static/javascript',]
2、总结,优点:方便更改;但是不建议使用,建议在开发过程中设置好目录位置。
标签库
标签库类似于Java的Struts中的JSP标签库,每一个标签库是一个独立的标签库文件,标签库中的每一个标签完成某个功能,采用XML标签方式(包括开放标签和闭合标签)。具体内容请参考官方文档。
内置标签
1、普通循环标签,使用示例:
{volist name="list" id="vo" key="k"}{$k}.{$vo.name}{/volist}
如果没有指定key属性的话,默认使用循环变量i
2、控制输出行数,如输出其中的第5~15条记录,使用示例:
{volist name="list" id="vo" offset="5" length='10'}{$vo.name}{/volist}
3、比较标签(不常用)
4、SWITCH标签(不常用),使用示例:
{switch User.level} {case 1}value1{/case} {case 2}value2{/case} {default /}default {/switch}
5、资源文件加载(常用),使用实例:
{load href="/static/js/common.js,/static/css/style.css"/}
互联网标签扩展
此扩展在开发过程中并不常用,使用起来较为麻烦。
今天介绍一下网站里面常见的用户登录功能的实现
用户登录我们先想一想实现思路,先帮常用的代码放在一个include文件,里面放一些链接数据库,常用函数等公用文件。然后常用的用户信息修改。我们看看需要哪些页面
代码文件公用的头部文件和公用的底部文件单独放在一个页面,方便后期维护。然后就是登陆,注册,逻辑处理。
代码是最基础的实现原理。在原理掌握的基础长就可以进行深化,封装成class文件,简化代码和文件,我们先从最基础的实现原理来看看怎么实现。
登陆的界面首先是基本的登陆页面。不含css,后期可以把页面美化一下。
然后看看数据提交到了loginCheck.php页面进行哪些逻辑处理
php逻辑代码处理我们分析代码 显示引用配置文件,我们看看配置文件,也就是最基本的数据库信息,定义一个数组
数据库配置然后在看看mysql.fun.php通过文件名称我们可以知道这是一个操作数据库的代码,我们把一些常用的数据库操作方在这个里面。然后在去调用。
数据库链接操作注意@的用途,感兴趣的朋友去删除这个看看效果。
接着分析代码就是接受用户名和密码,执行查找数据库操作,存在这个记录就跳转到main.php页面,不存在就跳转到login.php页面。这样也就类似实现一个后台登陆管理功能的实现。登陆成功进入后台,登陆失败禁止登陆。原理是不是很简单。有兴趣的朋友快去制作一个登陆功能吧。
登陆后台模板小编收集了一下后台界面模板和登陆界面模板,想加强这方面的也去试试吧。
网站后台管理界面这样就实现了一个最基本的后台管理功能。