-1

私が取り組んでいるプラグインでは、PHP擬似コードのJSONブロックを実行する機能を提供したいと思います。バックエンドPHPがJSONを解析し、その中で疑似コードを実行できるように、JSONが特別に形成される方法を設計する必要があることに気付きました。

JavaScriptに存在するため、サーバーに送信される前の問題のJSONブロックは次のとおりです。

var codeBlock = {
    opts: 
    [
        {
            http: {
                method: "GET",
                header: "Accept-language: en\r\n" +
                        "Cookie: foo=bar\r\n"
            }
        }
    ],
    context: 
    {
        stream_context_create: ['opts']
    },
    contents: 
    {
        file_get_contents: ['http://www.YourDomain.com/', false, 'context']
    },
    html: 
    {
        htmlentities: ['contents']
    }
}

上記のコードブロックでは、PHPに呼び出したいことを伝えていますfile_get_contents$optsそのためには、に渡されるという名前のオプション配列を定義する必要がありますstream_context_create。から返さstream_context_createれる結果は、という名前の変数に格納されます$contentsfile_get_contents次に、から返された結果を。という名前の変数に格納します$contents。最後に、返されたデータをからfile_get_contents変数に変換します$html

もちろん開始するには、JSONをサーバーに送信する単純なハンドラーを作成する必要があります。

最も重要なのは、結果を解析してデータを送り返すためのバックエンド関数を作成する必要があることです。

問題は、オープンエンドのコンテキスト(PHP関数の呼び出しとコードの可能なシーケンスが渡される可能性がある場合)でこれをどのように行うことができるかということです。

4

1 に答える 1

1

JSON「エンコードされた」PHPのこの動的な解析と実行を処理する主な機能は次のとおりです。基本的に、JSONを解析して、変数の指定を順番に識別します。PHPオブジェクトに出くわすと、その中にPHP関数呼び出しが存在することがわかります。関数のパラメーターの配列を反復処理して文字列「ポインター」を探し、それをそれらのポインター値に置き換えます。ポインターは、関数呼び出しへのパラメーターとして送信する必要がある、JSONで以前に定義された変数への単なる参照です。新しいパラメーター配列が作成されたら、それらのパラメーターを使用して要求された関数を呼び出し、その結果をその関数オブジェクト変数定義に戻します。ここで、別の関数呼び出しの引数として使用される場合と使用されない場合があります。

/**
 * Iterates over an array containing PHP and handles calls to enabled functions and executes them.
 * @param {phpObj} array A JSON decoded array of representational PHP.
 * @return {*} Will return the results of the last function call passed in through phpObj.
 */
function parse_php_object( $arr, $config ) {

    // We define a pointer array that contains reference names to parameter placeholders
    // that will be replaced by real data.
    $pointers = array();

    foreach ( $arr as $k => $v ) {

        // Create variable definition with our first level array keys
        ${$k} = $v;

        // Populate our pointers index
        $pointers[$k] = $k;

        // When a value is an object we attempt to call functions defined within
        if ( is_object( ${$k} ) ) {

            // Convert our function object to an array
            $funcArr = (Array)${$k};

            // Use the first key of the function array as our function name to call
            $func_name = array_keys($funcArr);
            $func_name = $func_name[0];

            // Get the array of arguments to parse to our arguments array
            $func_args = $funcArr[$func_name];

            // Create an array to store the arguments to pass to our function call
            $args_arr = array();

            // Now we iterate over our function arguments looking for reference strings
            foreach ( $func_args as $arg ) {

                // We compare against the keys in our pointers index which was created above
                if ( array_key_exists( $arg, $pointers ) ) {

                    // This is now a reference to ${$k}, the originally defined definition, the returned
                    // result of the last sucessful function call
                    $p = ${$arg};

                    // We push our arguments onto the args_array which will be passed to our function call
                    array_push( $args_arr, $p );

                } else {

                    // We push our arguments onto the args_array which will be passed to our function call
                    array_push( $args_arr, $arg );
                }
            }


            // Based on the security mode selected, use either our blacklist or whitelist.
            switch ( $config['SEC_MODE'] ) {
                case 'blacklist' :
                    if ( function_exists( $func_name ) 
                         && !in_array( $func_name, $config['LISTS']['blacklist'] ) ) {
                        $function_allowed = true;
                    } else {
                        $function_allowed = false;
                    }
                    break;

                case 'whitelist' :
                    if ( function_exists( $func_name ) 
                         && in_array( $func_name, $config['LISTS']['whitelist'] ) ) {
                        $function_allowed = true;
                    } else {
                        $function_allowed = false;
                    }
                    break;
            }

            // Call the requested function if permitted
            if ( $function_allowed === true ) {

                // Reassign our variable the returned value of a function call so that further function calls can
                // search for the existence of pointers and then use the updated variable definitions. This logic
                // takes advantage of the procedural nature of PHP and the order of the sub-blocks in the php object. 
                ${$k} = call_user_func_array( $func_name, $args_arr );
            } else {
                return ("Function you requested $func_name has been disabled by backend configuration.");
            }
        }

        // When we're not an object we're something else like an array, string, int, etc. If we're an array we need
        // to recursively iterate over ourselves to convert any objects into arrays.
        else {  
            if ( is_array( ${$k} ) ) {
                array_walk_recursive( ${$k}, 'object_to_array' );
            }
        }

    }

    // Return the returned result from our final function call
    return ${$k};
}

/**
 * Converts PHP objects to arrays by typecasting.
 * @param {object} Object A self referencing PHP object.
 */
function object_to_array( &$object ) {
    if ( is_object( $object ) ) {
        (Array)$object;
    }
}

コマンドの決定は渡されたデータのタイプに基づいて行われるため、この方法では反射パターンが使用されていると思います。さらに、これは、関数の処理インターフェースを特別に定義する必要なしに、多数のAJAXベースのプロジェクトで使用できます。

もちろん、結果をクライアントに送り返す前に、型チェック、セキュリティテスト、JSONエンコーディングを実行するコードは他にもありますが、上記の関数が大部分の処理を実行します。

于 2013-01-04T15:57:15.767 に答える