php unserialize 返回false的解决方法

php unserialize 返回false的解决方法

php 提供serialize(序列化) 与unserialize(反序列化)方法。

使用serialize序列化后,再使用unserialize反序列化就可以获取原来的数据。


<?php
$arr = array(
'name' => 'fdipzone',
'gender' => 'male'
);

$str = serialize($arr); //序列化
echo 'serialize str:'.$str."\r\n\r\n";

$content = unserialize($str); // 反序列化
echo "unserialize str:\r\n";
var_dump($content);

 

输出:

serialize str:a:2:{s:4:”name”;s:8:”fdipzone”;s:6:”gender”;s:4:”male”;}

unserialize str:
array(2) {
[“name”]=>
string(8) “fdipzone”
[“gender”]=>
string(4) “male”
}

但下面这个例子反序列化会返回false

 


<?php
$str = 'a:9:{s:4:"time";i:1405306402;s:4:"name";s:6:"新晨";s:5:"url";s:1:"-";s:4:"word";s:1:"-";s:5:"rpage";s:29:"http://www.baidu.com/test.html";s:5:"cpage";s:1:"-";s:2:"ip";s:15:"117.151.180.150";s:7:"ip_city";s:31:"中国北京市 北京市移动";s:4:"miao";s:1:"5";}';
var_dump(unserialize($str)); // bool(false)
?>

检查序列化后的字符串,发现出问题是在两处地方
s:5:”url”

s:29:”http://www.baidu.com/test.html”

这两处应为

s:3:”url”

s:30:”http://www.baidu.com/test.html”

出现这种问题的原因是序列化数据时的编码与反序列化时的编码不一致导致,例如数据库是latin1和UTF-8字符长度不一样。

另外有可能出问题的还有单双引号,ascii字符”\0″被解析为 ‘\0’,\0在C中是字符串的结束符等于chr(0),错误解析后算了2个字符。

\r在计算长度时也会出问题。

解决方法如下:


// utf8
function mb_unserialize($serial_str) {
$serial_str= preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
$serial_str= str_replace("\r", "", $serial_str);
return unserialize($serial_str);
}

// ascii
function asc_unserialize($serial_str) {
$serial_str = preg_replace('!s:(\d+):"(.*?)";!se', '"s:".strlen("$2").":\"$2\";"', $serial_str );
$serial_str= str_replace("\r", "", $serial_str);
return unserialize($serial_str);
}

&nbsp;

echo '<meta http-equiv="content-type" content="text/html; charset=utf-8">';
 
// utf8
function mb_unserialize($serial_str) {
 $serial_str= preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
 $serial_str= str_replace("\r", "", $serial_str);
 return unserialize($serial_str);
}
 
$str = 'a:9:{s:4:"time";i:1405306402;s:4:"name";s:6:"新晨";s:5:"url";s:1:"-";s:4:"word";s:1:"-";s:5:"rpage";s:29:"http://www.baidu.com/test.html";s:5:"cpage";s:1:"-";s:2:"ip";s:15:"117.151.180.150";s:7:"ip_city";s:31:"中国北京市 北京市移动";s:4:"miao";s:1:"5";}';
 
var_dump(unserialize($str)); // false
 
var_dump(mb_unserialize($str)); // 正确

使用处理过单双引号,过滤\r的mb_unserialize方法就能成功反序列化了。
使用unserialize
bool(false)

使用mb_unserialize
array(9) {
 ["time"]=>
 int(1405306402)
 ["name"]=>
 string(6) "新晨"
 ["url"]=>
 string(1) "-"
 ["word"]=>
 string(1) "-"
 ["rpage"]=>
 string(30) "http://www.baidu.com/test.html"
 ["cpage"]=>
 string(1) "-"
 ["ip"]=>
 string(15) "117.151.180.150"
 ["ip_city"]=>
 string(31) "中国北京市 北京市移动"
 ["miao"]=>
 string(1) "5"
}

PHP函数能解码德语 实体符号 转成 实际字符(ä,ö,ë)


Schlankheitspillen Fat Burner | Abnehmen BMI Gewichts-Kontrolle l Fettverbrenner Gewichtabnahme| Appetitz&amp;uuml;gler - Unterdr&amp;uuml;ckung Fetts&amp;auml;uren &amp;amp; F&amp;ouml;rderung Fettabbau Di&amp;auml;t| Glavonoid - Japan


&lt;?php

$title='Schlankheitspillen Fat Burner | Abnehmen BMI Gewichts-Kontrolle l Fettverbrenner Gewichtabnahme| Appetitz&amp;uuml;gler - Unterdr&amp;uuml;ckung Fetts&amp;auml;uren &amp;amp; F&amp;ouml;rderung Fettabbau Di&amp;auml;t| Glavonoid - Japan';
echo html_entity_decode($title);

echo strlen(htmlspecialchars_decode($title));

//输出内容
Schlankheitspillen Fat Burner | Abnehmen BMI Gewichts-Kontrolle l Fettverbrenner Gewichtabnahme| Appetitzügler - Unterdrückung Fettsäuren &amp; Förderung Fettabbau Diät| Glavonoid - Japan

猜你会用到一下内容

PHP怎么将HTML实体转换为普通字符

<?php

$my_str = "I&#039;m good &amp; &lt;b&gt;&quot;boy &quot;&lt;/b&gt;.";

echo htmlspecialchars_decode($my_str);

echo "<br>";

echo htmlspecialchars_decode($my_str, ENT_QUOTES);

echo "<br>";

echo $my_str;

 

 

 

微信小程序 res =>的意义及userInfoReadyCallback函数的作用

刚开始接触微信小程序,想写个迷你计算器的小程序,感觉开发挺方便的,当准备使用用户信息时,打算看一下它是怎么获取用户信息的,为之后获取用户openid准备。获取用户信息主要在app.js 和 index.js中

代码中的 res =>可以理解为function(res),其中res即为返回的数据结果对象,不知道又是哪新出的语法规则(后来补充,这个是ES6的箭头函数,


App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)

// 登录
wx.login({
success: res => {
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo

// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null,
}
})

index.js


/index.js
//获取应用实例
const app = getApp()

Page({
data: {
motto: '欢迎使用迷你计算器',
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},

onLoad: function () {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse){
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
},

getUserInfo: function(e) {
console.log(e)
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
}
})

首先执行的是app.js的wx.getUserInfo,这个是获取用户信息的网络请求,由于其返回结果不知道在index页面加载完成之前还是之后完成,因此分为两种情况:

在index页面加载完成之前返回:此时优先执行app.js中success函数的代码,app.globalData.userInfo就保存了用户信息。运行到这里时,由于userInfoReadyCallback函数是在index.onload中定义的,因此此时该函数并没有被定义,所以不执行该函数。之后执行index.js中onload中的代码,执行第一个if分支,赋值给页面的userInfo和hasUserInfo
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
在index页面加载完成之后返回:此时优先执行index.js中onload中的代码,由于用户信息还没有返回,所以app.globalData.userInfo为null,执行第二个if分支,定义userInfoReadyCallback函数。随后数据被返回,执行success的代码,app.globalData.userInfo在此时才保存了用户的信息,并执行userInfoReadyCallback函数,赋值给页面的userInfo和hasUserInfo
因此总体来说userInfoReadyCallback函数的作用,就是保证页面的userInfo和hasUserInfo被正确赋值,无论用户信息在页面加载完成之前还是之后返回。

原文链接:https://blog.csdn.net/zjw_python/article/details/80641963

H5页面适配iphoneX底部小黑条遮盖内容

iphoneX取消了物理按键,改为底部小黑条,这也在页面开发的过程中,会出现底部内容被小黑条遮盖的现象,影响页面效果,
我们可以这也解决
1:增加viewport属性 viewport-fit=”cover”
<meta name=”viewport” content=”width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0,viewport-fit=cover”>

2 利用constant函数 这个函数是ios11新增的css属性用于设定安全区域与边界的距离

safe-area-inset-left 安全区域与左右上下的距离

safe-area-inset-right

safe-area-inset-top

safe-area-inset-bottom

body{
padding-bottom:constant(safe-area-inset-bottom);
}
3:对fixed元素的适配
类型一: fixed 元素完全吸低(bottom=0)

通过增加内边距扩展高度
{
padding-bottom:constant(safe-area-inset-bottom);
}
通过calc覆盖原来高度
{
height:calc(30(假设值)+constant(safe-area-inset-bottom));
}
还有一种是新增空白元素
{
position:fixed;
bottom:0;
height:constant(safe-area-inset-bottom);
width:100%;
background:#fff;
}
类型二:fixed元素不完全吸底
通过外边距来处理
{
margin-bottom:constant(safe-area-inset-bottom);
}
还有一种通过calc覆盖原来bottom值
{
bottom:calc(20(设定值)+constant(safe-area-inset-bottom));
}

CentOS 7 搭建 TinyProxy 代理

Tinyproxy是一个轻量级的用于POSIX操作系统的http/https代理守护进程。在设计之初就遵循着更快并且更小的原则。在相关的运用案例中,它是一种理想的解决方案,例如在一个需要全部HTTP代理特性的嵌入式部署的案例中。然而,对于需要更大的代理案例来说,它是不可用的。

Tinyproxy本身是小巧的,几乎不需要占用系统资源。安装后,内存占用通常在2M左右,CPU负载随同步连接的数量线性增加(取决于连接的速度)。因此,Tinyproxy可以在一台旧机器上运行,也可以在网络设备上运行,比如基于linux的宽带路由器,而不会对性能产生任何明显的影响。

安装环境:阿里云CentOS7 香港服务器

1. 安装 TinyProxy

在Red Hat Enterprise Linux或其衍生产品(如CentOS)上,可以通过运行yum install tinyproxy从EPEL存储库安装Tinyproxy。

yum -y install tinyproxy
2. 配置 TinyProxy

vim /etc/tinyproxy/tinyproxy.conf
修改 Port 端口,默认为 8888

Port 12801

注释掉 Allow,表示允许所有人访问代理

#Allow 127.0.0.1

隐藏掉Via请求头部,去掉下面的注释

DisableViaHeader Yes

更多配置项,下面是列举一些配置文件默认的,不需要配置:

PidFile “/var/run/tinyproxy/tinyproxy.pid”

LogFile “/var/log/tinyproxy/tinyproxy.log”

LogLevel Info

MaxClients 100

MinSpareServers 5

MaxSpareServers 20

StartServers 10

3. 启动 TinyProxy

systemctl start tinyproxy.service
更多命令如下:

systemctl restart tinyproxy.service

systemctl stop tinyproxy.service

systemctl status tinyproxy.service

systemctl enable tinyproxy.service
4. 关闭防火墙或开放端口访问

方式1:关闭防火墙

/etc/init.d/iptables stop
方式2:开放端口访问

iptables -A INPUT -p tcp –dport 12801 -j ACCEPT
重启防火墙

/etc/init.d/iptables restart
注意:若采用的阿里云、腾讯云、AWS等云服务器,记得要在安全策略里开放端口号

5. 验证生效

1)命令行测试验证(服务器本地测试)

使用TinyProxy拉取google.com的页面信息:

curl -x 127.0.0.1:12801 google.com
可以看到成功拉取了谷歌的页面信息,说明我们的配置是成功。

2)Firefox测试(本机测试)

打开火狐浏览器,选择:选项-网络代理-设置,进入配置界面,根据下图进行配置:

配置完成后,我们使用百度搜索IP,搜索结果如下:

IP地址是我们服务器的地址,说明代理正常访问。然而,如果我们访问谷歌,会得到如下页面:

 

我们无法访问谷歌,不但如此,其他类似的网站我们也是无法访问的。这是为什么?首先,我们看下面的图,当我们想要访问外网的时候,这个请求数据包必然会经过防火墙的检查:

现在我们使用代理,但是依然需要经过防火墙的检查:

由于客户端与TinyProxy之间的请求数据是没有加密的,所以我们无法通过检查。

有人可能疑问,HTTPS是加密的请求,那么为什么不能绕过防火墙呢?

这是因为客户端在进行加密通信以前,需要进行连接握手。在连接握手时,身份认证证书信息(即服务器的公钥)是明文传输的,墙此时就会阻断特定证书的加密连接。

 

参考链接:

https://segmentfault.com/a/1190000011532677

http://blog.51cto.com/tianshili/1733869

http://tinyproxy.github.io/
———————
作者:sjailjq
来源:CSDN
原文:https://blog.csdn.net/sjailjq/article/details/81570592
版权声明:本文为博主原创文章,转载请附上博文链接!

centos 安装 tinyproxy 失败解决办法


yum -y install tinyproxy
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: centos.host-engine.com
* extras: centos.mirror.ndchost.com
* updates: mirror.fileplanet.com
No package tinyproxy available.

 

fastestmirror是yum的一个加速插件,这里是插件提示信息是插件不能用了。

不能用就先别用呗,禁用掉,先yum了再说。

1.修改插件的配置文件

# vi  /etc/yum/pluginconf.d/fastestmirror.conf

enabled = 1//由1改为0,禁用该插件

………………………….

2.修改yum的配置文件

# vi /etc/yum.conf

…………………….

plugins=1//改为0,不使用插件
———————

问题二 No package tinyproxy available.


yum install tinyproxy
base | 3.6 kB 00:00:00
extras | 3.4 kB 00:00:00
nodesource | 2.5 kB 00:00:00
updates | 3.4 kB 00:00:00
vz-base | 951 B 00:00:00
vz-updates | 951 B 00:00:00
No package tinyproxy available.
Error: Nothing to do

 

解决办法: 先安装epel:

yum install epel-release

 

yum install tinyproxy

CentOS 无法通过 yum 安装新版 nodejs 解决办法(安装的还是老版的)

第一步:

curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo bash -

第二步:

sudo yum -y install nodejs

 

如果以上步骤不能安装 最新版 node,执行以下命令后再执行第二步:

sudo yum clean all

 

如果存在多个 nodesoucre,执行以下命令删除,然后重新执行第一第二步:

sudo rm -fv /etc/yum.repos.d/nodesource*

创建ssh用户,设置用户sftp 文件上传目录及权限配置,SSH远程登录配置文件sshd_config详解

服务器创建虚拟主机,增加sftp用户实现文件传输功能,提供我司服务器的某一目录的访问(包括读写)权限,方便他们部署代码文件。

之所以是某一目录的访问,是因为 SFTP 的用户登录后,默认是能看到整个系统的文件目录,这样很不安全。

1、创建新用户

adduser sftpuser

useradd 和 adduser 的区别
useradd 只会添加一个用户,并没有创建它的主目录,除了添加一个新用户之外什么都没有。这个用户甚至不能登录,因为没有密码。所以这里选择 adduser。

2、设置该用户密码

passwd sftpuser

回车后再输入密码即可

3、禁止该用户登录 SSH

因为我们只想该用户使用 SFTP,并不需要该用户能登录 SSH,威胁安全。

usermod -s /bin/false sftpuser1

sftpuser1的 shell 改成 /bin/false。

 

4、修改该用户的家目录

usermod -d /data/wwwroot/user1/ sftpuser1

usermod -d /data/wwwroot/user1/ sftpuser1

这样每次用户访问服务器都会默认打开/data/wwwroot/user1/,但还是可以跳出这个访问其它目录,需要进行下面一步的操作。

5、设置 sshd_config:

打开sshd_config文件

vi /etc/ssh/sshd_config

找到 Subsystem sftp 这一行,修改成:

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

将上面的 sftpuser1 和 /data/wwwroot/user1/ 替换成你需要的。

多个用户请重复配置这三行:
Match user sftpuser2
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user2/

这样可以为不同的用户设置不同的限制目录。

6、重新启动 sshd 服务:

/etc/init.d/sshd restart

现在用 SFTP 软件使用sftpuser1用户登录,就可以发现目录已经被限定、锁死在/data/wwwroot/user1/了。


四、可能遇到的问题

1、修改sshd_config文件后重启 sshd,报错:Directive ‘UseDNS’ is not allowed within a Match block

语法错误,原因未知,只需要把两段配置的位置互调就不报错了。

修改前:

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

UseDNS no
AddressFamily inet
PermitRootLogin yes
SyslogFacility AUTHPRIV
PasswordAuthentication yes

修改后:

UseDNS no
AddressFamily inet
PermitRootLogin yes
SyslogFacility AUTHPRIV
PasswordAuthentication yes

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

注:当你出现这个错误的时候,sftp 肯定是连不上了。如果你习惯用 FileZilla 去修改配置文件,那么此时你得不情愿的切换到
shell,去用 vi/vim 去修改它了。

2、新用户通过 sftp 访问时,权限不全,只能读不能写

我试着用 root 账号去把该用户的家目录权限改成 777,但是会出现该用户 sftp 登陆不了的情况。(报错:Server unexpectedly closed network connection)

google 了原因如下:

给新用户的家目录的权限设定有两个要点:

1、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止的目录拥有者都只能是 root

2、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止都不可以具有群组写入权限(最大权限 755)

 

如果违反了上面的两条要求,那么就会出现新用户访问不了 sftp
的情况。

所以/data/wwwroot/user1/及上级的所有目录属主一定要是
root,并且组权限和公共权限不能有写入权限,如果一定需要有写入权限,那们可以在/data/wwwroot/user1/下建立 777 权限的文件夹

mkdir /data/wwwroot/user1/upload
chown -R sftpuser1:root /data/wwwroot/user1/upload

这样sftpuser1用户就可以在/data/wwwroot/user1/upload里随意读写文件了。

给sftp创建新用户、默认打开和限制在某个目录

一、环境:

CentOS 6.8
使用 FileZilla 进行 sftp 连接

二、背景

给外包的工作人员提供我司服务器的某一目录的访问(包括读写)权限,方便他们部署代码文件。

之所以是某一目录的访问,是因为 SFTP 的用户登录后,默认是能看到整个系统的文件目录,这样很不安全。

题外话:如果是针对 ftp 的用户权限管理,推荐使用 vsftpd,可通过 yum 直接安装。

三、正文

1、创建新用户

adduser sftpuser1

useradd 和 adduser 的区别
useradd 只会添加一个用户,并没有创建它的主目录,除了添加一个新用户之外什么都没有。这个用户甚至不能登录,因为没有密码。所以这里选择 adduser。

2、设置该用户密码

passwd sftpuser1

回车后再输入密码即可

3、禁止该用户登录 SSH

因为我们只想该用户使用 SFTP,并不需要该用户能登录 SSH,威胁安全。

usermod -s /bin/false sftpuser1

sftpuser1的 shell 改成 /bin/false。

4、修改该用户的家目录

usermod -d /data/wwwroot/user1/ sftpuser1

这样每次用户访问服务器都会默认打开/data/wwwroot/user1/,但还是可以跳出这个访问其它目录,需要进行下面一步的操作。

5、设置 sshd_config:

打开sshd_config文件

vi /etc/ssh/sshd_config

找到 Subsystem sftp 这一行,修改成:

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

将上面的 sftpuser1 和 /data/wwwroot/user1/ 替换成你需要的。

多个用户请重复配置这三行:
Match user sftpuser2
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user2/

这样可以为不同的用户设置不同的限制目录。

6、重新启动 sshd 服务:

/etc/init.d/sshd restart

现在用 SFTP 软件使用sftpuser1用户登录,就可以发现目录已经被限定、锁死在/data/wwwroot/user1/了。


四、可能遇到的问题

1、修改sshd_config文件后重启 sshd,报错:Directive ‘UseDNS’ is not allowed within a Match block

语法错误,原因未知,只需要把两段配置的位置互调就不报错了。

修改前:

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

UseDNS no
AddressFamily inet
PermitRootLogin yes
SyslogFacility AUTHPRIV
PasswordAuthentication yes

修改后:

UseDNS no
AddressFamily inet
PermitRootLogin yes
SyslogFacility AUTHPRIV
PasswordAuthentication yes

Subsystem sftp internal-sftp
UsePAM yes
Match user sftpuser1
ForceCommand internal-sftp
ChrootDirectory /data/wwwroot/user1/

注:当你出现这个错误的时候,sftp 肯定是连不上了。如果你习惯用 FileZilla 去修改配置文件,那么此时你得不情愿的切换到
shell,去用 vi/vim 去修改它了。

2、新用户通过 sftp 访问时,权限不全,只能读不能写

我试着用 root 账号去把该用户的家目录权限改成 777,但是会出现该用户 sftp 登陆不了的情况。(报错:Server unexpectedly closed network connection)

google 了原因如下:

给新用户的家目录的权限设定有两个要点:

1、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止的目录拥有者都只能是 root
2、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止都不可以具有群组写入权限(最大权限 755)

如果违反了上面的两条要求,那么就会出现新用户访问不了 sftp
的情况。

所以/data/wwwroot/user1/及上级的所有目录属主一定要是
root,并且组权限和公共权限不能有写入权限,如果一定需要有写入权限,那们可以在/data/wwwroot/user1/下建立 777 权限的文件夹

mkdir /data/wwwroot/user1/upload
chown -R sftpuser1:root /data/wwwroot/user1/upload

这样sftpuser1用户就可以在/data/wwwroot/user1/upload里随意读写文件了。

php 图形用户界面GUI 开发

一、下载指定系统扩展

1
2
http://pecl.php.net/package/ui
http://pecl.php.net/package/ui/2.0.0/windows

由于我的系统是64位win10,php版本是7.1,所以选择7.1 Thread Safe (TS) x64,linux用户可以自行下载源码包,编译安装。

解压php_ui-2.0.0-7.1-ts-vc14-x64.zip,把php_ui.dll复制到你php.ini中extension_dir设置的目录,把libui.dll和pthreadVC2.dll复制到C:\Windows\System32目录下。

在php.ini中加入如下:

1
extension=php_ui.dll

然后重启服务,phpinfo()查看,ui扩展安装成功。

 

二、我们创建一个简单的计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
use UI\Window;
use UI\Size;
use UI\Controls\Entry;
use UI\Controls\Label;
use UI\Controls\Button;
use UI\Controls\Grid;
//创建一个窗口
//参数一表示窗口标题
//参数二表示窗口大小
//参数三表示是否显示菜单
$win new Window('简单的计算器'new Size(640, 480), true);
//创建一个文本框
//Entry::Normal 普通单行文本框
//Entry::Password 密码框
//Entry::Search 搜索框
$num1 new Entry(Entry::Normal);
$num2 new Entry(Entry::Normal);
$ret new Entry(Entry::Normal);
//创建一个标签
$lab new Label('+');
//创建一个按钮
$btn new class('计算'extends Button {
    public function __construct($text) {
        parent::__construct($text);
    }
    protected function onClick() {
        global $num1$num2$ret;
        $n1 $num1->getText();
        $n2 $num2->getText();
        $ret->setText($n1 $n2);
    }
};
//创建一个网格
$grid new Grid();
//把上面的控件加入到网格布局中
$grid->append($num1, 0, 0, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($lab, 0, 1, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($num2, 0, 2, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($btn, 0, 3, 1, 1, true, Grid::Center, false, Grid::Center);
$grid->append($ret, 0, 4, 1, 1, true, Grid::Center, false, Grid::Center);
//把布局加入到窗口中
$win->add($grid);
//显示窗口
$win->show();
UI\run();

在控制台下运行php脚本

1
> php index.php

运行结果如下:

 

三、我们创建一个常用的注册表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
use UI\Window;
use UI\Size;
use UI\Controls\Box;
use UI\Controls\Entry;
use UI\Controls\Button;
use UI\Controls\Form;
use UI\Controls\Radio;
use UI\Controls\Check;
use UI\Controls\Combo;
use UI\Controls\MultilineEntry;
//创建一个窗口
//参数一表示窗口标题
//参数二表示窗口大小
//参数三表示是否显示菜单
$win new Window('简单的计算器'new Size(640, 480), true);
//创建一个表单
$frm new Form();
//用户名
$user new Entry(Entry::Normal);
$frm->append('用户名:'$user, false);
//密码
$pwd new Entry(Entry::Password);
$frm->append('密码:'$pwd, false);
//性别(单选)
$sex new Radio();
$sex->append("男");
$sex->append("女");
$sex->append("未知");
$frm->append('性别:'$sex, false);
//爱好(多选)
//创建一个盒子,水平排列
$loveBox new Box(Box::Horizontal);
$love1 new Check('看书');
$love2 new Check('旅游');
$love3 new Check('游戏');
//把多选控件加入盒子中
$loveBox->append($love1);
$loveBox->append($love2);
$loveBox->append($love3);
$frm->append('爱好:'$loveBox, false);
//地区(下拉框)
$area new Combo();
$area->append("北京");
$area->append("上海");
$area->append("武汉");
$frm->append('地区:'$area, false);
//简介(多行文本)
$desc new MultilineEntry();
$frm->append('简介:'$desc, false);
//注册按钮
$reg new class('注册'$winextends Button {
    protected $win;
    public function __construct($text$win) {
        $this->win = $win;
        parent::__construct($text);
    }
    //用于重写父类的单击事件
    protected function onClick() {
        $this->win->msg('消息''你点击了注册按钮');
    }
};
$frm->append(''$reg);
$win->add($frm);
//显示窗口
$win->show();
UI\run();

运行结果如下:

为了避免每次都要打命令运行php脚本,我们可以写个bat脚本来运行。

1
2
D:\amp\php7\php.exe -f D:\wwwroot\demo1\index.php
pause

注意php.exe的路径和运行脚本路径,保存为run.bat,运行结果如下: