[PHP] 확장 DLL(Zend Extension dll) 파일을 작성하고 적용하는 방법(사용자 내장 함수 만들기)


Development note/PHP  2019. 9. 21. 09:00

안녕하세요. 명월입니다.


이 글은 PHP에서 확장 DLL(Zend Extension dll) 파일을 작성하고 적용하는 방법(사용자 내장 함수 만들기)에 대한 글입니다.


우리가 PHP코딩을 하다 보면 사용되는 내장 함수들이 많습니다. 자주 사용되는 빈칸없애는 함수(trim)부터 문자열 분할하기(explode)등이 많이 있습니다.

기본적으로 PHP에서 이런 내장 함수를 많이 제공하기 때문에 PHP 개발하면서 불편함을 못 느끼는데, 간혹 PHP소스상의 함수가 아닌 이런 내장 함수를 만들지는 못할까 생각할 때가 많습니다.


추가적으로 사용할 내장 함수를 사용하려면 php.ini 설정에서 extension부분을 ext폴더 안의 dll로 import하는 환경 설정 부분이 있습니다.

이 내장 함수를 visual studio c++로 만들어서 우리가 PHP에 적용할 수 있습니다.

먼저 내장 함수를 사용하기 위해서는 Visual studio가 설치(C++ 개발 가능용)되어야 하고 php source가 필요합니다.

그리고 가장 중요한 apache-PHP가 설치되어 있어야 합니다.

링크 - [PHP] PHP 개발환경 만들기와 IDE(Eclipse) 설정하기


링크 - [C# 강좌 - 2] C# IDE 툴 Visual Stuio 설치 하기(Express 버젼)

이게 옛날 꺼네요...무려 7년전 글입니다. ㅠㅠ 옛날에 쓴 글들 다시 처음부터 다시 써야하는데 귀찮네요..

링크 - https://visualstudio.microsoft.com/ko/vs/community/

이제는 express 버젼이 아니고 community 버전으로 무료로 제공합니다. 설치방법 어렵지 않으니 다운 받으시고 설치하세요.


그리고 php 소스를 다운 받습니다.

링크 - https://windows.php.net/download#php-7.3


여기서 저는 현재 가장 최신인 7.3.9버전을 사용하고 있으니 7.3.9 버전의 소스를 다운로드하고 적당한 폴더에 압축을 풉니다.

저는 d:\php-7.3.9-src 폴더에 압축을 풀었습니다.


제 visual studio는 2017버전이긴 합니다만, 2008버전부터 최신버전까지는 아마 95%이상 사용법이 비슷할 것입니다.

먼저 Dynamic-Link Library(DLL)로 프로젝트를 만듭니다.

먼저 x86인지 x64인지 구별을 해야하는데, 이를 먼저 설정합니다. 저는 64비트를 설치했으므로 x64로 설정했습니다.

그리고 프로젝트 프로퍼티를 수정합니다.

C / C++의 General 탭을 가서 Include 디렉토리를 추가합니다.

그리고 소스를 압축 푼 폴더와 그 아래의 main, Zend, TSRM을 추가하도록합니다.

그리고 php 라이브러리를 추가하여야 하는데 이는 apache-php가 설치되어 있는 폴더 아래 dev폴더 안에 있습니다.

그리고 실제 라이브러리를 추가합니다.

여기까지 개발 준비는 끝났네요.

그럼 먼저 Header의 stdafx.h를 수정해서 include와 define를 설정합니다.

기존에 선언되어 있는 건 필요없으니 주석처리하거나 삭제해도 됩니다.

#pragma once

#define ZTS 1
#define ZEND_WIN32 1
#define PHP_WIN32 1
#define ZEND_DEBUG 0

#include "zend_config.w32.h"
#include "php.h"

그리고 위 소스를 추가합니다.

이제 프로젝트의 메인 파일로 가서 내장 함수를 작성합니다. 저의 경우는 UserExtensionExample.cpp가 되겠네요.

// UserExtensionExample.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"

// 사용할 내장 함수 이름입니다. 이 이름은 아래의 ZEND_FUNCTION과 일치해야 합니다.
ZEND_FUNCTION(nowonbun);

zend_function_entry functions[] = {
  // 사용할 내장 함수명을 일치시킵니다.
  ZEND_FE(nowonbun, NULL)
  {
    NULL, NULL, NULL
  }
};
// 엔트리 등록입니다.
zend_module_entry entry_module_entry = {
  STANDARD_MODULE_HEADER,
  "nowonbun Extension",
  functions,
  NULL, NULL, NULL, NULL, NULL,
  "1.0",
  STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(entry);

// 실제 함수가 호출되면 실행되는 영역입니다.
ZEND_FUNCTION(nowonbun)
{
  // php안에는 php용 데이터 타입이 존재합니다.
  zend_string *parameter;
  const char* data = "Hello world";
  
  // 파라미터를 String 타입으로 받습니다.
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", ¶meter) == FAILURE) {
    RETURN_BOOL(0);
  }
  // 반환할 변수를 선언합니다.
  zend_string *res = zend_string_alloc(ZSTR_LEN(parameter) + strlen(data), 0);
  // 이 두개는 문자열을 합치는 중입니다.
  memcpy(ZSTR_VAL(res), ZSTR_VAL(parameter), ZSTR_LEN(parameter));
  memcpy(ZSTR_VAL(res) + ZSTR_LEN(parameter), data, strlen(data));
  
  // 합치고 리턴합니다.
  RETURN_STR(res);
}

참고로 c++과 비슷하면서도 약간 다릅니다. php 전용 c++이라고나 할까요??

우리가 처음에 소스 압축 해제한 디렉토리 밑에 ext 폴더로 가면 php에서 실제로 사용되는 dll들 소스들이 있습니다. 그리고 zend_test폴더에는 정말 기본적인 예제가 있습니다.

아직 저도 php dll를 만들 기회가 많지 않아서 실제로 많이 만들어 보지는 않았는데 실제로 만들게 되면 여기 소스들을 참조해서 만들면 됩니다.

(혹시 설명이 필요하신이 계시면 댓글 남겨주세요.. 시간 내서 공부할 겸 몇개 만들어 봐야겠네요...엔돌핀이 솟습니다...)

위 소스는 참고로 파라미터로 데이터를 받으면 「파라미터 + Hello world」라고 출력을 하는 내장함수 입니다.

대충 C++ 소스라 어려운 게 없네요. 파라미터 리터널 타입은 PHP에서 소개하고 있습니다. 참고하시면 됩니다.

링크 - https://www.php.net/manual/en/internals2.funcs.php


위 링크를 가보시면 zval* 이 있는데 이게 void*와 같은 개념같네요.. 클래스 선언하게 되면 php와 포인터를 공유할 수 있는 객체같습니다.

이제 다 만들었으면 빌드하겠습니다.

워낙 간단한 프로그램이니깐 에러없이 컴파일이 되는 군요..

이제 output폴더로 가서 php의 ext폴더 밑으로 복사합니다.

그리고 php.ini 파일에도 extension을 추가합니다.

이제 아파치를 기동하고 index.php에서 사용해보겠습니다.

<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
  <?=nowonbun("여기는 명월일지입니다. ")?>
</body>
</html>


참조 - https://stackoverflow.com/questions/17251400

참조 - https://bloodguy.tistory.com/entry/PHP-Extension-만들기-Visual-C-2008


참조 - https://phpinternals.net/docs/zend_parse_parameters

참조 - https://www.php.net/manual/en/internals2.funcs.php

참조 - https://github.com/Microsoft/php-sdk-binary-tools

참조 - https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2


여기까지 PHP에서 확장 DLL(Zend Extension dll) 파일을 작성하고 적용하는 방법(사용자 내장 함수 만들기)에 관한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.