Windows Server2012服务器上配置PHP调用PowerPoint COM组件方法

弄这做啥?

  1. 实际的需求是:要通过PHP程序将PPT文件(.ppt,.pptx)按页转为.jpg图片的功能。
  2. 代码不难写,网上有很多。本地测试也容易,很快就搞定,但是到了服务器上,配置了很久。
  3. 每个人的服务器环境不同,我写的方法不一定适应你的情况,但是大同小异,多试试应该就OK。

配置步骤

1. Windows服务器。

我的服务器是安装的Windows Server 2012版本。

2. 安装Office。

想要调用PowerPoint的com组件,必须要在服务器上安装office,我选择的是安装office 2013 64位版本。
安装过程中,报了数次错误,我大概看了下,都是和日志写入什么的相关的,应该不会影响com组件,所以遇到错误我也一概忽略了。

3. php.ini配置。

我的php用的是7.2版本。
在php.ini文件中:
A. 将com.allow_dcom = true前面的#去掉。
B. 增加一行:extension=php_com_dotnet.dll
注意:老版本php中,extension=php_com_dotnet.dll是默认加#写在php.ini文件中的,7.2版本中没有写,但是我去php的ext文文件夹中看了一眼,是有php_com_dotnet.dll这个文件的,所以就放心的把extension=php_com_dotnet.dll加上了。

4.DCOM配置

在DCOM配置的问题上,网上有两个版本,我都列出来。
两个版本都需要先在cmd中输入dcomcnfg,然后会打开【组件服务】的窗口。
点击左侧树形目录中的【DCOM】后,再右侧找到Microsoft PowerPoint幻灯片后,在上面点击右键选择【属性】,会弹出属性窗口,切换到最右侧的【标识】标签,如下图所示:
file
要注意的是,如果你的服务器上没有安装Office PowerPoint,这个服务是找不到的。

版本1:【交互式用户】版本(有瑕疵)。

  1. 在【标识】标签里面选择【交互式用户】。
  2. 这时测试一下,会出现 ERR: Failed to create COM object powerpoint.application': 拒绝访问。的错误。
  3. 这时就需要进行下面的配置:
    切换到【安全】标签下。
    我的做法是在三个权限配置的地方都选择自定义:
    file
    然后,将以下几个用户都添加进去,并赋予全部权限:
    Everyone、NETWORK、SERVICE、Internet来宾用户(IUSER)、IIS、站点用户。

    问题:这样配置后的问题是,在远程桌面连接的情况下,程序运转是正常的,但是如果关闭远程桌面,则会报“因为配置标识不正确,系统无法开始服务器进程。请检查用户名和密码”的错误。所以这个版本的解决方案并不完美。

版本2:【下列用户】版本。

  1. 在【标识】标签里面选择【下列用户】。
  2. 然后通过【浏览】的方式选择Administrator用户,并输入密码。
    file
  3. 在版本1的基础上,再增加Administrator用户和Administrators用户组。

    其中的一个插曲是,当我选择了一个用户并输入密码想要保存的时候,报“8000401a”错误,网上查了下,需要在services.msc中开启server服务才可以。

6. 重启IIS,关掉安全狗。

以上配置完成后,重启IIS还是不能正常使用。我怀疑是服务器安全狗进行了限制,于是关掉了安全狗服务,但还是不行。

7. 重启服务器。

最后想到了重启大法,重启后,程序可以正常运转了。

总结

  1. 安全狗似乎不会对服务器调用DCOM组件做限制,至少我没有遇到。
  2. 重启后才生效的问题。有可能是因为安装了office后需要重启,也有可能是因为做完权限配置后需要重启。
  3. 除了上面提到的用户外,由于我的网站是通过nginx配置的SSL,所以我还加了很多用户,不知道是否有用,都列出来备查吧。
    file
  4. 还有就是在方案2中,添加Administrator账户时,似乎必须通过【浏览】按钮添加,如果直接写Administrator似乎会有问题。
  5. 网上还有说要在web.config中添加<system.web><identity impersonate="true" userName="用户名" password="密码" /></system.web>的,至少在我的服务器环境下这个方案没用。

参考过的文章:
https://blog.csdn.net/weixin_30520015/article/details/99214214
https://blog.csdn.net/taoyuanjsj/article/details/5319582
http://www.wangyang.me/2018/study_01/70.shtml
https://blog.csdn.net/luochuan/article/details/8806705
https://www.heiyu100.cn/news114.html

WAMP3.2.3通过cer证书安装SSL实现https方法

写在前面

SSL的证书有cer,crt,key,pem等多种格式,别问这些格式的证书有什么区别,我也不知道,也没兴趣去研究。
我的情况是,甲方给了个cer证书,要通过这个cer证书实现wamp上SSL功能。具体做法如下。

操作环境

WAMP版本:3.2.3 64位
证书格式:cer

操作步骤

  1. 编辑httpd.conf文件。
    文件位置:
    E:\wamp64\bin\apache\apache2.4.46\conf\httpd.conf
    将文件中这一行:
    LoadModule ssl_module modules/mod_ssl.so
    前面的#去掉。

  2. httpd.conf文件末尾添加下面这行内容:
    Include conf/ssl.conf

  3. E:\wamp64\bin\apache\apache2.4.46\conf目录下新建一个ssl.conf文件,并将如下内容粘贴进去。

    Listen 443
    SSLStrictSNIVHostCheck off
    SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
    SSLProtocol all -SSLv2 -SSLv3
    <VirtualHost *:443>
    DocumentRoot "E:/wamp64/www/"
    ServerName class.blcu.edu.cn
    ServerAlias class.blcu.edu.cn
    SSLEngine on
    SSLCertificateFile "E:/wamp64/bin/apache/apache2.4.46/conf/ssl/star.cer"
    </VirtualHost>
  4. 将cer证书文件复制到如下路径。
    E:/wamp64/bin/apache/apache2.4.46/conf/ssl

  5. 打开php openssl 扩展,在php.ini文件中。
    去掉;extension=php_openssl.dll前面的;

特别注意

重要的事情说三遍!!!
编辑E:\wamp64\bin\apache\apache2.4.46\conf内容时,行首不能有空格或者tab。
编辑E:\wamp64\bin\apache\apache2.4.46\conf内容时,行首不能有空格或者tab。
编辑E:\wamp64\bin\apache\apache2.4.46\conf内容时,行首不能有空格或者tab。

在中国商标网注册新账户时出现“未安装控件”该怎么办?

1. 中国商标网网址

最新的中国商标网网址是:http://sbj.cnipa.gov.cn/

2. 无需通过中介,自己也可以申请商标

网上随便找家商标申请代理公司,一个商标没1000元是别想注册下来的。
其实,国家知识产权商标局早已经开放了企业自己申请商标的入口。只需注册账户,便可以实现网上申请、网上缴费一条龙服务。
然而,很多人至今未能享受到这个便利,主要原因是想在中国商标网注册个新用户,确实有点难。

3. 申请注意事项

3.1 一台电脑只能申请和使用一个软证书。

也就是说,如果你有两家公司,两家公司都想在中国商标网注册用户申请商标,那么你必须有两台电脑才可以。这是官方给出的提示:

3.2 安装软证书需要重启电脑。

在填写申请信息前,确保已经安装了软证书。软证书的安装包可以在这里下载:

安装完成后需要重新启动电脑后才能生效。

3.3 主体资格证明文件扫描件问题。

再填写注册信息的时候,最后一项提交的内容是“上传主体资格证明文件”。官方对这项资料的说明是这样的:
“请上传主体资格证明文件(中文)彩色扫描件,格式为PDF,大小不超过2M。自然人申请的需申请人签名,法人或其它组织申请的需加盖公章”。

这句话其实表达的及其不好,证明文件的彩色扫描件很容易被认为是营业执照的彩色扫描件,而后面还说了一句要加盖公章。难倒要在营业执照上加盖公章后再扫描吗?
其实处理方式很简单:营业执照复印件上加盖公章然后彩色扫描就可以了。
唉~把话说清楚有这么难吗?

3.4. 注册用户时出现“未安装控件”

下面是重点了,安装了软证书后,你在网页里面里面填写完了所有的信息点击提交的时候,竟然又弹出来了“未安装控件”的提示框。这时有两种可能。

3.4.1 情况一:浏览器配置问题

安装完控件后,需要根据商标局官网的提示进行浏览器的配置,简单来说就是三点:
A. 将商标局官网加入安全名单。
B. 将浏览器ActiveX运行安全性完全放开。
C. 如果浏览器提示要运行ActiveX插件,放行。

具体做法可以参考以下页面方法:
先点击飘窗【重要提示】

然后点击【问题二】

3.4.2 情况二:浏览器选择问题

商标局网站已经明确说明了,火狐、谷歌浏览器无法正常使用商标局网站。
360和IE8以上浏览器可以使用。
然而,必须要注意的是,如果使用的IE浏览器,则必须是32位的IE浏览器,64位的不可以。

如果你选择64位的IE浏览器,你把电脑拆了也别想注册成功!

4. 总结

在线申请商标本是便民之举,却搞得如此复杂晦涩。
也许有人会说这样搞是为了提高安全性,但是我想问一句,难倒支付宝安全性比商标局网站差吗?肯定不会,但也没见支付宝网站有这么难搞。
是没能力搞好吗?我想不是,究其原因大家自己去体会吧!

超简单方法将webp转jpg图片

1. 关于webp文件

能看到这篇文章的人都是已经下载了webp文件却发现无法使用或者通过Photoshop编辑的人,所以纠结webp文件是什么的朋友请自行百度吧。
简单来说,webp就是Google搞的,在网页中替代jpg图片的一种东西。
然而,webp文件无法直接在Photoshop中编辑,也无法在Word文档一类的软件中使用。所以将webp转为jpg图片就成为了一种普遍需求。

2. 解决方案

网上有很多在线将webp转jpg的网站。这里介绍一种更简单的方法。
打开Windows自带的【画图】工具,将webp拖入画图工具,然后直接另存为jpg图片就OK了。
如下图所示:
file
以上方法在Windows10中的画图工具中亲测有效,Window7没有试过,大家可以自行尝试!

Python图形界面开发神器-page5.0.3安装程序及安装使用教程

1. 软件使用截图

简单的来说,可以通过此软件完成Python图形化界面设计,软件可以自动生成Python代码,省去了大量的调试界面位置的工作。

file

2. 软件下载安装

2.1 Tcl运行环境下载安装

page软件的运行需要基于Tcl环境,所以先安装Tcl是必须的。
官网Tcl官网下载地址:https://www.activestate.com/products/tcl/downloads/
由于官网下载时需要注册认证,所以我下载好了放在本站上以便大家方便使用:
ActiveTcl-8.6.9.8609.2-MSWin32-x64-5ccbd9ac8

注意:
如果通过官网下载的话,官网上有两个Tcl版本可供下载,运行page5.0.3必须下载ActiveTCL8.6才可以,如果安装的是TCL8.5版本运行page5.0.3时会报invalid command name "try"这样一个错误。

下载完成后,先安装,安装没什么可讲,就是普通的安装过程。

2.2 page5.0.3下载安装

官方在SourceForge上,国内下载可能会比较慢:
http://page.sourceforge.net/
当然,我已经下载好了放在本站上了:
page-5.0.3

安装过程也是普通过程,没什么特别需要说明的。

3. 软件使用

3.1 打开软件

打开桌面上的page图标即可打开软件
file

3.2 拖拽布局

通过拖拽实现页面元素布局,页面元素间存在父元素、子元素之间的关系。元素关系树状结构再左下角显示。这个多试几次就知道是怎么运作了。
file

3.3 生成代码

界面布局完成后,点击主界面菜单栏的【Gen_Python】下的【Generate Python GUI】
file
这时会弹出一个保存文件的窗口,保存的是.tcl的布局文件。后期需要对布局进行调整时,只需要打开这个文件就可以继续工作。

3.4 保存代码

3.3保存tcl文件后,就会弹出一个新页面,这个新页面中就是对应的自动生成的python程序代码:
file

点击左下角【save】按钮,就可以将生成的python代码保存到本地,保存位置默认和3.3里面.tcl文件的保存位置一致。
这时,打开3.3步骤里面.tcl文件的保存位置,就会发现一个和.tcl文件同名但扩展名为.py的文件。

3.5 代码修改

默认情况下,直接运行生成的.py文件会报错,主要错误就在

import page_support

page_support.init(root, top)

这两句上,我的做法是直接删除这两句,然后代码就可以正常运行了。

PHP通过SoapClient调用WebService的wsdl格式接口时的注意事项

1. 前言

话说这是个比较让我长见识的问题。虽然做了这么久的技术,但调用接口一直都是用json。通过WebService调用数据还是第一次接触。
由于自己对WebService不熟悉,所以理所应当的夹起尾巴做人,再不露怯的情况下先研究了一下有关WebService的知识,然后开始照着甲方给的WebService接口文档一个一个的去测试。现在觉得已经出师了,所以把过程记录下。

2. 关于阅读wsdl

wsdl是什么?wsdl怎么撰写?这个更多的是WebService服务器端的事情,也就是说这是提供WebService的人应该考虑的事情,如果你只需要调用WebService,需要了解的内容非常少。只需要基本看懂wsdl就可以了。
wsdl本质上就是XML,其中重要的标签有两个一个是<operation>另一个是<sequence>下的<element>

  • <operation>代表WebService可以调用的方法名称。
  • <sequence>下的<element>代表调用方法时需要的参数。

3. 关于传参的问题

3.1 通过键值对数组向方法传参。

假如我们在调用WebService的时候,需要向方法传参,需要以键值对数组的形式传进去。
为啥要强调这个问题呢?
因为在我拿到的接口文档中,调用接口的方法是以Java形式给出的例子:

public String InvokeIntoBaas(String token, String docId, String DocType)

于是乎我也顺理成章的在php中用下面的写法:

<?php
$client = new \SoapClient('http://XXXXX/XXXX?wsdl');

$token = "asd87a98s4ga515sd3ga12ga897sd";
$docId = "32";
$DocType = "tscDoc";

$result = $client->InvokeIntoBaas($token, $docId, $DocType);
var_dump($result);
?>

然后你会发现,这样肯定是无法运行成功的。
向方法传值,一定是通过键值对数组,数组里面写明参数名称和参数值,也就是说无论有多少个参数,都是向方法里面传一个键值对数组就够了。
就像下面这种方式:

<?php
$client = new \SoapClient('http://XXXXX/XXXX?wsdl');

$param = [];
$param["token"] = "asd87a98s4ga515sd3ga12ga897sd";
$param["docId"] = "32";
$param["DocType"] = "tscDoc";

$result = $client->InvokeIntoBaas($param);
var_dump($result);
?>

只有通过键值对数组的方式,WebService才能把传入的内容准确的识别。也就是说,WebService识别传入的参数不是通过参数的前后顺序,而是通过参数键值对中的键名。

3.2 参数内容以wsdl中的内容为准。

为什么上面要强调下wsdl呢?是因为我拿到WebService的接口文档时,接口文档里面写的一些内容无论我怎样试验都无法使用成功。最后发现,接口文档时间太久了,其中的某个字段名称已经更新。
而我是怎么知道的呢?
是通过看wsdl中<sequence>下的那些<element>知道的。
换句话说,再你向WebService中的方法传参的时候,参数键值对中的键名一定要和wsdl中的名字一一对应,差一个字母也不可以。

必须要提的
就通过这一点,我很肯定的指出了文档的错误,一个现学现用的新手给WebService开发人员还上了一课。是不是很厉害!哈哈哈!

4. 几个重要的函数

echo("打印暴露的方法:");
var_dump($client->__getFunctions());
print("<br/>");
echo("打印对应方法的参数和参数类型:");
var_dump($client->__getTypes());
print("<br/>");
echo("最后一次请求的头数据:");
var_dump($client->__getLastRequestHeaders());
echo "<br>";
echo("最后一次请求的数据:");
var_dump($client->__getLastRequest());
echo "<br>";
echo("最后一次返回的头数据:");
var_dump($client->__getLastResponseHeaders());
echo "<br>";
echo("最后一次返回的数据:");
var_dump($client->__getLastResponse());

PHP中使用SoapClient对象访问wsdl得到空object(stdClass),而__getLastResponse()方法却能获取XML返回结果的解决方案

1. 问题重现

<?php
$client = new \SoapClient('http://192.168.0.111:8989/dbservice/selectAll?wsdl');
$param = [];
$param['users'] = 'all';
$result =  $client->selectAllinspectOperation($param);
var_dump($result);
?>

运行后的返回结果如下,以下结果是全部返回内容,并没有隐藏什么:

object(stdClass)[2]
  public 'record' => 
    array (size=2)
      0 => 
        object(stdClass)[3]
      1 => 
        object(stdClass)[4]

2. 思考过程

  • 首先,运行结果没有报错。
  • 然后,selectAllinspectOperation()这个函数的目的是返回数据库中所有的结果。而数据库中目前只有两条数据,所以从返回结果来看,正好有个长度为2的数组。所以我认为查询是成功,且返回了正确的条目数。
  • object(stdClass)这个东东我比较陌生,查了下php文档,是个叫做基类的对象。具体是啥东东对本问题不是很重要,就不赘述了。当时我认为问题就是在object(stdClass)上,可能object(stdClass)把返回结果都封装隐藏起来了,所以看不到。
  • 于是乎又是一顿狂查,网上查到了一个函数get_object_vars()可以把object转为数组,试了一下,确实是把对象转为数组了,上面代码最后一句修改以下,运行结果如下:
    //var_dump(get_object_vars($result));运行结果
    array (size=1)
    'record' => 
    array (size=2)
      0 => 
        object(stdClass)[3]
      1 => 
        object(stdClass)[4]

    不过上面的结果只把最外层的object转为了数组,于是再深入以下,把里面的object(stdClass)也转为数组,同样是最后一行代码修改下,运行结果如下:

    //var_dump(get_object_vars(get_object_vars($result)["record"][0]));运行结果
    array (size=0)
    empty
  • 这下子又晕了,得到的是空值。于是又是一顿狂查,查到了几个SoapClient中的函数,可以打印SoapClient调用过程中的各种信息,于是把每个函数都写下来看看能返回什么结果:
    echo("打印暴露的方法:");
    var_dump($client->__getFunctions());
    print("<br/>");
    echo("打印对应方法的参数和参数类型:");
    var_dump($client->__getTypes());
    print("<br/>");
    echo("最后一次请求的头数据:");
    var_dump($client->__getLastRequestHeaders());
    echo "<br>";
    echo("最后一次请求的数据:");
    var_dump($client->__getLastRequest());
    echo "<br>";
    echo("最后一次返回的头数据:");
    var_dump($client->__getLastResponseHeaders());
    echo "<br>";
    echo("最后一次返回的数据:");
    var_dump($client->__getLastResponse());

    最重要的就是最后一个__getLastResponse()函数,发现所有期望的查询结果实际都返回回来了:
    file

  • 这就奇怪了不是吗?明明已经返回了查询结果,为什么之前获取不到呢?于是我放弃了这个接口,而是测试接口文档中其它的接口,却惊喜的发现其它接口是可以正常返回数据的,虽然返回的也是object(stdClass)类型数据,但是object(stdClass)下面是有具体的数值的。于是我开始怀疑,是不是给的接口有问题?
  • 于是又是一轮查询和思考。说实话,这方面的文档真的很少。经过国内、国外各种网站的查询和信息汇总。最终确定,确实是接口有问题。

3. 问题说明。

基本可以肯定的是,如果可以通过__getLastResponse()看到数据,而打印的数据是空object(stdClass),这个不是使用WebService的问题,而是服务器端WebService的返回值不符合相关规范,导致SoapClient无法对返回结果正常解析导致的。
所以,不要再症结这个问题了,除非你能修改WebService的内容,否则常规手段解决不了这个问题。

4. 解决方案。

之前也说过了,可以通过__getLastResponse()获取返回的内容。反正已经有了结果了,直接处理结果字符串不就好了吗。
所以解决方案很简单,直接使用PHP的XML处理函数,或者直接写个正则表达式获取里面的结果就好了!

5. 总结

我把以上这些情况反馈给了接口提供方,那边也最终证实,确实是他们返回的数据格式有瑕疵。
重要的事情说三遍,遇到这种情况:
不是你的问题!
不是你的问题!
不是你的问题!
是WebService的问题!
是WebService的问题!
是WebService的问题!

PHP正则表达式函数preg_match_all()用法

1. preg_match_all()

preg_match_all("/匹配模式/",$字符串,$匹配结果);

1.1 $匹配结果

匹配出来的结果存储在多维数组中,从多维数组中获取匹配结果的方式如下:

1.1.1 如果不含()子表达式

如果匹配模式中不含()子表达式的话,所有匹配结果都存储在返回结果第一个维度的第一个元素中,即:

$匹配结果[0][0];
$匹配结果[0][1];
$匹配结果[0][2];
1.1.2 如果含()子表达式

如果匹配模式不含()子表达式的话,整体匹配结果存储在返回结果第一个维度的第一个元素中;子表达式的匹配结果则顺延至返回结果的第一个维度的第二个、第三个...元素中,即:

//整体匹配结果
$匹配结果[0][0];
$匹配结果[0][1];
$匹配结果[0][2];
//第一个子表达式匹配结果
$匹配结果[1][0];
$匹配结果[1][1];
$匹配结果[1][2];
//第二个子表达式匹配结果
$匹配结果[2][0];
$匹配结果[2][1];
$匹配结果[2][2];

1.2 $字符串

$字符串必须在一行中。如果不在一行,则再匹配是需要考虑换行符\r\n的问题。

2. 任务描述

通过PHP的SOAP获得了一个XML的字符串,需要对这个XML字符串中的内容进行提取。XML字符串内容如下:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
    <soap:Body>
        <dbs:resultset xmlns:dbs="http://www.royotech.com/">
        <record>
            <float_id>95551e1d7bf9430d80361a0d21d13cd3</float_id>
            <float_name>张三</float_name>
            <float_sex>男</float_sex>
            <float_native>北京市东城区</float_native>
            <float_card>110102199008080808</float_card>
            <float_address>福建省莆田区</float_address>
            <float_unit>福州市美术设计制作有限公司</float_unit>
            <float_unit_adress>福建省莆田区</float_unit_adress>
            <float_job>销售</float_job>
            <float_states>0</float_states>
        </record>
        <record>
            <float_id>be7b91fed02641108ddb612bf15de26c</float_id>
            <float_name>李四</float_name>
            <float_sex>男</float_sex>
            <float_native>北京市东城区</float_native>
            <float_card>110103199106060606</float_card>
            <float_address>新乡市</float_address>
            <float_unit>新乡市电子技术有限公司</float_unit>
            <float_unit_adress>新乡市</float_unit_adress>
            <float_job>IT开发</float_job>
            <float_states>0</float_states>
        </record>
        </dbs:resultset>
    </soap:Body>
</soap:Envelope>

3. 代码

<?php
    $xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body><dbs:resultset xmlns:dbs="http://dbservices.tongtech.com/"><record><float_id>95551e1d7bf9430d80361a0d21d13cd3</float_id><float_name>庄正卿</float_name><float_sex>男</float_sex><float_native>北京市东城区</float_native><float_card>110101199003077950</float_card><float_address>福建省莆田区</float_address><float_unit>福州市益聚美术设计制作有限公司</float_unit><float_unit_adress>福建省莆田区</float_unit_adress><float_job>销售</float_job><float_states>0</float_states></record><record><float_id>be7b91fed02641108ddb612bf15de26c</float_id><float_name>逯俊郎</float_name><float_sex>男</float_sex><float_native>北京市东城区</float_native><float_card>110101199003078793</float_card><float_address>新乡市</float_address><float_unit>新乡市欣丰电子技术有限公司</float_unit><float_unit_adress>新乡市</float_unit_adress><float_job>IT开发</float_job><float_states>0</float_states></record></dbs:resultset></soap:Body></soap:Envelope>';

    $records = null;
    preg_match_all("/\<record\>.*?\<\/record\>/",$xml,$records);

    $tags = [   "inspect_id",
                "report_time",
                "recorder_name",
                "report_name",
                "report_dex",
                "report_card",
                "report_phone",
                "report_dec",
                "result",
                "inspect_states",
            ];

    foreach ($records as $record){
        foreach ($tags as $tag){
            echo $tag . " " . getTagInfo($tag,$record[0]) . "<br/>";
        }
    }

    function getTagInfo($tagName,$str){
        $arr_tag = "";
        preg_match_all("/\<".$tagName."\>(.*?)\<\/".$tagName."\>/",$str,$arr_tag);
        return $arr_tag[1][0];
    }
?>

ThinkPHP5.0增删改操作方法

1. 增加

1.1 单条增加

增加的数据存在数组里,然后调用table的insert方法。

    public function addOneNews(){
        $data = [
            "id" => 35,
            "content" => "新增加的内容",
            "author" => "UYTS",
            "price" => 888
        ];
        $result = DB::table("ksdt_cms_addonnews")->insert($data);
    }

操作成功后,返回值$result是影响的行数。
如果使用insertGetId($data)方法,则返回新增后的数据id。

1.2 批量增加

将要增加的数据放置在数组里面,然后使用table的insertAll方法。

public function addMoreNews(){
        $data = [
            [
                "id" => 36,
                "content" => "新增加的内容1",
                "author" => "UYTS",
                "price" => 888
            ],
            [
                "id" => 37,
                "content" => "新增加的内容2",
                "author" => "UYTS",
                "price" => 999
            ]
        ];
        DB::table("ksdt_cms_addonnews")->insertAll($data);
    }

2. 修改

2.1 where修改

  public function updateInfo(){
        $data = [
            "author" => "ROYOTECH"
        ];
        Db::table("ksdt_cms_addonnews")->where("id","36")->update($data);
    }

2.2 主键修改

如果修改的数组中包含主键,则无需再使用where。

public function updateInfo(){
        $data = [
            "id" => 36,
            "author" => "ROYOTECH"
        ];
        Db::table("ksdt_cms_addonnews")->update($data);
    }

2.3 运算修改

可以在update时使用inc,dec方法进行数值增减运算。

public function updateInfo(){
        Db::table("ksdt_cms_addonnews")->inc("price",2)->where("id",36)->update();
    }

2.4 MySQL函数修改

可以通过exp方法直接调用MySQL函数

    public function updateInfo(){
        Db::table("ksdt_cms_addonnews")->exp("author","LOWER(author)")->where("id",36)->update();
    }

2.5 raw方法修改

将运算过程通过raw函数写在数组里面,然后update

    public function updateInfo(){
        $data = [
            "id" => 36,
            "price" => Db::raw('price - 3'),
            "author" => Db::raw('upper(author)')
        ];
        Db::table("ksdt_cms_addonnews")->update($data);
    }

3. 删除

3.1 单条删除

    public function deleteInfo(){
        Db::table("ksdt_cms_addonnews")->delete(36);
    }

3.2 delete多条删除

    public function deleteInfo(){
        Db::table("ksdt_cms_addonnews")->delete([36,37]);
    }

3.3 where多条删除

    public function deleteInfo(){
        $where['id'] = array('in','1,2,3,4,5');
        Db::table("ksdt_cms_addonnews")->where($where)->delete();
    }

ThinkPHP5.0随学随记

1. 查看最后运行的SQL语句

return DB::getLastSql();

2. 链式查询

低效率方式:

$data1 = Db::name("user")->where("id",27)->select();
$data2 = Db::name("user")-select();

高效率方式:

$data = Db::name("user");
$result1 = $data->where("id",27)->select();
$result2 = $data->select();

然而运行结果发现,在高效模式下,$result2和$result1的返回结果是一样的。如果要去掉$result1的干扰因素,需要这样:

$data = Db::name("user");
$result1 = $data->where("id",27)->order("id","desc")->select();
$result2 = $data->removeOption("where")->removeOption("order")->select();

可以看出,语句变复杂了。
这个问题上需要自己去权衡效率和语句简洁度之间的问题。