当前位置: 首页 > 编程日记 > 正文

用C语言扩展PHP功能

用C语言扩展PHP功能

建议读者群:熟悉c,linux,php
   PHP经过最近几年的发展已经非常的流行,而且PHP也提供了各种各样非常丰富的函数。
但有时候我们还是需要来扩展PHP。比如:我们自己开发了一个数据库系统,而且有自己的
库函数来操作数据库,这时候,如果想在PHP中来操作我们自己的数据库的话,就必须自己
扩展PHP了,像mysql,postgresql,之所以PHP能够提供这些数据库操作函数,也都是扩展了
PHP的结果。
    先看看PHP的源代码结构:
    $ cd php-4.4.2/ext
    $ ls
    会显示出目前该PHP发行版本中所有的扩展模块。
    如果想深入学习的话,可以去看看mysql或者postgresql的PHP扩展实现。
   
    下面,我们通过一个简单的模块(mypg)来实现对postgresql的数据库操作。
    $ cd php-4.4.2/ext
    $ ./ext_skel –extname=mypg
    该程序会自动生成mypg目录
    $ cd mypg
    $ ls
    config.m4  CREDITS  EXPERIMENTAL  mypg.c  mypg.php  php_mypg.h  tests
   
    PHP已经自动为我们生成了一些必要的文件和示范代码。
    我们需要作一些修改才能正常的编译和使用该mypg模块。
    $ vi config.m4
    修改成如下内容:
PHP_ARG_ENABLE(mypg, whether to enable mypg support,
               [  –enable-mypg           Enable mypg support])

if test “$PHP_MYPG” != “no”; then
  dnl Write more examples of tests here…

  dnl # –with-mypg -> check with-path
  dnl SEARCH_PATH=”/usr/local /usr”     # you might want to change this
  dnl SEARCH_FOR=”/include/mypg.h”  # you most likely want to change this
  dnl if test -r $PHP_MYPG/; then # path given as parameter
  dnl   MYPG_DIR=$PHP_MYPG
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for mypg files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       MYPG_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl
  dnl if test -z “$MYPG_DIR”; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the mypg distribution])
  dnl fi

  dnl # –with-mypg -> add include path
  dnl PHP_ADD_INCLUDE($MYPG_DIR/include)

  dnl # –with-mypg -> check for lib and symbol presence
  dnl LIBNAME=mypg # you may want to change this
  dnl LIBSYMBOL=mypg # you most likely want to change this

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYPG_DIR/lib, MYPG_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_MYPGLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong mypg lib version or lib not found])
  dnl ],[
  dnl   -L$MYPG_DIR/lib -lm -ldl
  dnl ])
  dnl
  dnl PHP_SUBST(MYPG_SHARED_LIBADD)

  PHP_NEW_EXTENSION(mypg, mypg.c, $ext_shared)
fi

dnl开头的为注释,其实我们也只是把某些注释去掉了。

   然后修改php_mypg.h,内容为:
#ifndef PHP_MYPG_H
#define PHP_MYPG_H

extern zend_module_entry mypg_module_entry;
#define phpext_mypg_ptr &mypg_module_entry

#ifdef PHP_WIN32
#define PHP_MYPG_API __declspec(dllexport)
#else
#define PHP_MYPG_API
#endif

//模块初始化时调用函数
PHP_MINIT_FUNCTION(mypg);

//我们的数据库连接函数
PHP_FUNCTION(mypg_connect);
//我们的数据库操作函数
PHP_FUNCTION(mypg_execute);
//我们的数据库关闭函数
PHP_FUNCTION(mypg_close);

#ifdef ZTS
#include “TSRM.h”
#endif

#endif  /* PHP_MYPG_H */   

继续修改mypg.c,内容改为:
#ifdef HAVE_CONFIG_H
#include “config.h”
#endif

#include “php.h”
#include “php_ini.h”
#include “ext/standard/info.h”
#include “php_mypg.h”
#include “libpq-fe.h”

int le_link;
function_entry mypg_functions[] = {
        PHP_FE(mypg_connect,                                                    NULL)
        PHP_FE(mypg_execute,                                                    NULL)
        PHP_FE(mypg_close,                                                      NULL)
        {NULL, NULL, NULL}
};
zend_module_entry mypg_module_entry = {
        STANDARD_MODULE_HEADER,
        “mypg”, mypg_functions, PHP_MINIT(mypg), NULL, NULL, NULL,
        NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
};

ZEND_GET_MODULE(mypg)

//数据库链接关闭函数
static void _close_mypg_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
        PGconn *link = (PGconn *)rsrc->ptr;
        PQfinish(link);
}
PHP_MINIT_FUNCTION(mypg)
{
    //注册资源回收函数,如果没有显示用mypg_close关闭数据库连接的化,PHP会自动调用该函数释放资源
    le_link = zend_register_list_destructors_ex(_close_mypg_link, NULL, “mypg link”, module_number);
    return SUCCESS;

}

//连接数据库
static void php_mypg_do_connect(INTERNAL_FUNCTION_PARAMETERS)
{
        PGconn *link;

        //只接受一个函数参数
        if(ZEND_NUM_ARGS() != 1)
        {
            WRONG_PARAM_COUNT;
        }

        zval **connect_info;

        /* get the connection information string */
        if (zend_get_parameters_ex(1, &connect_info) == FAILURE) {
            RETURN_FALSE;
        }

        /* create our resource hash key */
        convert_to_string_ex(connect_info);

        //调用libpq, 执行数据库连接
        if ((link=PQconnectdb(Z_STRVAL_PP(connect_info))) && PQstatus(link)!=CONNECTION_OK) {
            RETURN_FALSE;
        }
      
        //将return_value注册为得到的数据库连接
        /* add it to the list */
        ZEND_REGISTER_RESOURCE(return_value, link, le_link);
}
PHP_FUNCTION(mypg_connect)
{
    php_mypg_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

//我们自己定义的数据库操作函数
PHP_FUNCTION(mypg_execute)
{
        zval **query, **link = NULL;
        int id;
        PGconn *conn;
        PGresult *res;

        //参数为2, 1:执行的sql  2:数据库链接句柄
        switch(ZEND_NUM_ARGS()) {
                case 2:
                        if (zend_get_parameters_ex(2, &query, &link)==FAILURE) {
                                WRONG_PARAM_COUNT;
                        }
                        break;
                default:
                        WRONG_PARAM_COUNT;
                        break;
        }
      
        //取得数据库链接
        ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1, “mypg link”,  le_link);

        convert_to_string_ex(query);
      
        //通过libpq执行SQL
        res = PQexec(conn, Z_STRVAL_PP(query));

        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
                RETURN_FALSE;
        }

        PQclear(res);
        
        RETURN_TRUE;

}
PHP_FUNCTION(mypg_close)
{
        zval **link;
        int id;
        PGconn *conn;

        switch (ZEND_NUM_ARGS()) {
                case 1:
                        if (zend_get_parameters_ex(1, &link)==FAILURE) {
                                RETURN_FALSE;
                        }
                        break;
                default:
                        WRONG_PARAM_COUNT;
                        break;
        }
        if(link == NULL)
        {
                RETURN_FALSE;
        }

        //根据资源句柄取得资源
        ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1,”mypg link”,  le_link);
      
        //删除该资源,PHP自动调用前面注册的函数来关闭数据库链接
        zend_list_delete(Z_RESVAL_PP(link));

        RETURN_TRUE;

}
    mypg模块就基本开发完成了,我们需要重新为php生成configure文件。
   
    $ cd php-4.4.2
    $ rm -rf autom4te.cache/; rm -f configure
    $ ./buildconf  –force
    此时PHP会读取所有ext/子目录下的config.m4,并集成到新生成的configure脚本中。
    如果没有意外,运行如下命令会得到如下结果:
    $ ./configure –help | grep mypg
      –enable-mypg           Enable mypg support
    编译PHP:
    $ ./configure —enable-mypg
    由于要链接libpq.so,可以vi Makefile
    在EXTRA_LIBS后面加上:-lpq 来把libpq编译进去,当然也可以通过修改mypg的config.m4来实现,
    这里不在啰嗦。
    $ make
    $ make install
   
    编写我们的模块测试脚本:testmypg.php
/*
* this is the sample php code
* to invoke our module: mypg
*/
$link = mypg_connect(”hostaddr=172.16.19.8 dbname=pgsql user=pgsql password=12345″);
if($link)
{
        echo “Successfully connected  to PostgreSQL.\n”;
}
else
{
        die(”Connect error.\n”);
}

$sql = “insert into test values(’12345′,’23145′)”;

mypg_execute($sql, $link);

$link2 = $link;

mypg_execute($sql, $link2);
mypg_execute($sql, $link);
mypg_close($link);

echo “Database query ok.\n”;

?>
运行该PHP程序,如果在postgresql的pgsql库中有table: test (col1 varchar(100), col2 varchar(100))
里面应该已经有2条记录了。

    编写php模块扩展需要很多PHP源码的知识,可以通过参考其他module或者直接阅读PHP代码来逐步提高自己
的开发能力。
    php官方的站点上也有一些文章可供参考:http://cn2.php.net/manual/en/internals2.php

http://cn2.php.net/manual/zh/internals2.structure.php
    希望这篇文章能够给想扩展PHP的兄弟一个大概的方向!

相关文章:

手把手快速实现 Resnet 残差模型实战

作者 | 李秋键 出品 | AI科技大本营(ID:rgznai100) 引言:随着深度学习的发展,网络模型的深度也随之越来越深,但随着网络模型深度的加深,往往会曾在这随着模型深度的加大,模型准确率反而下降的问…

JHipster开发环境安装

这里采用官方推荐的Yarn安装方法,默认操作系统为CentOS 7.4。 1 安装JDK 推荐版本:OpenJDK 1.8.0-64bit。 完整安装说明,请参考这里 2 安装Nodejs 推荐版本: v8.11.3 完整安装说明,请参考这里 3 安装Yarn 推荐版本&…

用C语言写PHP扩展

用C语言写PHP扩展 1:预定义 在home目录,也可以其他任意目录,写一个文件,例如caleng_module.def 内容是你希望定义的函数名以及参数: int a(int x,int y)string b(string str,int n) 2:到php源码目录的ext目…

Pandas 数据挖掘与分析时的常用方法

今天我们来讲一下用Pandas模块对数据集进行分析的时候,一些经常会用到的配置,通过这些配置的帮助,我们可以更加有效地来分析和挖掘出有价值的数据。数据集的准备这次我们需要用到的数据集是广为人所知的泰坦尼克号的乘客数据,我们…

MySQL基本概念

1. 分清几个概念:数据库,数据库对象和数据; 数据库分为:系统数据库和用户数据库; 系统数据库 是安装完MySQL服务器后自带的数据库,会记录一些必要的信息,用户不能直接修改这些系统数据库。转载…

SpringMvc+ajax实现文件跨域上传

最近开始学习SpringMVC框架,在学习数据绑定的时候,发现可以使用RequestParam注解绑定请求数据,实现了文件上传。但是如果一个项目是前后端分离的,前端系统向后端服务上传文件该怎么解决了? 首先考虑前端用哪一种方式进…

使用Nmap获取目标服务器开放的服务以及操作系统信息

http://nmap.org/download.html 1.下载安装rpm -vhU http://nmap.org/dist/nmap-5.61TEST5-1.i386.rpmrpm -vhU http://nmap.org/dist/zenmap-5.61TEST5-1.noarch.rpmrpm -vhU http://nmap.org/dist/ncat-5.61TEST5-1.i386.rpmrpm -vhU http://nmap.org/dist/nping-0.5.61TEST5…

Pandas 数据类型概述与转换实战

作者 | 周萝卜 来源 | 萝卜大杂烩 在进行数据分析时,确保使用正确的数据类型是很重要的,否则我们可能会得到意想不到的结果或甚至是错误结果。对于 pandas 来说,它会在许多情况下自动推断出数据类型 尽管 pandas 已经自我推断的很好了&#x…

7.10 数据注解特性--NotMapped

NotMapped特性可以应用到领域类的属性中,Code-First默认的约定,是为所有带有get,和set属性选择器的属性创建数据列。。 NotManpped特性打破了这个约定,你可以使用NotMapped特性到某个属性上面,然后Code-First就不会为这个属性就不…

Condition

2019独角兽企业重金招聘Python工程师标准>>> 1、Condition的简介 线程通信中的互斥除了用synchronized、Object类的wait()和notify()/notifyAll()方式实现外,方法JDK1.5中提供的Condition配套Lock可以实现相同的功能。Condition中的await()和signal()/si…

使用who.is查域名DNS信息以及用sameip.org查其他网站

www.who.is网站可以查域名信息,非常好用:例如查 hack-test.com然后我们可以找找同个IP上的其他站点(旁站:sameip.org)参考: 黑客是怎么攻击一个网站的?

基于 OpenCV 的人脸追踪

作者 | 努比 来源 | 小白学视觉 在Raspberry上启动项目很简单,所以让我们开始吧。 01. 产品清单 Raspberry Pi 4 Model B — 4GB 适用于Raspberry Pi的Pan-Tilt HAT Pi Camera v2 8MP 微型SD卡 迷你HDMI电缆 Raspberry Pi摄像头电缆—尺寸:457mm x …

-bash: /bin/rm: Argument list too long的解决办法

-bash: /bin/rm: Argument list too long的解决办法 当目录下文件太多时,用rm删除文件会报错: -bash: /bin/rm: Argument list too long 提示文件数目太多。 解决的办法是使用如下命令: ls | xargs -n 10 rm -fr ls 输出所有的文件名(用…

React使用ES6语法重构组件代码

首次使用react&#xff0c;要注意react不同版本库&#xff0c;是ES5还是ES6的写法&#xff0c;如何做到统一。下面对于ES6语法重构组件的代码如下&#xff1a;&#xff08;1&#xff09;原始代码&#xff1a; <script type"text/babel">var destinationdocumen…

PHP哈希表碰撞攻击原理

哈希表碰撞攻击&#xff08;Hashtable collisions as DOS attack&#xff09;的话题不断被提起&#xff0c;各种语言纷纷中招。本文结合PHP内核源码&#xff0c;聊一聊这种攻击的原理及实现。 哈希表碰撞攻击的基本原理 哈希表是一种查找效率极高的数据结构&#xff0c;很多语言…

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法Java语言提供了一种功能强大的注释形式&#xff1a;文档注释。如果编写Java源代码时添加了合适的文档注释&#xff0c;然后通过JDK提供的javadoc工具可以直接将源代码里的文档注释提取成一份系统的API文档。jav…

如何读取Excel表格中不同sheet表的同一位置单元格数据,并绘制条形图呢?

作者 | 黄伟呢来源 | 数据分析与统计学之美今天&#xff0c;有位朋友在群里面咨询了一个问题&#xff1a;如何读取Excel表格中"不同sheet表"的同一位置单元格数据&#xff0c;并绘制条形图呢&#xff1f;有人提议用vba&#xff0c;但是不得不说&#xff0c;没有学过v…

vue-router学习笔记

配置路由模式 const routernew VueRouter({routes }) hash模式(默认):通过url的hash来模拟一个完整的url&#xff0c;于是当url改变时&#xff0c;页面不会重新加载。history模式&#xff1a;通过history完成url跳转而不需要重新加载页面。注意&#xff1a;为了防止404错误&…

PHP防止注入攻击

注入攻击不多说了PHP addslashes() 函数--单撇号加斜线转义PHP String 函数定义和用法addslashes() 函数在指定的预定义字符前添加反斜杠。这些预定义字符是&#xff1a;单引号 ()双引号 (")反斜杠 (\)NULL语法addslashes(string)参数描述string必需。规定要检查的字符串。…

首届腾讯数字安全创新大赛在京启动,挖掘新锐力量推动产业创新

3月10日&#xff0c;首届腾讯数字安全创新大赛在京正式启动。本次大赛由腾讯安全和中国产业互联网发展联盟联合主办&#xff0c;腾讯安全、KEEN、元起资本、赛博英杰、数世咨询等多家企业联合发起&#xff0c;中国产业互联网发展联盟安全专委会承办。 大赛旨在寻找网络安全新力…

oracle数据库无监听程序

在电脑---服务---启动oracle tns 如果还是出现错误的话&#xff0c;找到Net Manager&#xff0c;将网络的ip监听删除&#xff0c;将本机的主机名配好&#xff0c;即可打开tns服务 转载于:https://www.cnblogs.com/jiangsheng3/p/5025201.html

个人开发者即时到账收款方案 BufPay.com

BufPay 个人即时到账支付平台前言 作为独立开发者&#xff0c;一般只有一个人独立奋战&#xff0c;做出了产品需要收款是非常麻烦的&#xff0c;接入支付宝微信支付都需要公司公户&#xff0c;而注册公司、开公户等一系列操作非常麻烦&#xff0c;成本也很高一年也要 1w 左右。…

用 Python 制作数据大屏,超简单

作者 | 俊欣来源 | 关于数据分析与可视化今天我们用Streamlit模块来制作一个数据面板&#xff0c;将数据更加直观地呈现给别人观看&#xff0c;整个页面大致如下图所示&#xff1a;制作工具栏在页面的左侧是一个工具栏&#xff0c;工具栏中有多个按钮&#xff0c;分别是“About…

Oracle 12C -- 清空audit记录

1.使用job清空 SQL> dbms_audit_mgmt.create_purge_job(audit_trail_type> DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,audit_trail_purge_interval>12&#xff0c;audit_trail_purge_name>audit_trail_pj,use_last_arch_timestamp>TRUE,container>dbms_audit_mgm…

魔法引用函数magic_quotes_gpc和magic_quotes_runtime的区别和用法

PHP提供两个方便我们引用数据的魔法引用函数magic_quotes_gpc和magic_quotes_runtime&#xff0c; 这两个函数如果在php.ini设置为ON的时候&#xff0c;就会为我们引用的数据碰到单引号和双引号"是自动加上反斜线&#xff0c;帮我们自动转译符号&#xff0c;确保数据操作的…

Unity脚本生成插件:Script Create Dialog

最近写代码又犯懒了...感觉每次新建脚本都要写一堆简单重复的东西好无聊&#xff0c;所以搜索了一下有没有自动生成脚本的插件。结果还真被我发现了&#xff0c;官方在N久之前就制作了自动生成脚本的插件[Script Create Dialog]&#xff0c;大概是名字起的和脚本生成器相差太多…

多路IO复用模型 select epoll 等

同步阻塞IO在等待数据就绪上花去太多时间&#xff0c;而传统的同步非阻塞IO虽然不会阻塞进程&#xff0c;但是结合轮询来判断数据是否就绪仍然会耗费大量的CPU时间。多路IO复用提供了对大量文件描述符进行就绪检查的高性能方案。selectselect诞生于4.2BSD&#xff0c;在几乎所有…

可操作性强!Python实现一个电影订票系统!

来源丨Python小二一、效果展示通过Python实现一个电影订票系统&#xff0c;效果如下所示&#xff1a;二、整体结构图三、代码分解3.1 infos.py一部电影的详细信息适合用 字典 结构来存储&#xff0c;我们可以给字典里添加多个键值对来保存电影的名称、座位表和宣传时用的字符画…

centos7 install mysql

1. 下载mysql的repo源 $ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2. 安装mysql-community-release-el7-5.noarch.rpm包 $ sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm 安装这个包后&#xff0c;会获得两个mysql的yum repo源&#x…

unity加载ab后,场景shader不起效问题(物件表现黑色)

需要把unity自带的shader&#xff0c;加入到默认列表转载于:https://www.cnblogs.com/lancidie/p/9293827.html