c を使用して Windows で PHP 拡張機能を作成します (暗号化および復号化 PHP ソース コード)
まずは hello world を使ってみます。
php ソース コード パッケージをダウンロードします。ext ディレクトリには、ext_skel と ext_skel_win32.php.
という 2 つの重要なファイルがあります。
cygwin をダウンロードすると、Windows 上で php 拡張機能を簡単に作成できます。
ダウンロード中。 。 。
ダウンロード後、php ext_skel_win32.php --extname=hello を使用してコンパイルし、拡張機能開発ディレクトリ hello
を生成します。
次に、テスト プログラム hello world
の作成を開始します。
hello.c ファイルに関数定義と関数登録ステートメントを追加します:
関数登録ステートメント: const zend_function_entry hello_functions[] = {
?PHP_FE(confirm_hello_compiled, NULL)?
??? PHP_FE(sayHello,NULL)//この文は手動で追加されました
?{NULL、NULL、NULL}
};
関数定義: PHP_FUNCTION(sayHello){
?php_printf("Hello C 拡張機能");
}
Cコードを直接書くと名前の衝突などが起こる可能性があるため、PHP_FUNCTIONのマクロ形式で記述する必要があるようです。
次に、php_hello.h に関数宣言ステートメントを追加します: PHP_FUNCTION(sayHello);
テストプログラムを作成すると、コンパイル結果が表示されます。../main/config.w32.h': No such file or directory
オンラインで確認したところ、追加のパッケージをダウンロードする必要があるようです。 。 。トラブル
http://www.php.net/extra/bindlib_w32.zip
http://www.php.net/extra/win32build.zip
これら 2 つのパッケージをまとめて、win32/build ディレクトリに置きます
次に、php ソース パッケージのルート ディレクトリで buildconf.bat を実行します (コマンド ラインから実行するのが最善です。そうしないと、表示される結果が点滅します)
次に、bison.exe (ダウンロードしたパッケージ内) が配置されているディレクトリを環境変数として設定し、configure.bat を実行します。完了すると、ファイル /main/config.w32.h が生成されます。
その後、Hello プロジェクトを再度コンパイルすると、大きなエラーが表示されます。
形式:....mainstreams/php_stream_transport.h(85): エラー C2143: 構文エラー: '*' の前に ')' がありません
....mainstreams/php_stream_transport.h(85) : エラー C2081: 'socklen_t' : 仮パラメータ リストの名前が不正です
ネット上では、マクロ定義が見つからないために起こると言われていますが、socklen_t マクロが定義されていないはずですが、マクロ定義をそのまま書くことはできません。 ??????? そこで、mainstreams/php_stream_transport.h を開くと、socklen_t addrlen が文字通りストレージの値であるはずなので、型エイリアスである必要があることがわかります。長さ。
したがって、このファイルに typedef int socklen_t; を追加します。
先ほどプロジェクトをコンパイルしたところ、エラーはかなり減りましたが、検査の結果、まだ 7 件のエラーがあり、中国語の記号が入力されていることが判明しました。修正して再度コンパイルします。 。 。別のエラーがあります:
リンク: 致命的なエラー LNK1181: 入力ファイル "php5ts.lib" を開けません
そこで、php5ts.lib ファイルを探し、それをプロジェクト ディレクトリまたは VC6 lib ファイルのデフォルトの検索ディレクトリに置きます。検索して検索してください。 。 。
tmd、Windowsを使用して検索しましたが、長い間見つかりませんでした。 Baidu によると、これは PHP バイナリ コード パッケージに含まれているとのこと。したがって、最初に同じバージョンのバイナリ コード パッケージをダウンロードします (これは、PHP を作成するときにダウンロードする必要があるパッケージである必要があります)
まず環境について話しましょう: Windows+vc6+php5.3.5 (バイナリコードパッケージとソースコードパッケージ)+cygwin
ダウンロードが完了しました。検索、コピー、コンパイル、成功しました。
しかし、非常に重大な問題が発生し、dllファイルが出てこない、、、泣きました
作成されるのはphp_hello.expとphp_hello.libです。どうして静的になるのでしょうか? ?
実際には生成されていますが、このディレクトリの下の Release_TS ディレクトリにはなく、ext の上の Release_TS ディレクトリにあります。
次にテストします。はは、未定義関数と言われていますが、テストした PHP のバージョンと拡張した PHP のバージョンが異なる可能性はありますか?
テスト後、iniにphp_hello.dllをロードしてApacheを再起動すると、メモリが読み取れないというエラーが表示されます。
コードには何も問題はないといつも感じていますが、前の設定とコンパイルに問題があるはずです。
多くのテストを行った結果、PHP バイナリ パッケージが間違ってダウンロードされたことがわかりました。vc6 ではなく vc9 をダウンロードする必要がありました。
?
次に、暗号化と復号化の記述を開始する必要があります。ここでの焦点は、暗号化および復号化アルゴリズム自体ではなく、zend 独自のインターフェイスを c と組み合わせて使用して、zend 層でプログラムし、zend がソース ファイルをコンパイルする前にファイルをコンパイルする方法です。
ファイルを復号化します (もちろん、ファイルが以前に暗号化されていた場合)。使いやすさのために。私のアイデアは、php_screw のような dll を生成するときに、暗号化された実行可能ファイルを生成することです。
ファイルは手動で実行され、ディレクトリパラメータを渡すことで、ディレクトリ内のすべてのファイルを暗号化できます。
ネットで色々調べた結果、php_screwのコードを調べてみましたが、やはり少し難しかったので、自分なりの考えで書いてみることにしました。もちろん、php_screw のコードをいくつかの場所で使用します
最初に、ファイルを復号化する関数を作成します。この関数は、既存の復号化アルゴリズムを使用してファイルの内容を復号化します。
この関数には、現在リクエストされているファイルのハンドルを受け取るためのパラメータが必要です (zend_compile_file、Baidu であるようです。確認してください。いくつかの記事ではこれが関数ポインタであると書かれていました。ソース コードを確認したところ、実際に関数ポインタでした) extern
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle
*file_handle、int 型 TSRMLS_DC);
では、現在要求されているファイルのファイル ポインタを取得するにはどうすればよいでしょうか?おそらく、zend_compile_file 関数ポインタが指す関数と関係があると思われます。ソースコード内に zend_compile_file が見つかりました
=
この関数は zend_ language_scanner.c で定義されていますが、オンラインでは次のように言われています。
-------------
zend_compile_file は、実行されるスクリプト ファイルを ZE の基本命令シーケンスで構成されるオペ コードにコンパイルする役割を果たします。
PHP は、このコードを実行するときに次の 4 つのステップを実行します:
1. スキャン (Lexing)、PHP コードを言語フラグメント (トークン) に変換します
2. トークンを解析し、単純で意味のある式に変換します
3. コンパイル、式を Opocdes
にコンパイルします。
4. 実行。オペコードを一度に 1 つずつ順番に実行し、PHP スクリプトの機能を実現します。
-------------
したがって、これらの 4 つの手順の前にファイルを復号化する必要があります。
このアイデアは、関数 a を書き換えて、コンパイル前にファイルを復号化するかどうかを決定し、その後、デフォルトのコンパイル関数を呼び出すことです。関数 a を定義した後、初期化を要求するときに関数 a を関数ポインター zend_compile_file
に渡す必要があります。
PHP_MINIT_FUNCTION(暗号化){
?old_comlie_file =
zend_complie_file;//後で呼び出せるようにデフォルトのコンパイルを保持します
?zend_complie_file = 関数 a;
?return SUCCESS;
}
ZEND_API zend_op_array *a(zend_file_handle *file_handle,int型
TSRMLS_DC)//TSRMLS_DC は、次のようなマクロです... (マクロの定義はまだ見つかりません) つまり、マルチスレッド環境におけるグローバル変数のスレッド セーフに関連しています。後で入力してください
?コードを復号化します。 。 。
?old_comlie_file(file_handle);
?....
}
しかし、ファイル ポインタを取得する方法がまだわかっていないため、問題はまだ解決されていません。 php_screw の復号化手順は非常に長いようですが、参照してください。 。 。見つかった fp =
fopen(ファイルハンドル->ファイル名,
"r"); file_handle にはファイル名情報が含まれていることがわかります (実際には、file_handle の構造定義ステートメントを見つけるとわかります)。
しかし、php_screw
にはまだそのような段落があります。
char?fname[32];
?if (zend_is_executing(TSRMLS_C))
{//TSRMLS_C はグローバル変数を取得します
??もし
(get_active_function_name(TSRMLS_C))
{//現在呼び出されている関数の名前を取得します (現在呼び出されている関数?関数はどこにありますか?PHP 関数?もちろん、これは zend の関数です。まだコンパイルされていないため、PHP 層の関数ではありません)。単独で実行されます)
???strncpy(fname,
get_active_function_name(TSRMLS_C), fname のサイズ - 2);
??}
?}
?if (fname[0]) {
??if (strcasecmp(fname,
"show_source") == 0//つまり、これら 2 つの関数が現在使用されている場合、それらは復号化またはコンパイルされません。まあ、それは正しいようです。
? ||
strcasecmp(fname, "ハイライト_ファイル") == 0) {
???戻る
NULL;
??}
?}?したがって、このセクションは依然として必要です。そうしないと、上記の 2 つの関数が発生したときに実装されません。このステップも、compile_file 関数に含める必要があります。したがって、ここで重要なのは、暗号化を解読させることではなく、暗号文を直接表示することです。
こんなコーナーもあります
?fp = fopen(ファイルハンドル->ファイル名,
"r");
?if (!fp) {//オープンに失敗した場合は、デフォルトのコンパイル関数を直接呼び出します
??戻る
org_compile_file(file_handle, type);
?}
?if (memcmp(buf, PM9SCREW, PM9SCREW_LEN) != 0)
{
??fclose(fp);
??戻る
org_compile_file(file_handle, type);
?}
?
if (file_handle->type ==
ZEND_HANDLE_FP)
fclose(file_handle->handle.fp);//ファイル ハンドルのタイプを決定し、対応する終了関数を適用します。
?if (ファイルハンドル->タイプ ==
ZEND_HANDLE_FD) close(file_handle->handle.fd);
?
?file_handle->handle.fp =
pm9screw_ext_fopen(fp);//関数を呼び出してファイルを復号化し、file_handle で fp 受信関数を使用して結果を返します
?file_handle->type =
ZEND_HANDLE_FP;//ハンドルタイプをファイルポインタタイプに設定します
?file_handle->opened_path =
Expand_filepath(ファイルハンドル->ファイル名, NULL
TSRMLS_CC);//ここで少し理解できませんが、現在のファイルのパスを受け入れるのでしょうか?私はずっと追跡し、この関数の最後に関数expand_filepath_exを見つけました。
一文はリターンです
real_path; コンパイルする現在のファイルのパスを返す必要があるようです。しかし、なぜ上記の 2 つの手順が必要なのでしょうか?設定タイプとパスです。復号化操作を行わない場合、これは必要ありません
私の推測では、fclose(file_handle->handle.fp) によって file_handle のステータスが変更されるため、リセットする必要があると考えられます。
バー!
//(しかし、1 つの質問は、この復号化はコンパイルの前なのか、それともスキャンの前なのかということです。意味論的に言えば、これはコンパイル前の復号化であると最初は考えています。
前に復号化されましたが、実際の状況からは、Scanning の前に復号化する必要があります。これは、compile_file 関数にペアがあるため、後者が正しいことがわかります。
open_file_for_scanning 関数の呼び出しは、上記の 123 のステップが、compile_file 関数で実行されることを意味します)
エントリーポイントはそこにあります (問題の 3/4 はまだ解決する必要があります)。
次に、ファイルを復号化する関数の作成を開始します
考慮すべき問題は、ファイルを復号した後の平文コードをファイルに書き込む必要がないため、これらの平文のファイル ポインタをどのように取得するかということです。一時ファイルでやるのでしょうか?ただし、各リクエストが異なる一時ファイルを使用する場合、
多数の一時ファイルが生成されます (明らかに現実的ではありません)。同じ php ファイルに対するさまざまなリクエストに 1 つの一時ファイルのみが使用される場合、リソース待機の問題も発生します (明らかに現実的ではありません)。メモリを直接指すことはできますか?
ファイルポインタを設定してみるとどうでしょうか?まず php_screw がどのように行うかを見てみましょう。 tmpfile() を呼び出すと一時ファイルが生成されますが、このファイルはプログラムが終了すると自動的に削除されます。実際にはメモリ内のファイルもそうだと思います
これが仕組みです。
PHP で書かれた可逆暗号化および復号化アルゴリズムを C で実装してみましょう。ただし、C には既製の md5 および Base64 関数がありません。この 2 つは放棄するしかないようです。
書いた後、コンパイルを開始し、発生したいくつかのエラーを修正しました。
その後、リンク中にエラーが発生しました: エラー LNK2001: 未解決の外部シンボル
_zend_compile_file
調べてみると関数のコンパイル方法が違うため関数を追加できないようです
BEGIN_EXTERN_C()
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle
*file_handle、int 型 TSRMLS_DC);
END_EXTERN_C()
以上です
dll ファイルは正常に生成されましたが、暗号化用の実行可能ファイルを生成する方法がわかりません。当然、最も簡単な解決策は別のプロジェクトをビルドすることです。 VCのコンパイルの仕組みやパラメータの設定が一部よく分からないので、最初にこれをやるしかないようです(今後プログラマーの自己啓発を勉強して、これになりそうです)議論しました)
その後、C でのポインターの受け渡しの問題に遭遇しました (長い間やっていなかったため、いくつかの基本を忘れていました。最後に、ポインターをパラメーターとして返す問題を解決するために二次ポインターを使用しました)
また、リンク時に _zend_compile_file シンボルが見つからないという問題にも遭遇しました (zend_api マクロ dllimportdllexport に関連)
実際、ファイルの読み取りと書き込みの問題に遭遇しましたが、ファイルに書き込まれた暗号文を手動で別のファイルにコピーしてテストした場合、結果は間違っています。ファイルを直接操作してから修正してください。
最後に、メモリを読み取れないというエラーが発生しました。 。 。
最終的に、ファイルの読み取り方法に問題があることがわかりました。テキスト モードでの読み取りと書き込みでは、一部の特殊文字が処理されます。
...最終的には、テスト関数は問題ありませんが、実際に適用したい場合は、暗号化したファイルを元のディレクトリに直接生成するなど、改善する必要があります。オリジナルのphpファイルをパッケージ化して管理しやすくします。
次に、zf フレームワークに取り組み始めました。ほとんど忘れていたのですが、まだ使用していないことがたくさんありました。
?
========================================
元のアドレス:
http://blog.sina.com.cn/s/blog_4d06da1f0100pgmj.html
http://blog.sina.com.cn/s/blog_4d06da1f0100pni3.html
?
?
========================================
関連資料:
Windows での PHP C 拡張機能の作成:
http://koda.iteye.com/blog/315779
?
C/C++ で PHP を拡張します:
http://www.laruence.com/2009/04/28/719.html
?
?
C を使用して PHP を自分で拡張する (1)
http://blog.ly5.org/archives/122.html
?
PHP を C で自分で拡張する (2) - 関数
http://blog.ly5.org/archives/123.html
?
C を使用して PHP を自分で拡張する (3) - 重要な ZEND API 関数
http://blog.ly5.org/archives/124.html
?
?
C で PHP 拡張機能を記述する方法
http://www.ej38.com/showinfo/c-php-212877.html
?