by秦天 发表于 2018-8-19 12:30

【PHP】真正意义上的PHP调用易语言DLL

本帖最后由 wushaominkk 于 2018-8-20 09:28 编辑

      前言:

      会点PHP的应该知道,PHP的局限性还是有的,比如我最近想翻译一段易语言为PHP代码,因为是从网上下载的源码,打开一看,全是置入代码,无奈也找不到其他能实现我想要的这个功能的代码,可能有人说,置入代码,可以翻译成汇编码,汇编码可以翻译成 伪C代码。伪C代码不就可以翻译成你想要的代码了吗?不管能不能这样翻译,就算可以,不考虑正确性的情况下,不累吗?于是我就想把这段置入代码编译成DLL,给易语言调用,想法是有了,怎么实现,百度了一下,很多人都是把易语言编译成EXE,通过命令行的方式,用PHP的system 或 exec命令,其实我以前也是这样调用,但是仔细观察会发现任务管理器中竟然有EXE的进程,就十分不爽了。又比如PHP后端不能执行JS,或者说不方便,用易语言写一个方法出来调用就行了,总之能干的事情太多了,于是就有了本教程。之所以说是原创,因为我并没有找到关于PHP调用易语言DLL教程


      原理:
      通过C语言编写一个PHP扩展DLL,在这个DLL中去调用我们易语言的DLL。      (由于本人想法是通过PHP扩展DLL的一个命令来调用易语言DLL(0-50个任意参数),加上本人C语言垃圾,导致最终的传参,和返回值,只能用文本型,并且不能有中文),其实如果你想传图片什么的,十六进制或者Base64编码一下就好.
      准备工作:Visual Studio (本人用的2017,其他版本自行测试)
         Cygwin(下载地址:http://www.cygwin.com/)如果下载慢试试百度云:https://pan.baidu.com/s/1x3BCJUocr3LFGrVfmzJgxg            
      PHP源码、PHP二进制文件(也就是成品):下载地址:http://windows.php.net/download/(下载二进制文件时应下载NTS非线程X86的版本)            
      易语言软件
正式开始:

1).先安装Cygwin(安装时间可能需要的有点久,做好心理准备)
http://att.125.la/data/attachment/forum/201808/18/221814xmfbctbjwtiockro.jpg
http://att.125.la/data/attachment/forum/201808/18/221913vfvje3v2qwie3mer.jpg
http://att.125.la/data/attachment/forum/201808/18/222134swuodcdu1ccu17oc.jpg
http://att.125.la/data/attachment/forum/201808/18/222135uiq9hvtco1qxe91c.jpg
下图:在中国,就选http://mirrors.163.com,没有的话就添加,后面一直下一步到结束。(可以按下CTRL多选)
http://att.125.la/data/attachment/forum/201808/18/222337mcpirhpp2hcrg2c7.jpg
2.)
解压PHP源码文件:php-7.2.9-src.zip解压出来(我这里是解压到 C:\php_src )
用记事本打开C:\php_src\ext\ext_skel_win32.php
找到:
$cygwin_path = 'c:\cygwin\bin';
找到这一行,将路径更改为 cygwin 安装的路径 我的是C:\cygwin64\就更改为
$cygwin_path = 'C:\cygwin64\bin';
3.)
解压PHP二进制文件php-7.2.8-nts-Win32-VC15-x86.zip解压到C:\php (解压到其他目录需要配置环境变量,解压到这个目录不用配置环境变量了)
打开CMD 进入到C:\php_src\ext\ 在里面运行命令:C:\php\php.exeext_skel_win32.php --extname=TEXT    【TEXT 可以自定义】
http://att.125.la/data/attachment/forum/201808/19/003457rbpm2iiggbpixixf.jpg
打开C:\php_src\ext\就会看到一个TEXT文件夹

打开Visual Studio 选择“文件”--“新建”--“从现有代码创建目录”
http://att.125.la/data/attachment/forum/201808/18/232201r09ggkfg7sgga1gu.jpg
选择C++
http://att.125.la/data/attachment/forum/201808/18/232347oszfs92zh0zzwwhw.jpg
这里选择刚才生成的文件夹路径,并且给项目命名
http://att.125.la/data/attachment/forum/201808/19/003642oj6of9verqffxew9.jpg
这里选择DLL项目,然后一直下一步,直到完成
http://att.125.la/data/attachment/forum/201808/18/232659cm5nss2sszm22myy.jpg
完成后,打开项目属性

http://att.125.la/data/attachment/forum/201808/19/003745k5f5t550hmluzfe7.jpg
"配置属性"->"常规"->Windows SDK 改为最新
http://att.125.la/data/attachment/forum/201808/19/003820gcbijzqbz65eyi6s.jpg
然后选择 "配置属性"->"c/c++"->"预处理器"->"预处理器定义"->编辑
在尾部添加以下变量:
ZEND_DEBUG=0PHP_EXTENSIONPHP_WIN32ZEND_WIN32HAVE_TEXT=1 (这里红色部分,要改成你的扩展名称,不改成你的扩展名,php会不识别,就是上面这段生成的文件夹名称)COMPILE_DL_TEXTZTS(这一个变量加上是开启线程安全,不加是关闭线程安全)线程安全的版本加,我们是非线程安全所以不加。
添加后点击确定
http://att.125.la/data/attachment/forum/201808/19/004001lm2sjcccsnzzczoz.jpg
然后选择 "配置属性"->"c/c++"->"常规"->"附加包含目录"->编辑
加入以下几个php源码目录(实际目录以开发者自己的目录为准):
C:\php_src
C:\php_src\main
C:\php_src\TSRM
C:\php_src\Zend
http://att.125.la/data/attachment/forum/201808/19/004113bn7ntmh6b7qiptwl.jpg
然后找到"配置属性"->"链接器"->"输入"-"附加依赖项"-"编辑"在最后加入php7.lib (这个文件在php二进制文件加的dev文件中,具体文件名看这个文件夹,这个文件夹只有这一共文件)
http://att.125.la/data/attachment/forum/201808/19/004244n03n8uzd80uaa25g.jpg
然后在 "配置属性"->"链接器"->常规 ,附加库目录输入 php7.lib 文件的路径
http://att.125.la/data/attachment/forum/201808/19/004442x6ph2zkjz7227a4a.jpg
加入完毕后点应用,确定,关闭属性页面,
然后在C:\php_src\win32\build\文件夹里找到“config.w32.h.in”,将这个文件复制到C:\php_src\main\文件夹里,去掉后面的“.in”然后用记事本打开
C:\php_src\main\config.w32.h在第一行加入:#define PHP_COMPILER_ID "VC15"    这里这个VC15,可以在PHP网站上,或者下载的PHP二进制文件名上面看到。
http://att.125.la/data/attachment/forum/201808/19/002201joxsju830j0oju2b.jpg
将这里改为【Release】
http://att.125.la/data/attachment/forum/201808/19/004639n8bj7ljeykjjeksb.jpg
然后尝试生成
http://att.125.la/data/attachment/forum/201808/19/004743hwfzbeeaq9jqaeio.jpg
生成通过,接下来写PHP扩展接口
http://att.125.la/data/attachment/forum/201808/19/004821s3w35rzjs1s91qek.jpg
打开 TEXT.c 文件
http://att.125.la/data/attachment/forum/201808/19/005013rtk8yik1y0gtd1su.jpg
找到以下代码:将 confirm_TEXT_compiled 改为 EDLL
==================================================================
const zend_function_entry TEXT_functions[] = {
      PHP_FE(confirm_TEXT_compiled,      NULL)                /* For testing, remove later. */
      PHP_FE_END      /* Must be the last line in TEXT_functions[] */
};
==================================================================
找到以下代码:将 confirm_TEXT_compiled 改为 EDLL      这个方法就是 扩展库的接口
==================================================================
PHP_FUNCTION(confirm_TEXT_compiled)
{
      char *arg = NULL;
      size_t arg_len, len;
      zend_string *strg;
      if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
                return;
      }
      strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "TEXT", arg);
      RETURN_STR(strg);
}
==================================================================
我们将上面的代码改为 以下代码。       下面代码仅支持无参数,和一个参数的方法,自己可以无限加
==================================================================
PHP_FUNCTION(EDLL)
{

      char *DLL_Name = NULL, *function = NULL, *arg_1 = NULL, *arg_2 = NULL;
      int Len;
      size_t len;
      zend_string *strg;
      int args = ZEND_NUM_ARGS();
      if (args == 1) {
                if (zend_parse_parameters(args, "s", &DLL_Name, &Len) == FAILURE) {
                        return;
                }
                strg = strpprintf(0, "抱歉,请输入动态链接库 %s 函数名称", DLL_Name);
                RETURN_STR(strg);
                return;
      }
      else if (args == 2) {

                if (zend_parse_parameters(args, "ss", &DLL_Name, &Len, &function, &Len) == FAILURE) {
                        return;
                }
      }
      else if (args == 3) {

                if (zend_parse_parameters(args, "sss", &DLL_Name, &Len, &function, &Len, &arg_1, &Len) == FAILURE) {
                        return;
                }
      }
      else {
                strg = strpprintf(0, "抱歉,参数输入过多");
                RETURN_STR(strg);
                return;
      }

      HMODULE hLoad;
      hLoad = LoadLibraryA(DLL_Name);//这里打开第一个参数传进来的DLL名称
      if (hLoad == NULL)
      {
                strg = strpprintf(0, "抱歉,无法载入动态链接库[%s]", DLL_Name);
      }
      else {
                if (args - 2 == 0) {
                        typedef char *(__stdcall*lpAddFun)(); //没有参数
                        lpAddFun addFun; //函数指针
                        addFun = (lpAddFun)GetProcAddress(hLoad, function);//
                        if (addFun != NULL) {
                              strg = strpprintf(0, "%s", addFun());
                        }
                        else {
                              strg = strpprintf(0, "无效方法 %s", function);
                        }
                }
                else if (args - 2 == 1) {
                        typedef char *(__stdcall*lpAddFun)(char[]); //一个参数
                        lpAddFun addFun; //函数指针
                        addFun = (lpAddFun)GetProcAddress(hLoad, function);
                        if (addFun != NULL) {
                              strg = strpprintf(0, "%s", addFun(arg_1));
                        }
                        else {
                              strg = strpprintf(0, "无效方法 %s", function);
                        }
                }
                else {
                        strg = strpprintf(0, "参数错误");
                        RETURN_STR(strg);
                        return;
                }

      }

      RETURN_STR(strg);
}
===================================================
代码改好后,我们生成DLL生成成功,
http://att.125.la/data/attachment/forum/201808/19/010854hv7i5j73wiavj0gg.jpg
我们把这个dll复制到c:\php\ext文件夹
然后到c:\php文件夹将php.ini-production 文件复制一个副本并且改名为php.ini 然后用记事本编辑
http://att.125.la/data/attachment/forum/201808/19/011432i72nhwjdnen9hen9.jpg
在最后一行加入:extension=phptext.dll保存关闭


然后打开易语言,新建->windows动态连接库写几个参数方法,(注意,返回值和参数只能用文本型,且不能为中文)http://att.125.la/data/attachment/forum/201808/19/011844kwdrbgr1zt966rd1.jpg编译为 qintian.dll 放到c:\php文件夹
然后再新建php文件来测试,=======================<?php
echo EDLL("qintian.dll","php")."\r\n";
echo EDLL("qintian.dll","php1","gogo")."\r\n";
echo EDLL("qintian.dll","php2","haha","sbsb");
?>=======================打开CMD切换到c:\php目录执行php.exe d:\test.php(我把上面php代码保存在d:\test.php)http://att.125.la/data/attachment/forum/201808/19/033642k7v7vxg8555frg8u.jpg大功告成。
最后,觉得有用的小伙伴,给个小星星!个人感觉绝对原创吧

LSXG 发表于 2020-5-5 16:05

CarroAro 发表于 2018-8-19 23:40
我也觉得有诡异..
用php你不用linux??



更可怕的是,为什么用Windows Server的 人非要实现PHP调用易语言的DLL,为什么不直接把函数写成PHP的呢?我理解PHP具有局限性,那么为什么非要用C写间接调用,典型E语言受害者,有时间学E不如好好学C/C++去制作你想要的扩展。

CarroAro 发表于 2018-8-19 23:40

Linkasyan 发表于 2018-8-19 13:43
你们为啥非得抱着E不放呢?

我也觉得有诡异..
用php你不用linux??

e语言??
何必呢

小朋友呢 发表于 2018-8-19 12:38

厉害啊楼主,之前只是听说,现在真的看到了

丸子吃枣药丸 发表于 2018-8-19 12:51

学习一波

3094644 发表于 2018-8-19 13:32

学习一下

Linkasyan 发表于 2018-8-19 13:43

你们为啥非得抱着E不放呢?

pojie5201314 发表于 2018-8-19 14:00

谢谢分享支持啊

JunDaYi 发表于 2018-8-19 14:26

真正意义上的PHP调用易语言DLL 之 PHP扩展开发

plpplppl 发表于 2018-8-19 14:33

感谢分享下载看下

ii丶白绝 发表于 2018-8-19 15:05

还行,加油!

悲伤落寞 发表于 2018-8-19 15:35

感谢分享
页: [1] 2 3 4
查看完整版本: 【PHP】真正意义上的PHP调用易语言DLL