设为首页 收藏本站
查看: 490|回复: 0

[经验分享] 用 SWIG 构建 PHP 扩展

[复制链接]

尚未签到

发表于 2017-3-23 12:00:46 | 显示全部楼层 |阅读模式
  作者:Martin Streicher, 软件开发人员, Pixel, Byte, and Comma
尽管编写一个 PHP 扩展并不是很困难,而 SWIG 的确进一步简化了这项任务,这主要是因为它自动化了结合 PHP 与 C 或 C++ 所需的工作。若给定对一个函数的描绘 — 函数的名称及其形参 — SWIG 就会生成一个包装程序来将 PHP 与低层代码连接起来。
  SWIG 需要一些前提条件。SWIG 的一些最新版本需要 PHP 的版本是 V5。此外,还需要有一个 C/C++ 编译器,比如 GNU Compiler Collection (GCC),以及 PHP Module Development Kit (MDK)。特别是您还要有与 PHP 安装相关的头文件。如果您使用的是 Ubuntu Linux ® 或一个 Debian 的变体并且已经从一个包存储库安装了 PHP V5,那么一般而言您就可以使用 Advanced Packaging Tool (APT) 添加 MDK 了。例如,在 Ubuntu 内核 9.10 上,键入 apt-get install sudo apt-get install --install-recommends --yes php5-dev。
  截止到 2009 年底,SWIG 的最新版本是 V1.3.40(参见 参考资料)。下载 tarball (一个由 gzip 压缩了的 TAR 文件),将它解压缩,然后针对您的系统配置这些代码,构建并安装这个软件。(要想找到所有的配置选项,运行 ./configure --help)。清单 1 提供了下载、解压缩和安装 SWIG 所需的命令。
  
清单 1. 下载、解压缩和安装 SWIG

$ wget http://prdownloads.sourceforge.net/swig/swig-1.3.40.tar.gz
$ tar xzf swig-1.3.40.tar.gz
$ cd swig-1.3.40
$ ./configure
$ make
$ sudo make install
$ which swig
/usr/local/bin/swig

  
构建一个扩展
  让我们构建一个扩展来用 Linux mcrypt 库加密和解密消息。PHP 提供了一个 mcrypt 库,但它不过是对此库的 C 版本稍作修饰后的结果。现在,让我们构建两个更为简洁的方法:一个用来加密字符串,另一个用来解密字符串。
  在 Ubuntu 或与其相似的系统上,您可以用 APT 安装恰当的 mcrypt 库和头文件:$ sudo apt-get install libmcrypt-dev libmcrypt4 mcrypt libmhash2。
  若您宁愿从头开始构建,或者您的分布版内不包括 mcrypt,那么可以从它的主页上下载源代码(参见 参考资料)。替代了 crypt 的 mcrypt 实用程序也依赖于 libmhash,因此必须在编译 mcrypt 之前构建 libmhash。清单 2 给出了构建 libmhash 所需的代码。
  
清单 2. 构建 libmhash

$ # libmhash
$ wget http://sourceforge.net/projects/mhash/files/mhash/0.9.9.9//
mhash-0.9.9.9.tar.bz2/download
$ tar xfj mhash-0.9.9.9.tar.bz2
$ cd mhash-0.9.9.9
$ ./configure
$ make
$ sudo make install
  # libmcrypt
$ wget ftp://mcrypt.hellug.gr/pub/crypto/mcrypt/libmcrypt//
libmcrypt-2.5.7.tar.gz
$ tar xfz libmcrypt-2.5.7.tar.gz
$ cd libmcrypt-2.5.7
$ ./configure
$ make
$ sudo make install
  $ # mcrypt
$ wget wget http://sourceforge.net/projects/mcrypt/files/MCrypt/2.6.8//
mcrypt-2.6.8.tar.gz/download
$ tar xfz mcrypt-2.6.8.tar.gz
$ cd mcrypt-2.6.8
$ ./configure
$ make
$ sudo make install

  
接下来,创建此扩展的 C 代码。代码中最有趣的函数是位于 清单 3 底部的 encode() 和 decode()。二者均具有两个形参 — 一个字符串和一个计数 — 并且均返回字符串。前者加密一个纯文本的字符串,返回其编码;后者解密一个加密了的字符串并返回纯文本。字符串可以是任意长度。
  上述代码使用了 Data Encryption Standard-Electronic Codebook (DES-ECB) 算法。秘密密匙可以是八个字符的任意字符串,并可显示为 12345678(只用于演示目的)。如果您要与其他方交换加密了的消息,需要获得交换方的密钥或创建一个新的密钥并共享它。(加密算法独立于架构和语言,不过,发送者和接收者均必须知道秘密密匙。)
  
清单 3. PHP 扩展的 C 代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>
  char *encode( char *string, int length );
char *decode( char *string, int length );
  MCRYPT start() {
MCRYPT td = mcrypt_module_open( "des", NULL, "ecb", NULL );
if ( td == MCRYPT_FAILED ) {
return( MCRYPT_FAILED );
}
  if ( mcrypt_enc_self_test( td ) != 0 ) {
return( MCRYPT_FAILED );
}
  int i;
char *IV;
int iv_size = mcrypt_enc_get_iv_size( td );
if ( iv_size != 0 ) {
IV = calloc( 1, iv_size );
for ( i = 0; i < iv_size; i++ ) {
IV[ i ] = rand();
}
}
  int keysize = mcrypt_enc_get_key_size( td );
char *key = calloc( 1, keysize );
memcpy(key, "12345678", keysize);
  i = mcrypt_generic_init ( td, key, keysize, IV );
if ( i < 0 ) {
mcrypt_perror( i );
exit(1);
}
  return( td );
}
  
void end( MCRYPT td ) {
mcrypt_generic_deinit( td );
mcrypt_module_close( td );
}
  
#define B64_DEF_LINE_SIZE 72
#define B64_MIN_LINE_SIZE 4
  /*
** encode 3 8-bit binary bytes as 4 '6-bit' characters
*/
void encodeblock( unsigned char in[3], unsigned char out[4], int len ) {
static const char
cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
out[0] = cb64[ in[0] >> 2 ];
out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? cb64[
((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}
  
char *base64encode( char *input, int size ) {
int i, x, len;
unsigned char in[3], out[4];
char *target = calloc( 1, ( ( size + 2 ) / 3 ) * 4 + 1 );
char *t = target;
  for ( x = 0; x < size; ) {
len = 0;
  for( i = 0; i < 3; i++ ) {
if ( x < size ) {
len++;
in = input[x++];
}
else {
in = 0;
}
}
  if( len ) {
encodeblock( in, out, len );
for( i = 0; i < 4; i++ ) {
*t++ = out;
}
}
}
  return( target );
}
  
char *encode( char *string, int length ) {
MCRYPT td = start();
int blocksize = mcrypt_enc_get_block_size( td );
int cryptsize = ( ( length + blocksize - 1 ) / blocksize ) * blocksize;
char *target = calloc( 1, cryptsize );
  memcpy( target, string, length );
  if ( mcrypt_generic( td, target, cryptsize ) != 0 ) {
fprintf( stderr, "Code failing" );
}
  end( td );
  char* result = base64encode( target, cryptsize );
  free( target );
return result;
}
  
char *decode( char *string, int length ) {
MCRYPT td = start();
int blocksize = mcrypt_enc_get_block_size( td );
char *block_buffer = calloc( 1, blocksize );
int decryptlength = (length + blocksize - 1) / blocksize * blocksize;
char *target = calloc( 1, decryptlength );
  memcpy(target, string, length);
  mdecrypt_generic( td, target, decryptlength );
  end( td );
  free(block_buffer);
return( target );
}

  
将清单 3 内的代码复制并粘贴到一个名为 secret.c 的新文件。下一个任务是使用 SWIG 自身的语法描述此扩展的 API。
  
--------------------------------------------------------------------------------
  回页首
  SWIG 文件
  在目前的开发阶段,可以在 secret.c 基础上手动构建一个扩展。但 SWIG 可以帮您完成这一艰苦工作 — 并且只需采用少量的伪代码。清单 4 所示的 secret.i 就是这个新扩展的 SWIG 模板。
  
清单 4. secret.i

%module secret
  %{
extern char *encode( char *string, int length );
extern char *decode( char *string, int length );
%}
  extern char *encode( char *string, int length );
extern char *decode( char *string, int length );

  
对 SWIG 语法和选项的全面解读超出了本文的讨论范围。完整的文档,可以在网上找到(参见 参考资料)。简单来讲,SWIG 文件一般在第 1 行声明扩展的名称。文件的其他部分声明入口点。就是这些内容。编译需要几个步骤:第一步是生成代码的包装程序:$ swig -php secret.i。
  SWIG 将 secret.i 转变为 secret_wrap.c。接下来的几个步骤是构建和链接这些包装程序代码、这个扩展以及 mcrypt 库。请务必用 -fpic 选项构建每个 C 源文件,因该选项可以生成独立于位置的代码,这非常适合于共享库。
  $ cc -fpic -c secret.c
$ gcc `php-config --includes` -fpic -c secret_wrap.c
$ gcc -shared *.o -o secret.so -lmcrypt
$ sudo cp secret.so `php-config --extension-dir`

  
前两个命令构建 C 源代码。第三个命令构建 PHP 扩展。-lmcrypt 选项解析此扩展内入口点在 mcrypt 库内的那些调用。第四个命令会将这个新的 PHP 扩展放入合适的目录以便它可被 PHP 加载。
  在开始编写 PHP 代码之前,最后一步是加载这个扩展。打开适当的 php.ini 文件 — 或者针对 Apache,或者针对 PHP 的命令行变体 — 并添加一行代码:extension=secret.so。
  如果不确定该编辑哪个 php.ini 文件,可以查询 PHP 本身。创建如下所示的这个共三行代码的程序并使用浏览器或交互解释器运行它:
  <?php
phpinfo();
?>

  
查找以 Loaded Configuration File 开头的一行代码。例如,在本文使用的测试平台上,此程序生成了输出 Loaded Configuration File => /etc/php5/cli/php.ini。因此,要编辑的文件是 /etc/php5/cli/php.ini。
  
--------------------------------------------------------------------------------
  回页首
  编写 PHP 代码
  有了这个出色的新扩展后,就可以开始编写 PHP 了。清单 5 显示了 code.php。
  
清单 5. code.php

<?php
include("secret.php");
  $string = "Double secret probation";
$base64encode = secret::encode($string, strlen($string));
$base64decode = base64_decode($base64encode);
$decode = secret::decode( $base64decode, strlen($base64decode));
  echo $decode . "/n";
?>

  
行 1 加载此扩展。行 4 编码字符串 Double secret probation 并使用 Base64 将加密了的这个字符串转变为可打印的字符,以便于用电子邮件等程序传输。行 5 对 Base64 编码进行解码以生成原始字符,行 6 将加密消息解密成原始文本。
  假设将这些代码保存在 coder.php 内,并在系统的 /usr/local/lib 下安装了 mcrypt 库,用 PHP CLI 命令就可以运行这些示例代码了:
  $ LD_LIBRARY_PATH=/usr/local/lib php ./code.php
Double secret probation

  --------------------------------------------------------------------------------
  回页首
  结束语
  SWIG 是重用现有代码的一种极好的方式。用 SWIG 包装 C 或 C++ 库,并将结果集成到您的下一个 Web 或系统应用程序。而更妙的是,SWIG 还可以从相同的 .i 文件生成面向其他脚本语言的包装程序。您只需编写一次扩展,之后,就可以与 PHP、Perl、Python、Ruby 和其他开发人员共享它了。
  
参考资料
  学习
  在 SWIG 站点了解有关 SWIG 扩展生成器的更多信息。
  查阅 SWIG 文档,获得可以使 SWIG 变得更易使用的文章和教程。此项目还维护着几个 wikis。
  PHP.net 是 PHP 开发人员资源中心。
  查看 “推荐 PHP 读物列表”。
  浏览 developerWorks 上的所有 PHP 内容。
  查看 IBM developerWorks 的 PHP 项目资源,扩展 PHP 技能。
  要收听面向软件开发人员的有趣访谈和讨论,请访问 developerWorks podcasts。
  在 PHP 中使用数据库?试试 Zend Core for IBM,这是一个无缝、即开即用、易于安装的 PHP 开发和生产环境,支持 IBM DB2 V9。
  My developerWorks 社区是一个成功社区的典范,涵盖了各种内容的主题。
  随时关注 developerWorks 技术活动和网络广播。
  查阅最近将在全球举办的面向 IBM 开放源码开发人员的研讨会、交易展览、网络广播和其他 活动。
  访问 developerWorks Open source 专区 获得丰富的 how-to 信息、工具和项目更新以及 最受欢迎的文章和教程,帮助您用开放源码技术进行开发,并将它们与 IBM 产品结合使用。
  查看免费的 developerWorks 演示中心,观看并了解 IBM 及开源技术和产品功能。
  获得产品和技术
  从这个项目站点 下载 SWIG。
  下载 mcrypt 库的源代码。
  使用 IBM 产品评估试用版软件 改进您的下一个开源开发项目,这些软件可以通过下载获得。
  下载 IBM 产品评估试用版软件 或 IBM SOA Sandbox for Reuse,并使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
  讨论
  参与 developerWorks blogs 并加入 developerWorks 社区。
  参与 developerWorks PHP 论坛:用 IBM 信息管理产品(DB2、IDS)开发 PHP 应用程序。
来源:http://www.ibm.com/developerworks/cn/opensource/os-php-swig/index.html
  出处:http://blog.csdn.net/heiyeshuwu/archive/2010/03/02/5338344.aspx

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-354133-1-1.html 上篇帖子: [转]PHP autoload机制详解 下篇帖子: PHP CodeIgniter框架源码解析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表