[Bubble://ちずろぐ/別館/]

別館 ではGISに関する情報を掲載しています。

[Bubble://ちずろぐ/別館/KaMap/]

MapserverのAJAX版UI,ka-Mapのデモです。

[Bubble://旧日記/]

旧本館。更新していません。

« MS RFC 37は実装されていない? | トップページ | PostgreSQL8.3を使っている人は »

2008年11月12日 (水)

PEAR::CodeGen_PECLでPHPのエクステンションを作成してみる

 PHPでプログラムを組んでいると,時々既存のCのライブラリ関数を使いたくなるわけですが,PECLは敷居が高そうでこれまで調べたことはありませんでした。
 たまたま,PEARのCodeGen_PECLを使うと割と簡単にできるらしい...という話がウエブに載っていたので,以前proj4のエントリで作ったProj.4のpj_fwd関数をPECLのエクステンションにしてみました。

まずはPEAR::CodeGen_PECLのインストール
% pear install -a codegen_pecl

 さっそく定義ファイル(specファイル)の作成。これができればほとんど終了です。
 XMLで概要,リリース情報,configureでチェックする内容,インクルードするファイル,リンクするライブラリ(この場合はlibproj.so)等々を記述し,<function>タグ以下の<code>タグ内(21行目以降)にCのコードを書けば終了です。

1 <?xml version="1.0" ?>
  2 <extension name="proj4" version="1.0.0">
  3     <summary>libproj PHP PECL extension</summary>
  4     <description>libproj PHP PECL extension</description>
  5     <release>
  6      <version>1.0</version>
  7      <date>2008-11-11</date>
  8      <state>alpha</state>
  9      <notes>
10       libproj pj_fwd test.
11      </notes>
12     </release>
13     <deps language="c" platform="unix">
14      <with name="libproj" defaults='/usr:/usr/local' testfile='include/projects.h'>
15       <header name="projects.h" />
16       <lib    name="proj" platform="unix" function="pj_fwd" />
17      </with>
18     </deps>
19     <function name="proj4_pj_fwd">
20      <proto>array proj4_pj_fwd(float u, float v, array params)</proto>
21      <code><![CDATA[
22       //
23       // type check and count.
24       //
25       int num_params = 0;
26       zval** entry = NULL;
27       zend_hash_internal_pointer_reset(params_hash);
28       while (zend_hash_get_current_data(params_hash, (void**)&entry) == SUCCESS) {
29        if (Z_TYPE_PP(entry) == IS_STRING) {
30         num_params++;
31        }
32        else {
33         zval_dtor(return_value);
34         php_error(E_WARNING, "Argument 1 should be a proj parameter strings.");
35         RETURN_FALSE;
36        }
37        zend_hash_move_forward(params_hash);
38       }
39
40       char** str_params = malloc(sizeof(char*) * num_params);
41       if (!str_params) {
42        zval_dtor(return_value);
43        php_error(E_WARNING, "malloc() error.");
44        RETURN_FALSE;
45       }
46
47       int counter = 0;
48       zend_hash_internal_pointer_reset(params_hash);
49       while (zend_hash_get_current_data(params_hash, (void**)&entry) == SUCCESS) {
50        str_params[counter] = Z_STRVAL_PP(entry);
51        zend_hash_move_forward(params_hash);
52        counter++;
53       }
54
55       PJ* proj_param = pj_init(num_params, str_params);
56       if (!proj_param) {
57        zval_dtor(return_value);
58        php_error(E_WARNING, "pj_init() error.");
59
60        if (str_params)
61         free(str_params);
62
63        RETURN_FALSE
64       }
65
66       projUV  idata;
67       idata.u = u * DEG_TO_RAD;
68       idata.v = v * DEG_TO_RAD;
69
70       projUV  odata;
71       odata = pj_fwd(idata, proj_param);
72
73       struct FACTORS factors;
74       if (pj_factors(idata, proj_param, 0.0, &factors)) {
75        zval_dtor(return_value);
76        php_error(E_WARNING, "pj_factors() error.");
77
78        if (proj_param)
79         pj_free(proj_param);
80        if (str_params)
81         free(str_params);
82
83        RETURN_FALSE
84       }
85
86       add_assoc_double(return_value, "ns", odata.u);
87       add_assoc_double(return_value, "ew", odata.v);
88       add_assoc_double(return_value, "areal_scales", factors.s);
89       add_assoc_double(return_value, "convergence",  factors.conv * RAD_TO_DEG);
90       char dms[256];
91       add_assoc_string(return_value, "convergence_dms", rtodms(dms, factors.conv, 0, 0), 1);
92
93       if (proj_param)
94        pj_free(proj_param);
95       if (str_params)
96        free(str_params);
97      ]]></code>
98   </function>
99 </extension>

完成したファイルを保存(proj4.xml)してあとは,

% pecl-gen -f proj4.xml

を実行すると,proj4ディレクトリが作成されます。
以降 proj4ディレクトリ内で

% cd proj4
% phpize
% ./configure --enable-proj4
% make
% sudo make install

でインストール完了。apacheを再起動すれば使えるようになります。

ブラウザでphpinfo()を実行するページを表示すると

Pecl_proj4

と表示されますが,これは先のxmlファイルのタグの情報を表示するようです。
 PHPで使用するコードは以下のような感じです。
  1 <?php
  2     $params = array("proj=tmerc",
  3                            "lat_0=33",
  4                            "lon_0=131",
  5                            "k=0.999900",
  6                            "x_0=0",
  7                            "y_0=0",
  8                            "ellps=GRS80",
  9                            "towgs84=0,0,0,0,0,0,0",
10                           "units=m",
11                           "no_defs");
12
13     $result = proj4_pj_fwd(131.396, 33.20960278, $params);
14
15     echo "NS : " . $result['ns'] . "\n";
16     echo "EW : " . $result['ew'] . "\n";
17     echo "Areal Scales : "    . $result['areal_scales']    . "\n";
18     echo "Convergence : "   . $result['convergence']     . "\n";
19     echo "Convergence : "   . $result['convergence_dms'] . "\n";
20 ?>

といかにも簡単そうに書きましたが,Cのコードの部分はPECLの約束事があるので初めはかなり大変です。ただしなれてしまえば結構手軽に使えるので,重宝しそうです。

以下参考資料です。

リンク: [PHPプロ!] = Do You PHP? =PEAR::CodeGen_PECLを使ってPECLモジュールを作ってみる:CodeZine.

リンク: CodeGen_PECL - PHP エクステンションジェネレータ.

リンク: Hello-PHP-Extension.pdf (application/pdf オブジェクト).

|

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/142859/43086967

この記事へのトラックバック一覧です: PEAR::CodeGen_PECLでPHPのエクステンションを作成してみる:

コメント

コメントを書く