使用C/C++编写PHP Extension

和Python,JavaScript等高级语言一样,PHP也可以通过C/C++编写扩展功能。这里分享下如何构建一个简单的PHP扩展,以及如何调用第三方DLL库。

参考原文:Making PHP Barcode Extension with Dynamsoft Barcode SDK

使用Visual Studio 2012构建PHP扩展

Windows PHP的安装包本身不包涵头文件,所以要构建PHP扩展,必须下载PHP的源码。在Windows上,要编译PHP,以及构建PHP扩展都必须使用对应的Visual Studio,不然会出现大量的错误。在这里我们使用Visual Studio 2012去构建PHP 5.6的扩展。步骤如下:

  1. 下载PHP 5.6的源码以及VC11 build版本。
  2. 创建一个空的Win32工程,应用类型选择DLL。
  3. 添加头文件路径:
    F:\php_pack\php-5.6.10-src
    F:\php_pack\php-5.6.10-src\Zend
    F:\php_pack\php-5.6.10-src\win32
    F:\php_pack\php-5.6.10-src\TSRM
    F:\php_pack\php-5.6.10-src\main
  4. 添加库路径:
    F:\php_pack\php-5.6.10-Win32-VC11-x86\dev
  5. 添加依赖:
    php5ts.lib
  6. 创建php_dbr.h
    #pragma once
     
    #include "zend_config.w32.h"    
    #include "php.h"
  7. 创建php_dbr.cpp
    #include "php_dbr.h"
     
    ZEND_FUNCTION(DecodeBarcodeFile);
     
    zend_function_entry CustomExtModule_functions[] = {
        ZEND_FE(DecodeBarcodeFile, NULL)
        {NULL, NULL, NULL}
    };
     
    zend_module_entry CustomExtModule_module_entry = {
        STANDARD_MODULE_HEADER,
        "Dynamsoft Barcode Reader",
        CustomExtModule_functions,
        NULL, NULL, NULL, NULL, NULL,
        NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
    };
     
    ZEND_GET_MODULE(CustomExtModule)
     
    ZEND_FUNCTION(DecodeBarcodeFile){
     
        RETURN_STRING("No Barcode detected", true);
    }
  8. 添加宏定义:
    ZEND_DEBUG=0
    ZTS=1
    ZEND_WIN32
    PHP_WIN32

    如果不添加,会出现很多错误。

  9. 现在build工程就可以生成php_dbr.dll了。

使用Dynamsoft Barcode SDK创建PHP Barcode Extension

来看一下如何通过PHP扩展调用第三方的DLL库:

  1. 添加Dynamsoft Barcode SDK的头文件和库文件路径到工程属性中
  2. 通过SDK的C/C++接口解码Barcode,并把结果转换成PHP可读数据:
#include "php_dbr.h"
 
#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"
 
#ifdef _WIN64
#pragma comment(lib, "DBRx64.lib")
#else
#pragma comment(lib, "DBRx86.lib")
#endif
 
void SetOptions(pReaderOptions pOption, int option_iMaxBarcodesNumPerPage, int option_llBarcodeFormat){
 
    if (option_llBarcodeFormat > 0)
        pOption->llBarcodeFormat = option_llBarcodeFormat;
    else
        pOption->llBarcodeFormat = OneD;
 
    if (option_iMaxBarcodesNumPerPage > 0)
        pOption->iMaxBarcodesNumPerPage = option_iMaxBarcodesNumPerPage;
    else
        pOption->iMaxBarcodesNumPerPage = INT_MAX;
 
}
 
ZEND_FUNCTION(DecodeBarcodeFile);
 
zend_function_entry CustomExtModule_functions[] = {
    ZEND_FE(DecodeBarcodeFile, NULL)
    {NULL, NULL, NULL}
};
 
zend_module_entry CustomExtModule_module_entry = {
    STANDARD_MODULE_HEADER,
    "Dynamsoft Barcode Reader",
    CustomExtModule_functions,
    NULL, NULL, NULL, NULL, NULL,
    NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
};
 
ZEND_GET_MODULE(CustomExtModule)
 
ZEND_FUNCTION(DecodeBarcodeFile){
    array_init(return_value);
 
    // Get Barcode image path
    char* pFileName = NULL;
    int iLen = 0;
 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pFileName, &iLen) == FAILURE) {
        RETURN_STRING("Invalid parameters", true);
    }
 
    // Dynamsoft Barcode Reader: init
    int option_iMaxBarcodesNumPerPage = -1;
    int option_llBarcodeFormat = -1;
    pBarcodeResultArray pResults = NULL;
    ReaderOptions option;
 
    SetOptions(&option, option_iMaxBarcodesNumPerPage, option_llBarcodeFormat);
 
    // decode barcode image file
    int ret = DBR_DecodeFile(
        pFileName,
        &option,
        &pResults
        );
 
    if (ret == DBR_OK)
    {
        int count = pResults->iBarcodeCount;
        pBarcodeResult* ppBarcodes = pResults->ppBarcodes;
        pBarcodeResult tmp = NULL;
 
        // loop all results
        for (int i = 0; i < count; i++)
        {
            tmp = ppBarcodes[i];
 
            // convert format type to string
            char format[64]; 
            sprintf (format, "%d", tmp->llFormat); 
 
            // (barcode type, result)
            add_assoc_string(return_value, format, tmp->pBarcodeData, 1);
        }
 
        // Dynamsoft Barcode Reader: release memory
        DBR_FreeBarcodeResults(&pResults);
    }
    else
    {
        RETURN_STRING("No Barcode detected", true);
    }
 
}

现在我们需要写一个PHP的测试脚本,并把DLL部署到PHP中。

一个简单的PHP Barcode Reader:

<?php
 
$filename = "F:\\git\\Dynamsoft-Barcode-Reader\\Images\\AllSupportedBarcodeTypes.tif";
 
if (file_exists($filename)) {
  echo "Barcode file: $filename \n";
  $resultArray = DecodeBarcodeFile($filename);
 
  if (is_array($resultArray)) {
    foreach($resultArray as $key => $value) {
      print "format:$key, result: $value \n";
      print "*******************\n";
    }
  }
  else {
    print "$resultArray";
  }
 
} else {
    echo "The file $filename does not exist";
}
 
?>

打开php.ini初始化文件,加入:

[Dynamsoft Barcode Reader]
extension=php_dbr.dll

现在要把生成的DLL拷贝到{PHP root directory}\ext。如果你同时把DynamsoftBarcodeReaderx86.dll也拷贝到这个目录下,PHP会找不到这个DLL,报出如下错误:

如何修复这个问题?你只要把第三方的DLL拷贝到PHP根目录下即可。现在再试一次:

源码

https://github.com/yushulx/Dynamsoft-Barcode-Reader/tree/master/samples/PHP

时间: 2024-11-02 11:18:08

使用C/C++编写PHP Extension的相关文章

neutron plugin 与 extension 编写流程

neutron plugin 与 extension 编写流程 关于neutron,它是openstack中管理网络相关的一个项目,它主要负责管理了openstack中的虚拟网络,它将网络作为一种服务提供给租户,它的设计遵循了SDN(soft define network)的设计原则从而实现了网络的虚拟化. neutron采用了插件技术,关于neutron的具体技术细节,可以参考: https://yeasy.gitbooks.io/openstack_understand_neutron/co

转载--编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)

阅读目录 建议16:易变业务使用脚本语言编写 建议17:慎用动态编译 建议18:避免instanceof非预期结果 建议19:断言绝对不是鸡肋 建议20:不要只替换一个类 回到顶部 建议16:易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy.Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它们都是在运行期解释执行的.为什么Java这种强编译型语言会需要这些脚本语言呢?那是因为脚本语言的三大特征,如下所示:

(翻译)如何编写好的用户手册

原文:How to Publish a Great User Manual 地址:http://www.asktog.com/columns/017ManualWriting.html When was the last time you curled up in bed with a really good user-manual just for the sheer joy of reading it? Never? Think that is some immutable law of n

深入理解php内核 编写扩展_III- 资源

原文:http://devzone.zend.com/article/1024-Extension-Writing-Part-III-Resources 编写扩展_III- 资源 介绍 资源 初始化资源 接收资源作为函数参数 销毁资源 强制销毁资源 持久资源 查找现存的持久资源 核对(代码)完整性 总结 3.1介绍 迄今为止,你已经处理了一些熟悉的概念,而且很容易就可以在在用户空间找到它们的对应物.在本教程中,你将深入一个更陌生的数据类型的内部运行机制,该类型对用户空间完全隐藏了内部细节,但是它

【转载】游戏外挂的编写原理和思路

原文:游戏外挂的编写原理和思路 游戏外挂的编写原理(一) 一. 前言 所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作.修改游戏网络数据包以及修改游戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将.虽然,现在对游戏外挂程序的“合法”身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧. 不管游戏外挂程序是不是“合法”身份,但是它却是具有一定的技术含量的,在这些小小程序中使用了许多高端技术,如拦截Sock技术.拦截API技术.模拟键盘与鼠标技术.

Grunt配置文件编写技巧及示范

受益于grunt这么久,继续分享关于grunt的一些技巧.grunt确实是前端项目中不可或缺的提升效率的工具.第一次接触grunt是在去年7月份,开始有接触LESS.Coffee Script的等需要编译的模板才能使用的,所以grunt就有了很大的用处.当然除了编译,还有一部分的工作就是压缩,grunt常用的任务就是压缩JS.CSS,检查语法错误,同时也可以保证质量压缩图片(删除图片多余信息). 使用起来也很简单,基于node,所以我们就可以通过js来控制这些文件.唯一需要做的是编写配置文件,做

手把手教你编写一个简单的PHP模块形态的后门

看到Freebuf 小编发表的用这个隐藏于PHP模块中的rootkit,就能持久接管服务器文章,很感兴趣,苦无作者没留下PoC,自己研究一番,有了此文 0×00. 引言 PHP是一个非常流行的web server端的script语言.目前很多web应用程序都基于php语言实现.由于php是个开源软件并易于扩展,所以我们可以通过编写一个PHP模块(module 或者叫扩展 extension)来实现一个Backdoor. 本文就简单介下如何一步步编写一个简单的php 动态扩展后门. 0×01. p

深入理解php内核 编写扩展 II:参数、数组和ZVALs

原文:http://devzone.zend.com/article/1022-Extension-Writing-Part-II-Parameters-Arrays-and-ZVALs Part II: Parameters,Arrays, and ZVALs 原文:http://devzone.zend.com/article/1023-Extension-Writing-Part-II-Parameters-Arrays-and-ZVALs-continued Part II: Param

深入理解php内核 编写扩展 I:介绍PHP和Zend

内容: 编写扩展I -  PHP和Zend起步 原文:http://devzone.zend.com/public/view/tag/Extension Part I: Introduction to PHP and Zend http://devzone.zend.com/article/1021-Extension-Writing-Part-I-Introduction-to-PHP-and-Zend 编写扩展_II - 参数.数组和ZVALs 编写扩展_II - 参数.数组和ZVALs[继