Skip to content

Commit 240c71f

Browse files
committed
Compile the PHP Extensions inspectors to native exe, in order to avoid missing dependencies problems (so that they will run in nanoserver)
1 parent 0405698 commit 240c71f

File tree

8 files changed

+317
-323
lines changed

8 files changed

+317
-323
lines changed
Binary file not shown.
Binary file not shown.

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,14 @@ By default `Set-PhpDownloadCache` does not persist the configured value: you can
212212

213213
## FAQ
214214

215-
### What are [those executable](https://github.com/mlocati/powershell-phpmanager/tree/master/PhpManager/private/bin) in the archive???
215+
### What are [those executable](https://github.com/mlocati/powershell-phpmanager/tree/master/PhpManager/private/bin) in the archive?
216216

217217
In order to retrieve the name and the version of the locally available extensions, as well as to determine if the are PHP extensions (to be added in the `php.ini` file with `extension=...`) or Zend extensions (to be added in the `php.ini` file with `zend_extension=...`), we need to inspect the extension DLL files.
218-
This is done with [this C# code](https://github.com/mlocati/powershell-phpmanager/blob/master/src/Inspect-PhpExtension.cs).
218+
This is done with [this C code](https://github.com/mlocati/powershell-phpmanager/blob/master/src/Inspect-PhpExtension.c).
219219

220-
You could think that this C# code could be included in the PowerShell scripts with the [`Add-Type -Language CSharp`](http://go.microsoft.com/fwlink/?LinkId=821749) cmdlet.
220+
You could think that this code could be written in C# and included in the PowerShell scripts with the [`Add-Type -Language CSharp`](http://go.microsoft.com/fwlink/?LinkId=821749) cmdlet.
221221
Sadly, we have to inspect DLLs that are compiled both for 32 and for 64 bits architectures, and the code would be able to inspect DLL with the same architecture used by PowerShell.
222222
So, if PowerShell is running in 64-bit mode, we won't be able to inspect 32-bit DLLs.
223223
That's why we need these executables: the will be started in 32 bits (`Inspect-PhpExtension-x86.exe`) or in 64 bits (`Inspect-PhpExtension-x64.exe`).
224224

225-
Those executables are compiled with this simple [batch file](https://github.com/mlocati/powershell-phpmanager/blob/master/src/compile.bat), but of course you don't have to trust them:
226-
you can download and decompile them with a tool like [ILSpy](https://github.com/icsharpcode/ILSpy) to check that their source code is [exactly this](https://github.com/mlocati/powershell-phpmanager/blob/master/src/Inspect-PhpExtension.cs).
225+
Of course you don't have to trust them: you can compile them on your own (it will require [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)) by calling the [`compile.bat`](https://github.com/mlocati/powershell-phpmanager/blob/master/src/compile.bat) script.

src/Inspect-PhpExtension.c

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
#include <windows.h>
2+
#include <inttypes.h>
3+
#include <stdio.h>
4+
5+
// https://github.com/php/php-src/blob/php-7.2.0/Zend/zend_modules.h#L36
6+
// https://github.com/php/php-src/blob/php-7.2.4/Zend/zend_modules.h#L36
7+
#define ZMA_PHP_7_2 20170718
8+
// https://github.com/php/php-src/blob/php-7.1.0/Zend/zend_modules.h#L36
9+
// https://github.com/php/php-src/blob/php-7.1.16/Zend/zend_modules.h#L36
10+
#define ZMA_PHP_7_1 20160303
11+
// https://github.com/php/php-src/blob/php-7.0.0/Zend/zend_modules.h#L36
12+
// https://github.com/php/php-src/blob/php-7.0.29/Zend/zend_modules.h#L36
13+
#define ZMA_PHP_7_0 20151012
14+
// https://github.com/php/php-src/blob/php-5.6.0/Zend/zend_modules.h#L36
15+
// https://github.com/php/php-src/blob/php-5.6.35/Zend/zend_modules.h#L36
16+
#define ZMA_PHP_5_6 20131226
17+
// https://github.com/php/php-src/blob/php-5.5.0/Zend/zend_modules.h#L36
18+
// https://github.com/php/php-src/blob/php-5.5.38/Zend/zend_modules.h#L36
19+
#define ZMA_PHP_5_5 20121212
20+
// https://github.com/php/php-src/blob/php-5.4.0/Zend/zend_modules.h#L36
21+
// https://github.com/php/php-src/blob/php-5.4.45/Zend/zend_modules.h#L36
22+
#define ZMA_PHP_5_4 20100525
23+
// https://github.com/php/php-src/blob/php-5.3.0/Zend/zend_modules.h#L36
24+
// https://github.com/php/php-src/blob/php-5.3.29/Zend/zend_modules.h#L36
25+
#define ZMA_PHP_5_3 20090626
26+
// https://github.com/php/php-src/blob/php-5.2.0/Zend/zend_modules.h#L42
27+
// https://github.com/php/php-src/blob/php-5.2.17/Zend/zend_modules.h#L42
28+
#define ZMA_PHP_5_2 20060613
29+
// https://github.com/php/php-src/blob/php-5.1.0/Zend/zend_modules.h#L41
30+
// https://github.com/php/php-src/blob/php-5.1.6/Zend/zend_modules.h#L42
31+
#define ZMA_PHP_5_1 20050922
32+
// https://github.com/php/php-src/blob/php-5.0.3/Zend/zend_modules.h#L40
33+
// https://github.com/php/php-src/blob/php-5.0.4/Zend/zend_modules.h#L41
34+
#define ZMA_PHP_5_0_3 20041030
35+
// https://github.com/php/php-src/blob/php-5.0.0/Zend/zend_modules.h#L40
36+
// https://github.com/php/php-src/blob/php-5.0.2/Zend/zend_modules.h#L41
37+
#define ZMA_PHP_5_0_0 20040412
38+
39+
typedef struct {
40+
LPCSTR error;
41+
LPCSTR php;
42+
LPCSTR threadSafe;
43+
LPCSTR type;
44+
LPCSTR name;
45+
LPCSTR version;
46+
} extensionInfo;
47+
48+
typedef struct {
49+
uint16_t size;
50+
DWORD zend_api;
51+
} zend_module_entry_Base;
52+
53+
typedef struct {
54+
zend_module_entry_Base common;
55+
uint8_t zend_debug;
56+
uint8_t zts;
57+
LPVOID ini_entry;
58+
LPVOID deps; // NEW VS 20020429
59+
LPCSTR name;
60+
LPVOID functions;
61+
LPVOID module_startup_func;
62+
LPVOID module_shutdown_func;
63+
LPVOID request_startup_func;
64+
LPVOID request_shutdown_func;
65+
LPVOID info_func;
66+
LPCSTR version;
67+
} zend_module_entry_20050617;
68+
69+
typedef struct {
70+
zend_module_entry_Base common;
71+
uint8_t zend_debug;
72+
uint8_t zts;
73+
LPVOID ini_entry;
74+
LPCSTR name;
75+
LPVOID functions;
76+
LPVOID module_startup_func;
77+
LPVOID module_shutdown_func;
78+
LPVOID request_startup_func;
79+
LPVOID request_shutdown_func;
80+
LPVOID info_func;
81+
LPCSTR version;
82+
} zend_module_entry_20020429;
83+
84+
typedef zend_module_entry_Base*(__stdcall *getModuleEntryBase)();
85+
86+
typedef struct {
87+
LPCSTR name;
88+
LPCSTR version;
89+
LPCSTR author;
90+
LPCSTR URL;
91+
LPCSTR copyright;
92+
} zend_extension_entry;
93+
94+
void parsePhpExtension(HMODULE hModule, extensionInfo* extensionInfo)
95+
{
96+
FARPROC get_moduleAddress = GetProcAddress(hModule, "get_module");
97+
if (get_moduleAddress == NULL) {
98+
get_moduleAddress = GetProcAddress(hModule, "_get_module");
99+
}
100+
if (get_moduleAddress != NULL) {
101+
zend_module_entry_Base* zmeBase = ((getModuleEntryBase)get_moduleAddress)();
102+
switch (zmeBase->zend_api) {
103+
case ZMA_PHP_7_2:
104+
if (extensionInfo->php == NULL) {
105+
extensionInfo->php = "7.2";
106+
}
107+
case ZMA_PHP_7_1:
108+
if (extensionInfo->php == NULL) {
109+
extensionInfo->php = "7.1";
110+
}
111+
case ZMA_PHP_7_0:
112+
if (extensionInfo->php == NULL) {
113+
extensionInfo->php = "7.0";
114+
}
115+
case ZMA_PHP_5_6:
116+
if (extensionInfo->php == NULL) {
117+
extensionInfo->php = "5.6";
118+
}
119+
case ZMA_PHP_5_5:
120+
if (extensionInfo->php == NULL) {
121+
extensionInfo->php = "5.5";
122+
}
123+
case ZMA_PHP_5_4:
124+
if (extensionInfo->php == NULL) {
125+
extensionInfo->php = "5.4";
126+
}
127+
case ZMA_PHP_5_3:
128+
if (extensionInfo->php == NULL) {
129+
extensionInfo->php = "5.3";
130+
}
131+
case ZMA_PHP_5_2:
132+
if (extensionInfo->php == NULL) {
133+
extensionInfo->php = "5.2";
134+
}
135+
case ZMA_PHP_5_1:
136+
if (extensionInfo->php == NULL) {
137+
extensionInfo->php = "5.1";
138+
}
139+
{
140+
zend_module_entry_20050617* zme = (zend_module_entry_20050617*) zmeBase;
141+
if (zme->zts == 0 || zme->zts == 1) {
142+
extensionInfo->type = "Php";
143+
extensionInfo->threadSafe = zme->zts == 0 ? "0" : "1";
144+
if (zme->name != NULL && zme->name[0] != '\0') {
145+
extensionInfo->name = zme->name;
146+
}
147+
if (zme->version != NULL && zme->version[0] != '\0') {
148+
extensionInfo->version = zme->version;
149+
}
150+
}
151+
}
152+
break;
153+
case ZMA_PHP_5_0_3:
154+
if (extensionInfo->php == NULL) {
155+
extensionInfo->php = "5.0";
156+
}
157+
case ZMA_PHP_5_0_0:
158+
if (extensionInfo->php == NULL) {
159+
extensionInfo->php = "5.0";
160+
}
161+
{
162+
zend_module_entry_20020429* zme = (zend_module_entry_20020429*) zmeBase;
163+
if (zme->zts == 0 || zme->zts == 1) {
164+
extensionInfo->type = "Php";
165+
extensionInfo->threadSafe = zme->zts == 0 ? "0" : "1";
166+
if (zme->name != NULL && zme->name[0] != '\0') {
167+
extensionInfo->name = zme->name;
168+
}
169+
if (zme->version != NULL && zme->version[0] != '\0') {
170+
extensionInfo->version = zme->version;
171+
}
172+
}
173+
}
174+
break;
175+
default:
176+
extensionInfo->error = "Unrecognized ZEND_MODULE_API_NO";
177+
break;
178+
}
179+
}
180+
}
181+
182+
void parseZendExtension(HMODULE hModule, extensionInfo* extensionInfo)
183+
{
184+
FARPROC zend_extension_entryAddress = GetProcAddress(hModule, "zend_extension_entry");
185+
if (zend_extension_entryAddress == NULL) {
186+
zend_extension_entryAddress = GetProcAddress(hModule, "_zend_extension_entry");
187+
}
188+
if (zend_extension_entryAddress != NULL) {
189+
FARPROC extension_version_infoAddress = GetProcAddress(hModule, "extension_version_info");
190+
if (extension_version_infoAddress == NULL) {
191+
extension_version_infoAddress = GetProcAddress(hModule, "_extension_version_info");
192+
}
193+
if (extension_version_infoAddress != NULL) {
194+
zend_extension_entry* zee = (zend_extension_entry*) zend_extension_entryAddress;
195+
extensionInfo->type = "Zend";
196+
if (zee->name != NULL && zee->name[0] != '\0') {
197+
extensionInfo->name = zee->name;
198+
}
199+
if (zee->version != NULL && zee->version[0] != '\0') {
200+
extensionInfo->version = zee->version;
201+
}
202+
}
203+
}
204+
}
205+
206+
void parseDll(HMODULE hModule, extensionInfo* extensionInfo)
207+
{
208+
if (extensionInfo->error == NULL) {
209+
parsePhpExtension(hModule, extensionInfo);
210+
if (extensionInfo->error == NULL) {
211+
parseZendExtension(hModule, extensionInfo);
212+
}
213+
}
214+
}
215+
216+
void parseFile(LPCSTR filename, LPCSTR architecture)
217+
{
218+
HMODULE hModule = LoadLibraryEx(filename, NULL, DONT_RESOLVE_DLL_REFERENCES);
219+
if (hModule == NULL) {
220+
printf("Unable to open the DLL.\n");
221+
} else {
222+
extensionInfo extensionInfo;
223+
ZeroMemory(&extensionInfo, sizeof(extensionInfo));
224+
parseDll(hModule, &extensionInfo);
225+
if (extensionInfo.error != NULL) {
226+
printf("%s\n", extensionInfo.error);
227+
} else if (extensionInfo.type == NULL) {
228+
printf("Unrecognized DLL.\n");
229+
} else {
230+
printf(
231+
"php:%s\tarchitecture:%s\tthreadSafe:%s\ttype:%s\tname:%s\tversion:%s\tfilename:%s\n",
232+
extensionInfo.php == NULL ? "" : extensionInfo.php,
233+
architecture,
234+
extensionInfo.threadSafe == NULL ? "" : extensionInfo.threadSafe,
235+
extensionInfo.type,
236+
extensionInfo.name == NULL ? "" : extensionInfo.name,
237+
extensionInfo.version == NULL ? "" : extensionInfo.version,
238+
filename
239+
);
240+
}
241+
FreeLibrary(hModule);
242+
}
243+
}
244+
245+
int main(int argc, LPCSTR argv[])
246+
{
247+
if (argc < 2) {
248+
printf("Syntax: %s <path-to-extension-1> ... <path-to-extension-N>\n", argv[0]);
249+
return 1;
250+
}
251+
LPCSTR architecture;
252+
switch (sizeof(LPVOID)) {
253+
case 4:
254+
architecture = "x86";
255+
break;
256+
case 8:
257+
architecture = "x64";
258+
break;
259+
default:
260+
printf("Unrecognized architecture.\n");
261+
return 1;
262+
break;
263+
}
264+
UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
265+
for (int i = 1; i < argc; i++) {
266+
parseFile(argv[i], architecture);
267+
}
268+
SetErrorMode(errorMode);
269+
return 0;
270+
}

0 commit comments

Comments
 (0)