ほとんどの PHP エンジニアは、PHP の C コードコアがどのように機能するかを知る必要はありませんが、dl() 関数の存在や、この記事の焦点の 1 つであるサードパーティのライブラリを使用したことがあるという人もいるでしょう。
この記事が、PHP をより広い範囲に広げたいと考えているエンジニアに役立つことを願っています。
まず、php リクエストの実行プロセスを見てみましょう:
ブラウザ ユーザー ---> Web サーバー (Apache、nginx) ---> Zend エンジンがファイル システムから php コード ファイルを読み取る ---> Zend インタープリターが動作
--->解釈されたコードを実行します-->Zend エンジンによって登録された関数インターフェース-->組み込みモジュールまたは必要な外部モジュール拡張機能-->データベース memcache などのバックエンド リソース
その中には
Zendエンジンが登録する関数インターフェースは、PHPエンジニアがよく触れる様々なPHP関数です
外部モジュールの拡張子はさまざまです。PHP でコンパイルされた so ファイル (linux) または dll ファイル (windwos) です。
解釈されたコードを実行すると、ブラウザのコンテンツがここから返されます。
組み込みモジュールはphpを起動するたびに起動されるモジュールです
上記のフローチャートから、php は 1 外部モジュールの拡張 2 Zend エンジン 3 組み込みモジュールの 3 つのポイントから拡張できることがわかります。以下で 1 つずつ説明します。
外部モジュール拡張機能
dl() を使用したことがある場合、外部拡張モジュール ファイルは、php スクリプトの実行中にメモリにロードされ、必要な場合にのみロードされます。
このスクリプトは実行が終了するとメモリから解放されますが、一般に実行速度は遅くなりますが、PHP を再コンパイルする必要はありません。
内蔵モジュール
これも Zend エンジンの外部のモジュールですが、すでに PHP に組み込まれているため、変更がある場合は PHP を再コンパイルする必要があります。モジュール内で
が作成されます
PHP のメモリは大きくなりますが、呼び出しも高速になります。テストでは、一部のモジュールは組み込みモードで実行すると 30% 以上速度が向上します。
ゼンドエンジン
まず、ZEND エンジンを変更することは絶対にお勧めしません。たとえば、配列のキーワードの名前を変更したい場合は、PHP 言語の一部の特性を実現できます。ここで気づいてください。
ダウンロードしたphpのソースコードのうち、zendで始まる部分がzendエンジンに関係するコードです
一般的な PHP ソース コードのディレクトリ構造は次のようになります:
メインphpのメインソースコード
ext php 拡張子
さまざまなサーバーを使用した SAPI インタラクション レイヤー コード
ゼンド ゼンド エンジンパーツ
TSRM スレッド セーフティ関連モジュール コード
以下では、例として単純なモジュールを使用して、PHP をどのように拡張できるかを示します:
まず第一に、PHP コードには独自の標準セットがあり、これに従う必要があります。これを遵守しないと、モジュールが変数を解放できなくなったり、その他の問題が発生したりする可能性があります。これらの標準には、マクロ定義、変数宣言などが含まれます。公式ウェブサイトで詳細な手順を参照してください。
/* 拡張標準ヘッダー */
#include "php.h"
/* これでエクスポートされる関数を宣言します */
/* Zend エンジンによって登録された関数インターフェース */
zend_function_entry helloworldmod_interfaces[] =
{
ZEND_FE(helloworld_module, NULL)
{ヌル、ヌル、ヌル}
};
/* これはこのモジュールの宣言エンティティであり、その値はモジュールのコンパイルに実際の影響を与えます */
zend_module_entry helloworldmod_module_entry =
{
STANDARD_MODULE_HEADER、
「ハローワールド」
Helloworldmod_interfaces さん、
ヌル、
ヌル、
ヌル、
ヌル、
ヌル、
NO_VERSION_YET、
STANDARD_MODULE_PROPERTIES
};
/* zend エンジンへの登録を宣言します。これにより、helloworldmod_module_entry がダイナミック ライブラリ helloworldmod.so*/
に属していることを示すことができます。
#if COMPILE_DL_helloworld_module
ZEND_GET_MODULE(helloworldmod)
#endif
/* これは新しい関数の実際のコードです */
ZEND_FUNCTION(helloworld_module)
{
「Hello,world」を返します;
他の拡張 config.m4 ファイルに基づいて、必要なコンパイル構成情報に変更できます。このモジュールは、ほぼ空の config.m4 ファイルです
次に、phpize を使用して構成ファイルを生成し、./configure && make && make install を実行して動的ライブラリのコピーをコンパイルします
test.php
エコー helloworld_module();
?>
出力:
「ハロー、ワールド」
PHP 拡張機能の完成後、PHP の C コードの内部を深く掘り下げましたが、場合によってはこれでは十分ではありません。 C 言語で C ライブラリを呼び出すプロセスを深く掘り下げる必要があります。Linux の非常に強力なツールは、LD_PRELOAD 環境変数です
。
LD_PRELOAD 環境変数は、プログラム内で参照される関数またはグローバル変数の場所を見つけるためのコンパイラーのフィルターです。たとえば、PHP の C コードでネットワーク接続を開始するためのメソッド connect の呼び出しは、実際には動的リンクを通じて行われます
。
Linux C ライブラリの関数 connect を探します。これらのリンク ファイルは通常、lib の下に配置されます。これは、PHP のコード実行に影響を与えるためのエントリ ポイントでもあります。 PHP プログラムは関数を動的にロードする前に LD_PRELOAD をチェックするため、lib の下に接続します
提供されているダイナミック ライブラリにはこの接続機能がありますか? ここで PHP の動作を妨げることができます。
以下は、実装方法を示すネットワーク アクセスのフィルタリングの簡単な例です:
まず、LD_PRELOAD 環境変数の値として so ファイルを準備するコードがあります。
lp_demo.c
#include
#include
#include
#include
#include
#include
//独自の接続関数を定義します
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t
アドレスレン){
static int (*connect_linuxc)(int, const struct sockaddr*, socklen_t)=NULL;
unsigned char *ip_char;
// lsym の RTLD_NEXT オプションを使用して、LD_PRELOAD 環境変数の connect メソッドをバイパスし、C ライブラリの関数を見つけます
if (!connect_linuxc) connect_linuxc=dlsym(RTLD_NEXT,"connect");
ip_char=serv_addr->sa_data;
ip_char+=2;
//192.168.2.3 が見つかりました
If ((*ip_char==192)&&(*(ip_char+1)==168)&&(*(ip_char+2)==2)&&(*(ip_char+3)==3)) {
//単にパーミッションエラーコードを返すだけです
return EACCES;
}
// 実際の connect メソッドを呼び出します
戻り connect_linuxc(sockfd,serv_addr,addrlen);
}
soファイルにコンパイルします
$ gcc -o lp_demo.so -shared lp_demo.c -ldl
テストファイルtest.php
file_get_contents("http://192.168.2.3/");
?>
使い方
LD_PRELOAD=lp_demo.so php test.php
このようにして、彼は 192.168.2.3 などの内部 URL にアクセスできなくなります。優れたサンドボックスとして機能します。
さらに、fwrite fopen などの関数を使用して、ファイル システム上の PHP の読み取りおよび書き込み操作を mencache や nosql などのバックエンド リソースに転送することもできます。
最後に、C ライブラリの内部を深く掘り下げたとしても、C ライブラリの下には sys_ で始まる関数がたくさんあります。それらは実際の関数です。カーネル空間についてはこれ以上説明しません。
。