Linux/FreeBSD下用C语言开发PHP的so扩展模块例解
2008-12-02 10:13
676 查看
我从97年接触互联网的web开发,至今已经过去9年了,从最初的frontpage做html页面到学会ASP+access+IIS开始,就跟
web开发干上了,后来又依次使用了ASP+SQLServer+IIS、JSP+Oracle+Jrun(Resin/Tomcat)、
PHP+Syabse(MySQL)+Apache … 最后我定格到了 PHP+MySQL+Apache+Linux(BSD)
的架构上,也就是大家常说的LAMP架构,这说来有很多理由,网上也有很多人讨论各种架构和开发语言之间的优劣,我就不多说了,简单说一下我喜欢LAMP
的几个主要原因:
1、全开放的免费平台;
2、简单易上手、各种资源丰富;
3、PHP、MySQL、Apache与Linux(BSD)系统底层以及彼此间无缝结合,非常高效;
4、均使用最高效的语言C/C++开发,性能可靠;
5、PHP语言和C的风格基本一致,还吸取了Java和C++的诸多架构优点;
6、这是最关键的一点,那就是PHP可以非常方便的使用C/C++开发扩展模块,给了PHP无限的扩张性!
基于以上原因,我非常喜欢基于PHP语言的架构,其中最关键的一点就是最后一点,以前在Yahoo和mop均推广使用这个平台,在C扩展php方面也有一些经验,在此和大家分享一下,希望可以抛砖引玉。
用C语言编写PHP的扩展模块的方法有几种,根据最后的表现形式有两种,一种是直接编译进php,一种是编译为php的so扩展模块来被php调用,另
外根据编译的方式有两种,一种使用phpize工具(php编译后有的),一种使用ext_skel工具(php自带的),我们使用最多,也是最方便的方
式就是使用ext_skel工具来编写php的so扩展模块,这里也主要介绍这种方式。
我们在php的源码目录里面可以看到有个ext
目录(我这里说的php都是基于Linux平台的php来说的,不包括windows下的),在ext目录下有个工具 ext_skel
,这个工具可以让我们简单的开发出php的扩展模块,它提供了一个通用的php扩展模块开发步骤和模板。下面我们以开发一个在php里面进行
utf8/gbk/gb2312三种编码转换的扩展模块为例子进行说明。在这个模块中,我们要最终提供以下几个函数接口:
(1) string toplee_big52gbk(string s)
将输入字符串从BIG5码转换成GBK
(2) string toplee_gbk2big5(string s)
将输入字符串从GBK转换成BIG5码
(3) string toplee_normalize_name(string s)
将输入字符串作以下处理:全角转半角,strim,大写转小写
(4) string toplee_fan2jian(int code, string s)
将输入的GBK繁体字符串转换成简体
(5) string toplee_decode_utf(string s)
将utf编码的字符串转换成UNICODE
(6) string toplee_decode_utf_gb(string s)
将utf编码的字符串转换成GB
(7) string toplee_decode_utf_big5(string s)
将utf编码的字符串转换成BIG5
(8) string toplee_encode_utf_gb(string s)
将输入的GBKf编码的字符串转换成utf编码
首先,我们进入ext目录下,运行下面命令:
#./ext_skel –extname=toplee
这时,php会自动在ext目录下为我们生成一个目录toplee,里面包含下面几个文件
.cvsignore
CREDITS
EXPERIMENTAL
config.m4
php_toplee.h
tests
toplee.c
toplee.php
其中最有用的就是config.m4和toplee.c文件
接下来我们修改config.m4文件
#vi ./config.m4
找到里面有类似这样几行
1. dnl PHP_ARG_WITH(toplee, for toplee support,
2. dnl Make sure that the comment is aligned:
3. dnl [ --with-toplee Include toplee support])
4.
5. dnl Otherwise use enable:
6.
7. dnl PHP_ARG_ENABLE(toplee, whether to enable toplee support,
8. dnl Make sure that the comment is aligned:
9. dnl [ --enable-toplee Enable toplee support])
上面的几行意思是说告诉php编译的使用使用那种方式加载我们的扩展模块toplee,我们使用–with-toplee的方式,于是我们修改为下面的样子
1. PHP_ARG_WITH(toplee, for toplee support,
2. Make sure that the comment is aligned:
3. [ --with-toplee Include toplee support])
4.
5. dnl Otherwise use enable:
6.
7. dnl PHP_ARG_ENABLE(toplee, whether to enable toplee support,
8. dnl Make sure that the comment is aligned:
9. dnl [ --enable-toplee Enable toplee support])
然后我们要做的关键事情就是编写toplee.c,这个是我们编写模块的主要文件,如果您什么都不修改,其实也完成了一个php扩展模块的编写,里面有类似下面的几行代码
1. PHP_FUNCTION(confirm_toplee_compiled) 2. { 3. char *arg = NULL; 4. intarg_len, len; 5. charstring[256]; 6. 7. if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "s", &arg, &arg_len) == FAILURE){ 8. return; 9. } 10. 11. len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "toplee", arg); 12. RETURN_STRINGL(string, len, 1); 13. }如
果我们在后面完成php的编译时把新的模块编译进去,那么我们就可以在php脚本中调用函数toplee(),它会输出一段字符串
“Congratulations! You have successfully modified ext/toplee/config.m4.
Module toplee is now compiled into PHP.”
下面是我们对toplee.c的修改,让其支持我们预先规划的功能和接口,下面是toplee.c的源代码
1. /* 2. +----------------------------------------------------------------------+ 3. | PHP Version 4 | 4. +----------------------------------------------------------------------+ 5. | Copyright (c) 1997-2002 The PHP Group | 6. +----------------------------------------------------------------------+ 7. | This source file is subject to version 2.02 of the PHP license, | 8. | that is bundled with this package in the file LICENSE, and is | 9. | available at through the world-wide-web at | 10. | http://www.php.net/license/2_02.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: | 16. +----------------------------------------------------------------------+ 17. 18. $Id: header,v 1.10 2002/02/28 08:25:27 sebastian Exp $ 19. */ 20. 21. #ifdefHAVE_CONFIG_H 22. #include "config.h" 23. #endif 24. 25. #include "php.h" 26. #include "php_ini.h" 27. #include "ext/standard/info.h" 28. #include "php_gbk.h" 29. #include "toplee_util.h" 30. 31. /* If you declare any globals in php_gbk.h uncomment this: 32. ZEND_DECLARE_MODULE_GLOBALS(gbk) 33. */ 34. 35. /* True global resources - no need for thread safety here */ 36. staticintle_gbk; 37. 38. /* {{{ gbk_functions[] 39. * 40. * Every user visible function must have an entry in gbk_functions[]. 41. */ 42. function_entrygbk_functions[] = { 43. PHP_FE(toplee_decode_utf, NULL) 44. PHP_FE(toplee_decode_utf_gb, NULL) 45. PHP_FE(toplee_decode_utf_big5, NULL) 46. PHP_FE(toplee_encode_utf_gb, NULL) 47. 48. PHP_FE(toplee_big52gbk, NULL) 49. PHP_FE(toplee_gbk2big5, NULL) 50. PHP_FE(toplee_fan2jian, NULL) 51. PHP_FE(toplee_normalize_name, NULL) 52. {NULL, NULL, NULL} /* Must be the last line in gbk_functions[] */ 53. }; 54. /* }}} */ 55. 56. /* {{{ gbk_module_entry 57. */ 58. zend_module_entrygbk_module_entry = { 59. #ifZEND_MODULE_API_NO >= 20010901 60. STANDARD_MODULE_HEADER, 61. #endif 62. "gbk", 63. gbk_functions, 64. PHP_MINIT(gbk), 65. PHP_MSHUTDOWN(gbk), 66. PHP_RINIT(gbk), /* Replace with NULL if there's nothing to do at request start */ 67. PHP_RSHUTDOWN(gbk), /* Replace with NULL if there's nothing to do at request end */ 68. PHP_MINFO(gbk), 69. #ifZEND_MODULE_API_NO >= 20010901 70. "0.1", /* Replace with version number for your extension */ 71. #endif 72. STANDARD_MODULE_PROPERTIES 73. }; 74. /* }}} */ 75. 76. #ifdefCOMPILE_DL_GBK 77. ZEND_GET_MODULE(gbk) 78. #endif 79. 80. /* {{{ PHP_INI 81. */ 82. /* Remove comments and fill if you need to have entries in php.ini*/ 83. PHP_INI_BEGIN() 84. PHP_INI_ENTRY("gbk2uni", "", PHP_INI_SYSTEM, NULL) 85. PHP_INI_ENTRY("uni2gbk", "", PHP_INI_SYSTEM, NULL) 86. PHP_INI_ENTRY("uni2big5", "", PHP_INI_SYSTEM, NULL) 87. PHP_INI_ENTRY("big52uni", "", PHP_INI_SYSTEM, NULL) 88. PHP_INI_ENTRY("big52gbk", "", PHP_INI_SYSTEM, NULL) 89. PHP_INI_ENTRY("gbk2big5", "", PHP_INI_SYSTEM, NULL) 90. // STD_PHP_INI_ENTRY("gbk.global_value", "42", PHP_INI_ALL, OnUpdateInt, global_value, zend_gbk_globals, gbk_globals) 91. // STD_PHP_INI_ENTRY("gbk.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_gbk_globals, gbk_globals)
92. PHP_INI_END() 93. 94. /* }}} */ 95. 96. /* {{{ php_gbk_init_globals 97. */ 98. /* Uncomment this function if you have INI entries 99. static void php_gbk_init_globals(zend_gbk_globals *gbk_globals) 100. { 101. gbk_globals->global_value = 0; 102. gbk_globals->global_string = NULL; 103. } 104. */ 105. /* }}} */ 106. 107. chargbk2uni_file[256]; 108. charuni2gbk_file[256]; 109. charbig52uni_file[256]; 110. charuni2big5_file[256]; 111. chargbk2big5_file[256]; 112. charbig52gbk_file[256]; 113. 114. //utf file init flag 115. staticintinitutf=0; 116. 117. /* {{{ PHP_MINIT_FUNCTION 118. */ 119. PHP_MINIT_FUNCTION(gbk) 120. { 121. /* If you have INI entries, uncomment these lines 122. ZEND_INIT_MODULE_GLOBALS(gbk, php_gbk_init_globals, NULL);*/ 123. REGISTER_INI_ENTRIES(); 124. memset(gbk2uni_file, 0, sizeof(gbk2uni_file)); 125. memset(uni2gbk_file, 0, sizeof(uni2gbk_file)); 126. memset(big52uni_file, 0, sizeof(big52uni_file)); 127. memset(uni2big5_file, 0, sizeof(uni2big5_file)); 128. memset(gbk2big5_file, 0, sizeof(gbk2big5_file)); 129. memset(big52gbk_file, 0, sizeof(big52gbk_file)); 130. 131. strncpy(gbk2uni_file, INI_STR("gbk2uni"), sizeof(gbk2uni_file)-1); 132. strncpy(uni2gbk_file, INI_STR("uni2gbk"), sizeof(uni2gbk_file)-1); 133. strncpy(big52uni_file, INI_STR("big52uni"), sizeof(big52uni_file)-1); 134. strncpy(uni2big5_file, INI_STR("uni2big5"), sizeof(uni2big5_file)-1); 135. strncpy(gbk2big5_file, INI_STR("gbk2big5"), sizeof(uni2big5_file)-1); 136. strncpy(big52gbk_file, INI_STR("big52gbk"), sizeof(uni2big5_file)-1); 137. 138. //InitMMResource(); 139. InitResource(); 140. if((uni2gbk_file[0] == '') || (uni2big5_file[0] == '') 141. || (gbk2big5_file[0] == '') || (big52gbk_file[0] == '') 142. || (gbk2uni_file[0] == '') || (big52uni_file[0] == '')) 143. { 144. returnFAILURE; 145. } 146. 147. if(gbk2uni_file[0] != '') 148. { 149. if(LoadOneCodeTable(CODE_GBK2UNI, gbk2uni_file) != NULL) 150. { 151. toplee_cleanup_mmap(NULL); 152. returnFAILURE; 153. } 154. } 155. 156. if(uni2gbk_file[0] != '') 157. { 158. if(LoadOneCodeTable(CODE_UNI2GBK, uni2gbk_file) != NULL) 159. { 160. toplee_cleanup_mmap(NULL); 161. returnFAILURE; 162. } 163. } 164. 165. if(big52uni_file[0] != '') 166. { 167. if(LoadOneCodeTable(CODE_BIG52UNI, big52uni_file) != NULL) 168. { 169. toplee_cleanup_mmap(NULL); 170. returnFAILURE; 171. } 172. } 173. 174. if(uni2big5_file[0] != '') 175. { 176. if(LoadOneCodeTable(CODE_UNI2BIG5, uni2big5_file) != NULL) 177. { 178. toplee_cleanup_mmap(NULL); 179. returnFAILURE; 180. } 181. } 182. 183. if(gbk2big5_file[0] != '') 184. { 185. if(LoadOneCodeTable(CODE_GBK2BIG5, gbk2big5_file) != NULL) 186. { 187. toplee_cleanup_mmap(NULL); 188. returnFAILURE; 189. } 190. } 191. 192. if(big52gbk_file[0] != '') 193. { 194. if(LoadOneCodeTable(CODE_BIG52GBK, big52gbk_file) != NULL) 195. { 196. toplee_cleanup_mmap(NULL); 197. returnFAILURE; 198. } 199. } 200. 201. initutf = 1; 202. returnSUCCESS; 203. } 204. /* }}} */ 205. 206. /* {{{ PHP_MSHUTDOWN_FUNCTION 207. */ 208. PHP_MSHUTDOWN_FUNCTION(gbk) 209. { 210. /* uncomment this line if you have INI entries*/ 211. UNREGISTER_INI_ENTRIES(); 212. 213. toplee_cleanup_mmap(NULL); 214. returnSUCCESS; 215. } 216. /* }}} */ 217. 218. /* Remove if there's nothing to do at request start */ 219. /* {{{ PHP_RINIT_FUNCTION 220. */ 221. PHP_RINIT_FUNCTION(gbk) 222. { 223. returnSUCCESS; 224. } 225. /* }}} */ 226. 227. /* Remove if there's nothing to do at request end */ 228. /* {{{ PHP_RSHUTDOWN_FUNCTION 229. */ 230. PHP_RSHUTDOWN_FUNCTION(gbk) 231. { 232. returnSUCCESS; 233. } 234. /* }}} */ 235. 236. /* {{{ PHP_MINFO_FUNCTION 237. */ 238. PHP_MINFO_FUNCTION(gbk) 239. { 240. php_info_print_table_start(); 241. php_info_print_table_header(2, "gbk support", "enabled"); 242. php_info_print_table_end(); 243. 244. /* Remove comments if you have entries in php.ini*/ 245. DISPLAY_INI_ENTRIES(); 246. 247. } 248. /* }}} */ 249. 250. 251. /* Remove the following function when you have succesfully modified config.m4 252. so that your module can be compiled into PHP, it exists only for testing 253. purposes. */ 254. 255. /* {{{ proto toplee_decode_utf(string s) 256. */ 257. PHP_FUNCTION(toplee_decode_utf) 258. { 259. char *s = NULL, *t=NULL; 260. intargc = ZEND_NUM_ARGS(); 261. ints_len; 262. 263. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 264. return; 265. 266. if(!initutf) 267. RETURN_FALSE 268. t = strdup(s); 269. if(t==NULL) 270. RETURN_FALSE 271. 272. 273. DecodePureUTF(t, KEEP_UNICODE); 274. RETVAL_STRING(t,1); 275. free(t); 276. return; 277. } 278. /* }}} */ 279. 280. /* {{{ proto toplee_decode_utf_gb(string s) 281. */ 282. PHP_FUNCTION(toplee_decode_utf_gb) 283. { 284. char *s = NULL, *t=NULL; 285. intargc = ZEND_NUM_ARGS(); 286. ints_len; 287. 288. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 289. return; 290. 291. if(!initutf) 292. RETURN_FALSE 293. t = strdup(s); 294. if(t==NULL) 295. RETURN_FALSE 296. 297. DecodePureUTF(t, DECODE_UNICODE); 298. RETVAL_STRING(t,1); 299. free(t); 300. return; 301. 302. } 303. /* }}} */ 304. 305. /* {{{ proto toplee_decode_utf_big5(string s) 306. */ 307. PHP_FUNCTION(toplee_decode_utf_big5) 308. { 309. char *s = NULL, *t=NULL; 310. intargc = ZEND_NUM_ARGS(); 311. ints_len; 312. 313. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 314. return; 315. 316. if(!initutf) 317. RETURN_FALSE 318. t = strdup(s); 319. if(t==NULL) 320. RETURN_FALSE 321. 322. 323. DecodePureUTF(t, DECODE_UNICODE | DECODE_BIG5); 324. RETVAL_STRING(t,1); 325. free(t); 326. return; 327. } 328. /* }}} */ 329. intEncodePureUTF(unsignedchar* strSrc, 330. unsignedchar* strDst, intnDstLen, intnFlag) 331. { 332. intnRet; 333. intpos; 334. unsignedshortc; 335. unsignedshort* uBuf; 336. intnSize; 337. intnLen; 338. intnReturn; 339. 340. nLen=strlen((constchar*)strSrc); 341. if(nDstLen < nLen*2+1) 342. return0; 343. 344. nSize=nLen+1; 345. uBuf=(unsignedshort*)emalloc(sizeof(unsignedshort)*nSize); 346. 347. nRet=MultiByteToWideChar(936, 0, (constchar*)strSrc, strlen((constchar*)strSrc), 348. uBuf, nSize); 349. 350. nReturn=0; 351. pos=nRet; 352. while(pos>0) 353. { 354. c = *uBuf; 355. if(c < 0x80){ 356. strDst[nReturn++] = (char)c; 357. }elseif(c < 0x800){ 358. strDst[nReturn++] = (0xc0 | (c >> 6)); 359. strDst[nReturn++] = (0x80 | (c & 0x3f)); 360. }elseif(c < 0x10000){ 361. strDst[nReturn++] = (0xe0 | (c >> 12)); 362. strDst[nReturn++] = (0x80 | ((c >> 6) & 0x3f)); 363. strDst[nReturn++] = (0x80 | (c & 0x3f)); 364. }elseif(c < 0x200000){ 365. strDst[nReturn++] = (0xf0 | (c >> 18)); 366. strDst[nReturn++] = (0x80 | ((c >> 12) & 0x3f)); 367. strDst[nReturn++] = (0x80 | ((c >> 6) & 0x3f)); 368. strDst[nReturn++] = (0x80 | (c & 0x3f)); 369. } 370. pos--; 371. uBuf++; 372. } 373. strDst[nReturn]=''; 374. 375. returnnReturn; 376. } 377. 378. /* {{{ proto toplee_encode_utf_gb(string s) 379. */ 380. PHP_FUNCTION(toplee_encode_utf_gb) 381. { 382. char *s = NULL; 383. intargc = ZEND_NUM_ARGS(); 384. ints_len; 385. char* sRet; 386. 387. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 388. return; 389. 390. if(!initutf) 391. RETURN_FALSE 392. sRet=emalloc(strlen(s)*2+1); 393. 394. EncodePureUTF(s, sRet, strlen(s)*2+1, 0); 395. RETVAL_STRING(sRet,1); 396. return; 397. } 398. /* }}} */ 399. 400. 401. /* {{{ proto toplee_big52gbk(string s) 402. */ 403. PHP_FUNCTION(toplee_big52gbk) 404. { 405. char *s = NULL; 406. intargc = ZEND_NUM_ARGS(); 407. ints_len; 408. char* sRet = NULL; 409. 410. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 411. return; 412. 413. if(!initutf) 414. RETURN_FALSE 415. 416. sRet=estrdup(s); 417. if(NULL == sRet) 418. RETURN_FALSE 419. 420. BIG52GBK(sRet, strlen(sRet)); 421. RETVAL_STRING(sRet,1); 422. return; 423. } 424. /* }}} */ 425. 426. /* {{{ proto toplee_gbk2big5(string s) 427. */ 428. PHP_FUNCTION(toplee_gbk2big5) 429. { 430. char *s = NULL; 431. intargc = ZEND_NUM_ARGS(); 432. ints_len; 433. char* sRet = NULL; 434. 435. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 436. return; 437. 438. if(!initutf) 439. RETURN_FALSE 440. 441. sRet=estrdup(s); 442. if(NULL == sRet) 443. RETURN_FALSE 444. 445. GBK2BIG5(sRet, strlen(sRet)); 446. RETVAL_STRING(sRet,1); 447. return; 448. } 449. /* }}} */ 450. 451. /* {{{ proto toplee_normalize_name(string s) 452. */ 453. PHP_FUNCTION(toplee_normalize_name) 454. { 455. char *s = NULL; 456. intargc = ZEND_NUM_ARGS(); 457. ints_len; 458. char* sRet = NULL; 459. 460. if(zend_parse_parameters(argcTSRMLS_CC, "s", &s, &s_len) == FAILURE) 461. return; 462. 463. if(!initutf) 464. RETURN_FALSE 465. 466. NormalizeName(s); 467. 468. RETURN_STRING(s, 1); 469. 470. 471. return; 472. } 473. /* }}} */ 474. 475. /* {{{ proto toplee_fan2jian(int code, string s) 476. */ 477. PHP_FUNCTION(toplee_fan2jian) 478. { 479. char *s = NULL; 480. intargc = ZEND_NUM_ARGS(); 481. ints_len, code; 482. char* sRet = NULL; 483. char *pSource; 484. char *pDest1=NULL, *pDest2=NULL; 485. intnSourceLen, nDestLen; 486. 487. if(zend_parse_parameters(argcTSRMLS_CC, "ls", &code, &s, &s_len) == FAILURE) 488. return; 489. 490. if(!initutf) 491. RETURN_FALSE 492. 493. pSource = s; 494. nSourceLen = s_len; 495. pDest1 = malloc(nSourceLen * 2); 496. pDest2 = malloc(nSourceLen+1); 497. if(NULL == pDest1 || NULL == pDest2) 498. goto_f2j_err; 499. 500. memset(pDest1, 0, nSourceLen * 2); 501. memset(pDest2, 0, nSourceLen + 1); 502. nDestLen = MultiByteToWideChar(code, 0, pSource, nSourceLen, (short *)pDest1, nSourceLen * 2); 503. 504. if(0 >= nDestLen) 505. goto_f2j_err; 506. 507. nDestLen = WideCharToMultiByte(code, 0, (short *)pDest1, nDestLen, pDest2, nSourceLen, NULL, NULL); 508. if(0 >= nDestLen) 509. goto_f2j_err; 510. 511. RETVAL_STRING(pDest2, 1); 512. if(pDest1 != NULL) 513. free(pDest1); 514. if(pDest2 != NULL) 515. free(pDest2); 516. return; 517. 518. _f2j_err: 519. if(pDest1 != NULL) 520. free(pDest1); 521. if(pDest2 != NULL) 522. free(pDest2); 523. RETURN_FALSE; 524. } 525. /* }}} */ 526. 527. /* 528. * Local variables: 529. * tab-width: 4 530. * c-basic-offset: 4 531. * End: 532. * vim600: noet sw=4 ts=4 fdm=marker 533. * vim<600: noet sw=4 ts=4 534. */
事实上我们在这个文件里面定义了所有我们要实现的接口,剩下的部分就是我们再编写几个具体实现的C语言代码,有关C具体实现的技术细节就不在此讨论,有
个关键的大家注意就是,您可以在ext/toplee目录下加入您所有用于实现您在toplee.c里面定义的接口的C源文件和头文件,让
toplee.c在编译的时候可以调用到,这些都是标准的C语言语法。Michael就不另说,下我把我们实现的几个代码都贴出来:
相关文章推荐
- Linux/FreeBSD下用C语言开发PHP的so扩展模块例解
- Linux/FreeBSD下用C语言开发PHP的so扩展模块例解
- Linux/FreeBSD下用C语言开发PHP的so扩展模块例解
- Linux-FreeBSD下用C语言开发PHP的so扩展模块例解
- Linux/Ubuntu下C语言开发PHP的.so扩展模块过程
- Linux/Ubuntu下C语言开发PHP的.so扩展模块过程
- Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
- LINUX下PHP编译添加相应的动态扩展模块so(不需要重新编译PHP,以openssl.so为例)
- PHP扩展开发之动态加载so模块与静态重编译PHP(下)
- LINUX下PHP扩展模块的开发和测试(原创)
- Linux下php扩展模块开发
- Linux下php扩展模块开发
- LINUX下PHP编译添加相应的动态扩展模块so(不需要重新编译PHP,以openssl.so为例)
- LINUX下PHP编译添加相应的动态扩展模块so(不需要重新编译PHP,以openssl.so为例)
- LINUX下PHP编译添加相应的动态扩展模块so(不需要重新编译PHP,以openssl.so为例)
- Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
- PHP扩展开发之动态加载so模块与静态重编译PHP(上)
- Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
- 用C语言写PHP扩展 linux
- linux系统扩展php的zip模块