我从 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. int arg_len , len ; 5. char string [ 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. #ifdef HAVE_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. static int le_gbk ; 37. 38. /* {{{ gbk_functions[] 39. * 40. * Every user visible function must have an entry in gbk_functions[]. 41. */ 42. function_entry gbk_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_entry gbk_module_entry = { 59. #if ZEND_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. #if ZEND_MODULE_API_NO >= 20010901 70. " 0.1 " , /* Replace with version number for your extension */ 71. #endif 72. STANDARD_MODULE_PROPERTIES 73. } ; 74. /* }}} */ 75. 76. #ifdef COMPILE_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. char gbk2uni_file [ 256 ] ; 108. char uni2gbk_file [ 256 ] ; 109. char big52uni_file [ 256 ] ; 110. char uni2big5_file [ 256 ] ; 111. char gbk2big5_file [ 256 ] ; 112. char big52gbk_file [ 256 ] ; 113. 114. //utf file init flag 115. static int initutf = 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 ] == '\ 0 ' ) || ( uni2big5_file [ 0 ] == '\ 0 ' ) 141. || ( gbk2big5_file [ 0 ] == '\ 0 ' ) || ( big52gbk_file [ 0 ] == '\ 0 ' ) 142. || ( gbk2uni_file [ 0 ] == '\ 0 ' ) || ( big52uni_file [ 0 ] == '\ 0 ' )) 143. { 144. return FAILURE ; 145. } 146. 147. if ( gbk2uni_file [ 0 ] != '\ 0 ' ) 148. { 149. if ( LoadOneCodeTable ( CODE_GBK2UNI , gbk2uni_file ) != NULL ) 150. { 151. toplee_cleanup_mmap ( NULL ) ; 152. return FAILURE ; 153. } 154. } 155. 156. if ( uni2gbk_file [ 0 ] != '\ 0 ' ) 157. { 158. if ( LoadOneCodeTable ( CODE_UNI2GBK , uni2gbk_file ) != NULL ) 159. { 160. toplee_cleanup_mmap ( NULL ) ; 161. return FAILURE ; 162. } 163. } 164. 165. if ( big52uni_file [ 0 ] != '\ 0 ' ) 166. { 167. if ( LoadOneCodeTable ( CODE_BIG52UNI , big52uni_file ) != NULL ) 168. { 169. toplee_cleanup_mmap ( NULL ) ; 170. return FAILURE ; 171. } 172. } 173. 174. if ( uni2big5_file [ 0 ] != '\ 0 ' ) 175. { 176. if ( LoadOneCodeTable ( CODE_UNI2BIG5 , uni2big5_file ) != NULL ) 177. { 178. toplee_cleanup_mmap ( NULL ) ; 179. return FAILURE ; 180. } 181. } 182. 183. if ( gbk2big5_file [ 0 ] != '\ 0 ' ) 184. { 185. if ( LoadOneCodeTable ( CODE_GBK2BIG5 , gbk2big5_file ) != NULL ) 186. { 187. toplee_cleanup_mmap ( NULL ) ; 188. return FAILURE ; 189. } 190. } 191. 192. if ( big52gbk_file [ 0 ] != '\ 0 ' ) 193. { 194. if ( LoadOneCodeTable ( CODE_BIG52GBK , big52gbk_file ) != NULL ) 195. { 196. toplee_cleanup_mmap ( NULL ) ; 197. return FAILURE ; 198. } 199. } 200. 201. initutf = 1 ; 202. return SUCCESS ; 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. return SUCCESS ; 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. return SUCCESS ; 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. return SUCCESS ; 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. int argc = ZEND_NUM_ARGS () ; 261. int s_len ; 262. 263. if ( zend_parse_parameters ( argc TSRMLS_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. int argc = ZEND_NUM_ARGS () ; 286. int s_len ; 287. 288. if ( zend_parse_parameters ( argc TSRMLS_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. int argc = ZEND_NUM_ARGS () ; 311. int s_len ; 312. 313. if ( zend_parse_parameters ( argc TSRMLS_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 ; 相关资源:垃圾分类数据集及代码