xref: /PHP-7.4/ext/com_dotnet/com_extension.c (revision dc108fea)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
16    +----------------------------------------------------------------------+
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <intsafe.h>
24 
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "php_com_dotnet.h"
29 #include "php_com_dotnet_internal.h"
30 #include "Zend/zend_exceptions.h"
31 #include "Zend/zend_interfaces.h"
32 
33 ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
34 static PHP_GINIT_FUNCTION(com_dotnet);
35 
36 zend_class_entry
37 	*php_com_variant_class_entry,
38    	*php_com_exception_class_entry,
39 	*php_com_saproxy_class_entry;
40 
41 /* {{{ arginfo */
42 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_set, 0, 0, 2)
43 	ZEND_ARG_INFO(0, variant)
44 	ZEND_ARG_INFO(0, value)
45 ZEND_END_ARG_INFO()
46 
47 ZEND_BEGIN_ARG_INFO_EX(arginfo_left_right, 0, 0, 2)
48 	ZEND_ARG_INFO(0, left)
49 	ZEND_ARG_INFO(0, right)
50 ZEND_END_ARG_INFO()
51 
52 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_abs, 0, 0, 1)
53 	ZEND_ARG_INFO(0, left)
54 ZEND_END_ARG_INFO()
55 
56 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_fix, 0, 0, 1)
57 	ZEND_ARG_INFO(0, left)
58 ZEND_END_ARG_INFO()
59 
60 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_int, 0, 0, 1)
61 	ZEND_ARG_INFO(0, left)
62 ZEND_END_ARG_INFO()
63 
64 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_neg, 0, 0, 1)
65 	ZEND_ARG_INFO(0, left)
66 ZEND_END_ARG_INFO()
67 
68 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_not, 0, 0, 1)
69 	ZEND_ARG_INFO(0, left)
70 ZEND_END_ARG_INFO()
71 
72 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_round, 0, 0, 2)
73 	ZEND_ARG_INFO(0, left)
74 	ZEND_ARG_INFO(0, decimals)
75 ZEND_END_ARG_INFO()
76 
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_cmp, 0, 0, 2)
78 	ZEND_ARG_INFO(0, left)
79 	ZEND_ARG_INFO(0, right)
80 	ZEND_ARG_INFO(0, lcid)
81 	ZEND_ARG_INFO(0, flags)
82 ZEND_END_ARG_INFO()
83 
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_date_to_timestamp, 0, 0, 1)
85 	ZEND_ARG_INFO(0, variant)
86 ZEND_END_ARG_INFO()
87 
88 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_date_from_timestamp, 0, 0, 1)
89 	ZEND_ARG_INFO(0, timestamp)
90 ZEND_END_ARG_INFO()
91 
92 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_get_type, 0, 0, 1)
93 	ZEND_ARG_INFO(0, variant)
94 ZEND_END_ARG_INFO()
95 
96 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_set_type, 0, 0, 2)
97 	ZEND_ARG_INFO(0, variant)
98 	ZEND_ARG_INFO(0, type)
99 ZEND_END_ARG_INFO()
100 
101 ZEND_BEGIN_ARG_INFO_EX(arginfo_variant_cast, 0, 0, 2)
102 	ZEND_ARG_INFO(0, variant)
103 	ZEND_ARG_INFO(0, type)
104 ZEND_END_ARG_INFO()
105 
106 ZEND_BEGIN_ARG_INFO_EX(arginfo_com_get_active_object, 0, 0, 1)
107 	ZEND_ARG_INFO(0, progid)
108 	ZEND_ARG_INFO(0, code_page)
109 ZEND_END_ARG_INFO()
110 
111 ZEND_BEGIN_ARG_INFO(arginfo_com_create_guid, 0)
112 ZEND_END_ARG_INFO()
113 
114 ZEND_BEGIN_ARG_INFO_EX(arginfo_com_event_sink, 0, 0, 2)
115 	ZEND_ARG_INFO(0, comobject)
116 	ZEND_ARG_INFO(0, sinkobject)
117 	ZEND_ARG_INFO(0, sinkinterface)
118 ZEND_END_ARG_INFO()
119 
120 ZEND_BEGIN_ARG_INFO_EX(arginfo_com_print_typeinfo, 0, 0, 1)
121 	ZEND_ARG_INFO(0, comobject)
122 	ZEND_ARG_INFO(0, dispinterface)
123 	ZEND_ARG_INFO(0, wantsink)
124 ZEND_END_ARG_INFO()
125 
126 ZEND_BEGIN_ARG_INFO_EX(arginfo_com_message_pump, 0, 0, 0)
127 	ZEND_ARG_INFO(0, timeoutms)
128 ZEND_END_ARG_INFO()
129 
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_com_load_typelib, 0, 0, 1)
131 	ZEND_ARG_INFO(0, typelib_name)
132 	ZEND_ARG_INFO(0, case_insensitive)
133 ZEND_END_ARG_INFO()
134 /* }}} */
135 
136 static const zend_function_entry com_dotnet_functions[] = {
137 	PHP_FE(variant_set, arginfo_variant_set)
138 	PHP_FE(variant_add, arginfo_left_right)
139 	PHP_FE(variant_cat, arginfo_left_right)
140 	PHP_FE(variant_sub, arginfo_left_right)
141 	PHP_FE(variant_mul, arginfo_left_right)
142 	PHP_FE(variant_and, arginfo_left_right)
143 	PHP_FE(variant_div, arginfo_left_right)
144 	PHP_FE(variant_eqv, arginfo_left_right)
145 	PHP_FE(variant_idiv, arginfo_left_right)
146 	PHP_FE(variant_imp, arginfo_left_right)
147 	PHP_FE(variant_mod, arginfo_left_right)
148 	PHP_FE(variant_or, arginfo_left_right)
149 	PHP_FE(variant_pow, arginfo_left_right)
150 	PHP_FE(variant_xor, arginfo_left_right)
151 	PHP_FE(variant_abs, arginfo_variant_abs)
152 	PHP_FE(variant_fix, arginfo_variant_fix)
153 	PHP_FE(variant_int, arginfo_variant_int)
154 	PHP_FE(variant_neg, arginfo_variant_neg)
155 	PHP_FE(variant_not, arginfo_variant_not)
156 	PHP_FE(variant_round, arginfo_variant_round)
157 	PHP_FE(variant_cmp, arginfo_variant_cmp)
158 	PHP_FE(variant_date_to_timestamp, arginfo_variant_date_to_timestamp)
159 	PHP_FE(variant_date_from_timestamp, arginfo_variant_date_from_timestamp)
160 	PHP_FE(variant_get_type, arginfo_variant_get_type)
161 	PHP_FE(variant_set_type, arginfo_variant_set_type)
162 	PHP_FE(variant_cast, arginfo_variant_cast)
163 	/* com_com.c */
164 	PHP_FE(com_create_guid, arginfo_com_create_guid)
165 	PHP_FE(com_event_sink, arginfo_com_event_sink)
166 	PHP_FE(com_print_typeinfo, arginfo_com_print_typeinfo)
167 	PHP_FE(com_message_pump, arginfo_com_message_pump)
168 	PHP_FE(com_load_typelib, arginfo_com_load_typelib)
169 	PHP_FE(com_get_active_object, arginfo_com_get_active_object)
170 	PHP_FE_END
171 };
172 
173 /* {{{ com_dotnet_module_entry
174  */
175 zend_module_entry com_dotnet_module_entry = {
176 	STANDARD_MODULE_HEADER,
177 	"com_dotnet",
178 	com_dotnet_functions,
179 	PHP_MINIT(com_dotnet),
180 	PHP_MSHUTDOWN(com_dotnet),
181 	PHP_RINIT(com_dotnet),
182 	PHP_RSHUTDOWN(com_dotnet),
183 	PHP_MINFO(com_dotnet),
184 	PHP_COM_DOTNET_VERSION,
185 	PHP_MODULE_GLOBALS(com_dotnet),
186 	PHP_GINIT(com_dotnet),
187 	NULL,
188 	NULL,
189 	STANDARD_MODULE_PROPERTIES_EX
190 };
191 /* }}} */
192 
193 #ifdef COMPILE_DL_COM_DOTNET
194 #ifdef ZTS
195 ZEND_TSRMLS_CACHE_DEFINE()
196 #endif
ZEND_GET_MODULE(com_dotnet)197 ZEND_GET_MODULE(com_dotnet)
198 #endif
199 
200 /* {{{ PHP_INI
201  */
202 
203 /* com.typelib_file is the path to a file containing a
204  * list of typelibraries to register *persistently*.
205  * lines starting with ; are comments
206  * append #cis to end of typelib name to cause its constants
207  * to be loaded case insensitively */
208 static PHP_INI_MH(OnTypeLibFileUpdate)
209 {
210 	FILE *typelib_file;
211 	char *typelib_name_buffer;
212 	char *strtok_buf = NULL;
213 	int cached;
214 
215 	if (NULL == new_value || !new_value->val[0] || (typelib_file = VCWD_FOPEN(new_value->val, "r"))==NULL) {
216 		return FAILURE;
217 	}
218 
219 	typelib_name_buffer = (char *) emalloc(sizeof(char)*1024);
220 
221 	while (fgets(typelib_name_buffer, 1024, typelib_file)) {
222 		ITypeLib *pTL;
223 		char *typelib_name;
224 		char *modifier, *ptr;
225 		int mode = CONST_CS | CONST_PERSISTENT;	/* CONST_PERSISTENT is ok here */
226 
227 		if (typelib_name_buffer[0]==';') {
228 			continue;
229 		}
230 		typelib_name = php_strtok_r(typelib_name_buffer, "\r\n", &strtok_buf); /* get rid of newlines */
231 		if (typelib_name == NULL) {
232 			continue;
233 		}
234 		typelib_name = php_strtok_r(typelib_name, "#", &strtok_buf);
235 		modifier = php_strtok_r(NULL, "#", &strtok_buf);
236 		if (modifier != NULL) {
237 			if (!strcmp(modifier, "cis") || !strcmp(modifier, "case_insensitive")) {
238 				php_error_docref("com.configuration", E_DEPRECATED, "Declaration of case-insensitive constants is deprecated");
239 				mode &= ~CONST_CS;
240 			}
241 		}
242 
243 		/* Remove leading/training white spaces on search_string */
244 		while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */
245 			typelib_name ++;
246 		}
247 		ptr = typelib_name + strlen(typelib_name) - 1;
248 		while ((ptr != typelib_name) && isspace(*ptr)) {
249 			*ptr = '\0';
250 			ptr--;
251 		}
252 
253 		if ((pTL = php_com_load_typelib_via_cache(typelib_name, COMG(code_page), &cached)) != NULL) {
254 			php_com_import_typelib(pTL, mode, COMG(code_page));
255 			ITypeLib_Release(pTL);
256 		}
257 	}
258 
259 	efree(typelib_name_buffer);
260 	fclose(typelib_file);
261 
262 	return SUCCESS;
263 }
264 
ZEND_INI_MH(OnAutoregisterCasesensitive)265 static ZEND_INI_MH(OnAutoregisterCasesensitive)
266 {
267 	if (!zend_ini_parse_bool(new_value)) {
268 		php_error_docref("com.configuration", E_DEPRECATED, "Declaration of case-insensitive constants is deprecated");
269 	}
270 	return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
271 }
272 
273 PHP_INI_BEGIN()
274     STD_PHP_INI_ENTRY("com.allow_dcom",				"0", PHP_INI_SYSTEM, OnUpdateBool, allow_dcom, zend_com_dotnet_globals, com_dotnet_globals)
275     STD_PHP_INI_ENTRY("com.autoregister_verbose",	"0", PHP_INI_ALL, OnUpdateBool, autoreg_verbose, zend_com_dotnet_globals, com_dotnet_globals)
276     STD_PHP_INI_ENTRY("com.autoregister_typelib",	"0", PHP_INI_ALL, OnUpdateBool, autoreg_on, zend_com_dotnet_globals, com_dotnet_globals)
277     STD_PHP_INI_ENTRY("com.autoregister_casesensitive",	"1", PHP_INI_ALL, OnAutoregisterCasesensitive, autoreg_case_sensitive, zend_com_dotnet_globals, com_dotnet_globals)
278 	STD_PHP_INI_ENTRY("com.code_page", "", PHP_INI_ALL, OnUpdateLong, code_page, zend_com_dotnet_globals, com_dotnet_globals)
279 	PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypeLibFileUpdate)
PHP_INI_END()280 PHP_INI_END()
281 /* }}} */
282 
283 /* {{{ PHP_GINIT_FUNCTION
284  */
285 static PHP_GINIT_FUNCTION(com_dotnet)
286 {
287 #if defined(COMPILE_DL_COM_DOTNET) && defined(ZTS)
288 	ZEND_TSRMLS_CACHE_UPDATE();
289 #endif
290 	memset(com_dotnet_globals, 0, sizeof(*com_dotnet_globals));
291 	com_dotnet_globals->code_page = CP_ACP;
292 }
293 /* }}} */
294 
295 /* {{{ PHP_MINIT_FUNCTION
296  */
PHP_MINIT_FUNCTION(com_dotnet)297 PHP_MINIT_FUNCTION(com_dotnet)
298 {
299 	zend_class_entry ce, *tmp;
300 
301 	php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
302 	php_com_persist_minit(INIT_FUNC_ARGS_PASSTHRU);
303 
304 	INIT_CLASS_ENTRY(ce, "com_exception", NULL);
305 	php_com_exception_class_entry = zend_register_internal_class_ex(&ce, zend_ce_exception);
306 	php_com_exception_class_entry->ce_flags |= ZEND_ACC_FINAL;
307 /*	php_com_exception_class_entry->constructor->common.fn_flags |= ZEND_ACC_PROTECTED; */
308 
309 	INIT_CLASS_ENTRY(ce, "com_safearray_proxy", NULL);
310 	php_com_saproxy_class_entry = zend_register_internal_class(&ce);
311 	php_com_saproxy_class_entry->ce_flags |= ZEND_ACC_FINAL;
312 /*	php_com_saproxy_class_entry->constructor->common.fn_flags |= ZEND_ACC_PROTECTED; */
313 	php_com_saproxy_class_entry->get_iterator = php_com_saproxy_iter_get;
314 
315 	INIT_CLASS_ENTRY(ce, "variant", NULL);
316 	ce.create_object = php_com_object_new;
317 	php_com_variant_class_entry = zend_register_internal_class(&ce);
318 	php_com_variant_class_entry->get_iterator = php_com_iter_get;
319 	php_com_variant_class_entry->serialize = zend_class_serialize_deny;
320 	php_com_variant_class_entry->unserialize = zend_class_unserialize_deny;
321 
322 	INIT_CLASS_ENTRY(ce, "com", NULL);
323 	ce.create_object = php_com_object_new;
324 	tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
325 	tmp->get_iterator = php_com_iter_get;
326 	tmp->serialize = zend_class_serialize_deny;
327 	tmp->unserialize = zend_class_unserialize_deny;
328 
329 #if HAVE_MSCOREE_H
330 	INIT_CLASS_ENTRY(ce, "dotnet", NULL);
331 	ce.create_object = php_com_object_new;
332 	tmp = zend_register_internal_class_ex(&ce, php_com_variant_class_entry);
333 	tmp->get_iterator = php_com_iter_get;
334 	tmp->serialize = zend_class_serialize_deny;
335 	tmp->unserialize = zend_class_unserialize_deny;
336 #endif
337 
338 	REGISTER_INI_ENTRIES();
339 
340 #define COM_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS|CONST_PERSISTENT)
341 
342 #if SIZEOF_ZEND_LONG == 8
343 # define COM_ERR_CONST(x) { \
344 	zend_long __tmp; \
345 	ULongToIntPtr(x, &__tmp); \
346 	REGISTER_LONG_CONSTANT(#x, __tmp, CONST_CS|CONST_PERSISTENT); \
347 }
348 #else
349 # define COM_ERR_CONST COM_CONST
350 #endif
351 
352 	COM_CONST(CLSCTX_INPROC_SERVER);
353 	COM_CONST(CLSCTX_INPROC_HANDLER);
354 	COM_CONST(CLSCTX_LOCAL_SERVER);
355 	COM_CONST(CLSCTX_REMOTE_SERVER);
356 	COM_CONST(CLSCTX_SERVER);
357 	COM_CONST(CLSCTX_ALL);
358 
359 #if 0
360 	COM_CONST(DISPATCH_METHOD);
361 	COM_CONST(DISPATCH_PROPERTYGET);
362 	COM_CONST(DISPATCH_PROPERTYPUT);
363 #endif
364 
365 	COM_CONST(VT_NULL);
366 	COM_CONST(VT_EMPTY);
367 	COM_CONST(VT_UI1);
368 	COM_CONST(VT_I1);
369 	COM_CONST(VT_UI2);
370 	COM_CONST(VT_I2);
371 	COM_CONST(VT_UI4);
372 	COM_CONST(VT_I4);
373 	COM_CONST(VT_R4);
374 	COM_CONST(VT_R8);
375 	COM_CONST(VT_BOOL);
376 	COM_CONST(VT_ERROR);
377 	COM_CONST(VT_CY);
378 	COM_CONST(VT_DATE);
379 	COM_CONST(VT_BSTR);
380 	COM_CONST(VT_DECIMAL);
381 	COM_CONST(VT_UNKNOWN);
382 	COM_CONST(VT_DISPATCH);
383 	COM_CONST(VT_VARIANT);
384 	COM_CONST(VT_INT);
385 	COM_CONST(VT_UINT);
386 	COM_CONST(VT_ARRAY);
387 	COM_CONST(VT_BYREF);
388 
389 	COM_CONST(CP_ACP);
390 	COM_CONST(CP_MACCP);
391 	COM_CONST(CP_OEMCP);
392 	COM_CONST(CP_UTF7);
393 	COM_CONST(CP_UTF8);
394 	COM_CONST(CP_SYMBOL);
395 	COM_CONST(CP_THREAD_ACP);
396 
397 	COM_CONST(VARCMP_LT);
398 	COM_CONST(VARCMP_EQ);
399 	COM_CONST(VARCMP_GT);
400 	COM_CONST(VARCMP_NULL);
401 
402 	COM_CONST(NORM_IGNORECASE);
403 	COM_CONST(NORM_IGNORENONSPACE);
404 	COM_CONST(NORM_IGNORESYMBOLS);
405 	COM_CONST(NORM_IGNOREWIDTH);
406 	COM_CONST(NORM_IGNOREKANATYPE);
407 #ifdef NORM_IGNOREKASHIDA
408 	COM_CONST(NORM_IGNOREKASHIDA);
409 #endif
410 	COM_ERR_CONST(DISP_E_DIVBYZERO);
411 	COM_ERR_CONST(DISP_E_OVERFLOW);
412 	COM_ERR_CONST(DISP_E_BADINDEX);
413 	COM_ERR_CONST(MK_E_UNAVAILABLE);
414 
415 #if SIZEOF_ZEND_LONG == 8
416 	COM_CONST(VT_UI8);
417 	COM_CONST(VT_I8);
418 #endif
419 
420 	PHP_MINIT(com_typeinfo)(INIT_FUNC_ARGS_PASSTHRU);
421 
422 	return SUCCESS;
423 }
424 /* }}} */
425 
426 /* {{{ PHP_MSHUTDOWN_FUNCTION
427  */
PHP_MSHUTDOWN_FUNCTION(com_dotnet)428 PHP_MSHUTDOWN_FUNCTION(com_dotnet)
429 {
430 	UNREGISTER_INI_ENTRIES();
431 #if HAVE_MSCOREE_H
432 	if (COMG(dotnet_runtime_stuff)) {
433 		php_com_dotnet_mshutdown();
434 	}
435 #endif
436 
437 	PHP_MSHUTDOWN(com_typeinfo)(INIT_FUNC_ARGS_PASSTHRU);
438 
439 	return SUCCESS;
440 }
441 /* }}} */
442 
443 /* {{{ PHP_RINIT_FUNCTION
444  */
PHP_RINIT_FUNCTION(com_dotnet)445 PHP_RINIT_FUNCTION(com_dotnet)
446 {
447 	COMG(rshutdown_started) = 0;
448 	return SUCCESS;
449 }
450 /* }}} */
451 
452 /* {{{ PHP_RSHUTDOWN_FUNCTION
453  */
PHP_RSHUTDOWN_FUNCTION(com_dotnet)454 PHP_RSHUTDOWN_FUNCTION(com_dotnet)
455 {
456 #if HAVE_MSCOREE_H
457 	if (COMG(dotnet_runtime_stuff)) {
458 		php_com_dotnet_rshutdown();
459 	}
460 #endif
461 	COMG(rshutdown_started) = 1;
462 	return SUCCESS;
463 }
464 /* }}} */
465 
466 /* {{{ PHP_MINFO_FUNCTION
467  */
PHP_MINFO_FUNCTION(com_dotnet)468 PHP_MINFO_FUNCTION(com_dotnet)
469 {
470 	php_info_print_table_start();
471 
472 	php_info_print_table_header(2, "COM support", "enabled");
473 	php_info_print_table_header(2, "DCOM support", COMG(allow_dcom) ? "enabled" : "disabled");
474 
475 #if HAVE_MSCOREE_H
476 	php_info_print_table_header(2, ".Net support", "enabled");
477 #else
478 	php_info_print_table_header(2, ".Net support", "not present in this build");
479 #endif
480 
481 	php_info_print_table_end();
482 
483 	DISPLAY_INI_ENTRIES();
484 }
485 /* }}} */
486