apache+php+cgi搭建前端(二).md

接着上一篇,搞完了httpd+php,接下来就要通过phpcgi接口调用C函数,例子还是在我的git仓库

编译测试动态库

/*hello.c*/
int cc_add(int a, int b)
{
    return a +b;
}
int cc_mul(int a, int b)
{
    return a*b;
}
/*hello.h*/
int cc_add(int a, int b);
int cc_mul(int a, int b);
gcc -fPIC -g -c hello.c -o hello.o
gcc -shared hello.o -o libweb_so.so
cp libweb_so.so /usr/local/lib

编译php扩展模块

预设变量

  • PHP5=php-5.6.32
  • X86_INSTALL=”/home/pan/apache/x86”
  • SO_NAME=web_so
tar xzf php-5.6.32.tar.gz
cd ${PHP7}/ext|| exit 1
./ext_skel --extname=${SO_NAME}|| exit 1
cd ${SO_NAME}|| exit 1

编辑config.m4文件

# 将以下代码去注释;注意是enable函数,后面编译参数是要对应起来的
PHP_ARG_ENABLE(web_so, whether to enable web_so support,
Make sure that the comment is aligned:
[  --enable-web_so           Enable web_so support])

生成configure脚本

    ${X86_INSTALL}/${PHP5}/bin/phpize|| exit 1

修改php.ini文件

# 设置允许加载动态库
enable_dl = On
# 设置加载动态的名称, 如果动态库不在标准的modules目录下,则需要完整路径(未经测试)
extension=web_so.so

编辑扩展c文件

/*编辑php_web_so.h*/
PHP_FUNCTION(confirm_web_so_compiled);
PHP_FUNCTION(hello_add);
/*编辑web_so.c, 增加如下代码*/
PHP_FUNCTION(confirm_web_so_compiled)
{
	char *arg = NULL;
	int arg_len, len;
	char *strg;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
		return;
	}

	len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "web_so", arg);
	RETURN_STRINGL(strg, len, 0);
}
PHP_FUNCTION(hello_add)
{
    long int a, b;
    long int result;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FAILURE) {
        return;
    }
    result = cc_add(a, b);
    RETURN_LONG(result);
}

/*在zend_function_entry字符串数组中增加元素*/
const zend_function_entry web_so_functions[] = {
	PHP_FE(confirm_web_so_compiled,	NULL)		/* For testing, remove later. */
	PHP_FE(hello_add, NULL)
	PHP_FE_END	/* Must be the last line in web_so_functions[] */
};

编译

#  php-config文件路径需自行确定,在php安装目录的/bin下
./configure --enable-web_so --with-libdir=/usr/local/lib/libweb_so.so --with-php-config=/home/pan/apache/x86/php-5.6.32/bin/php-config
make LDFLAGS=-lweb_so
# 将编译出的扩展so拷贝至httpd的modules目录
make install
cp modules/web_so.so /home/pan/apache/x86/httpd-2.4.29/modules/

重启apache httpd

sudo /etc/init.d/httpd restart

结果验证

  • 启动httpd

  • 编辑测试php文件, 放入htdocs目录

<?php
echo confirm_web_so_compiled("panzehua");
echo "<br/>";
echo hello_add(2, 4);
?>
  • 显示如下结果即功能OK

php test result

常见问题排查

如果测试页面报错,要分以下情况

  • 如果以下文字显示在测试页面中,则说明自行编译的动态有问,httpd扩展动态库web_so.so无法链接上libweb_so.so

    Congratulations! You have successfully modified ext/web_so/config.m4. Module panzehua is now compiled into PHP.

    该情况下,phpinfo()函数的应该能找到如下信息

web so info

  • 如果实在链接有问题,建议可以使用动态加载动态库的方法解决,即在PHP_MINIT_FUNCION函数中使用dlopen动态加载函数库
  PHP_MINIT_FUNCTION(webInter)
{
    void *handle = NULL;
    char *error;
    handle = dlopen("/usr/local/lib/librpc_web.dylib", RTLD_LAZY);
    return SUCCESS;
}
  • 如果没有显示,则说明web_so.so扩展库安装有问题,则在phpinfo()中应该查不到web_so.so信息,排查如下几点

    • 确定编译出来得web_so.so链接是否正常,使用ldd查看

    ldd check web so

    该问题注意编译阶段的configure参数–with-libdir

    • 如果apache错误提示找不到函数则要看/usr/local/lib目录下链接的动态库是否存在,以及是否是动态库 ldd check hello so

该问题应该是编译libweb_so.so有问题

其余常见问题

  • httpd无法启动,一般是httpd.conf中加载的模块有问题
  • httpd启动后,web无法访问自己虚拟的IP;请用ifconfig命令确定IP是否存在
  • 如果在php.ini中加载了extension,但是实际测试没有加载,很可能是编译extension使用的phpsize, php-config工具和libphp5.so不一致;这种情况在httpd error_log文件中会有错误日志
  • 使用phpsize和php-config工具,最好指定具体php版本的绝对路径,避免环境有多个php版本影响
  • 如果phpinfo()能正常现实extension信息,但是使用extension中提供的PHP_FUNCION,却报404错误,一半是core-dump了,这时候观察下error_log,每一次刷新都会多一条日志