Translation [PHP extension development and Embedded] chapter 19th-setting up the hosting environment

Source: Internet
Author: User
Tags php language php framework sapi zts hosting


Setting up the hosting environment

Now that you know the world of Phpapi and can do a lot of work with Zval and the language internals, it's time to move the target and do what it does best: explain the scripting code.

Embedded SAPI

In retrospect, PHP builds a hierarchical system. The top tier is all extensions that provide user-space functions and class libraries. At the same time, it is the service API (SAPI) layer, which acts as an interface for webserver (such as Apache, IIS, and the command-line interface CLI).

In this many SAPI implementations there is a special SAPI that is embedded SAPI. When this SAPI implementation is built, a library object containing all of the PHP and Zend API functions and variables you know is created, and the Library object contains additional helper functions and macros to simplify the invocation of external programs.

The libraries that build the embedded API and the header files perform the same actions as the compilation of the other Sapi. You only need to pass--enable-embed to the./configure command. As before, using--enable-debug is helpful for error reporting and tracking.

You may also need to open--enable-maintainer-zts, of course, for reasons you've already heard, and it will help you notice the error of the code, but there are other reasons. Suppose at some point that you have multiple apps that use PHP to perform script tasks; One of the applications is a simple short life cycle, and it does not use threads, so for efficiency you may want to turn off Zts.

Now assume that the second application uses a thread, such as webserver, that each thread needs to keep track of its request context. If Zts is turned off, only the first application can use the library; However, if Zts is turned on, two apps can use the same shared object in their own process space.

Of course, you can also build two versions at the same time and give them different names, but this has more to do with the small efficiencies that include zts than when you don't need zts.

By default, the embedded library will be built as a libphp5.so shared object, or a dynamic-link library under Windows, but it may also be built as a static library using the optional Static keyword (--enable-embed=static).

The version built as a static library avoids zts/non-zts problems and the potential for multiple versions of PHP in a system. The risk is that this means that your results will be significantly larger by applying binary, which will host the entire zendengine and PHP framework, so when you choose, you need to think carefully about whether you need a relatively small library.

No matter how you choose to build it, once you execute make install, LIBPHP5 will be copied to your./configure in the lib/directory specified by the prefix directory. A header file named Php_embed.h is also placed in the Prefix/include/php/sapi/embed directory, along with several other important header files that you need to compile the program using the PHP embedded library.

Build and compile a host app

In essence, a library is simply a collection of code with no purpose. To make it work, you need an app that embeds PHP. First, let's encapsulate a very simple application that starts the Zend engine and initializes PHP to process a request, then goes back to the cleanup of resources.

#include <sapi/embed/php_embed.h>int main (int argc, char *argv[]) {    php_embed_start_block (ARGC,ARGV)    Php_embed_end_block ()    return 0;}


Since this involves a lot of header files, it usually takes time for the build to actually take longer than such a small snippet. If you are using a different prefix than the default path (/usr/local), verify that the path is specified in the following way:

Gcc-i/usr/local/php-dev/include/php/\-i/usr/local/php-dev/include/php/main/\-i/usr/local/php-dev/include/php/ zend/\-i/usr/local/php-dev/include/php/tsrm/\-lphp5 \-o embed1 embed1.c

Since this command is cumbersome to input every time, you may prefer to use a simple makefile instead:

CC = gcc CFLAGS =-c \    -i/usr/local/php-dev/include/php/\    -i/usr/local/php-dev/include/php/main/\    -i/usr /local/php-dev/include/php/zend/\    -i/usr/local/php-dev/include/php/tsrm/\    -wall-gldflags =-lphp5all: EMBED1.C    $ (cc)-O embed1.o embed1.c $ (CFLAGS)    $ (cc)-O embed1 embed1.o $ (ldflags)

There are some important differences between this makefile and the commands provided earlier. First, it opens the compile-time warning with the-wall switch and opens the debug message with-G. In addition, it divides the compilation and linking phases into two separate phases, which makes it relatively easy to add more source files at a later stage. Please re-group this makefile, but it is used to align tab (horizontal tab) instead of space.

Now that you've made changes to the embed1.c source file, you can build a new embed1 executable simply by executing a make command.

Re-create the CLI by embedding the wrapper

Now that PHP can be accessed in your app, it's time to let it do something. The rest of this chapter is centered around recreating the CLI SAPI in this test application framework.

Very simply, the most basic function of the CLI binaries is to specify the name of a script on the command line, which is interpreted by PHP to execute. Replacing the contents of your embed1.c with the following code implements the CLI in your application.

#include <stdio.h> #include <sapi/embed/php_embed.h>int main (int argc, char *argv[]) {    Zend_file_ handle    script;    /* Basic Parameter Check *    /if (argc <= 1) {        fprintf (stderr, "Usage:%s <filename.php> <arguments>\n", argv[0]) ;        return-1;    }        /* Set a file processing structure */    script.type             = zend_handle_fp;    Script.filename         = argv[1];    Script.opened_path      = NULL;    Script.free_filename    = 0;    if (! ( SCRIPT.HANDLE.FP = fopen (Script.filename, "RB")) {        fprintf (stderr, "Unable to open:%s\n", argv[1]);        return-1;    }        /* When registering a command-line argument with PHP ($argv/$argc in PHP), ignore the first command-line argument because it has no meaning for PHP scripts/    argc-;    argv + +;        Php_embed_start_block (argc, argv)        php_execute_script (&script tsrmls_cc);    Php_embed_end_block ()        return 0;}

The original code in the translator's environment can not directly run, the above code is modified.

Of course, you need a file to test it, create a small php script, name it test.php, and use your embed program on the command line to execute it:

$./embed1 test.php

If you pass other arguments to the command line, you can see them in your PHP script using $_server[' argc ']/$_server[' argv '.

You may have noticed that the code between Php_embed_start_block () and Php_embed_end_block () is indented. This detail is because these two macros actually form the code block scope of a C language. That is, Php_embed_start_block () contains an open curly brace "{", and in Php_embed_end_block () there is a closing curly brace "}" corresponding to it. One of the important problems with this is that they cannot be put into separate start/stop functions. In the next chapter you will see a solution to this problem.

New use of old technology

After Php_embed_start_block () is called, your application is at the beginning of a PHP request cycle, which is equivalent to the Rinit callback function after completion. You can now execute the php_execute_script () command, or any other Php/zend API directive that can appear in the php_function () or Rinit () block, as before.

Set Initial variables

The 2nd chapter describes the concept of manipulating symbol tables in the "inside and outside of variables", and the 5th to 18th chapter describes how to use these techniques with user-space scripts to invoke internal functions. There are no changes to the processing here, although there is no active user space script, but your wrapper application can still manipulate the symbol table. Replace your Php_embed_start_block ()/php_embed_end_block () code block with the following code:

    Php_embed_start_block (argc, argv)        zval    *type;        Alloc_init_zval (type);        Zval_string (Type, "Embedded", 1);        Zend_set_symbol (&eg (symbol_table), "type", type);                Php_execute_script (&script tsrmls_cc);    Php_embed_end_block ()

Now rebuild the embed1 with make and test it with the following test script:

<?phpvar_dump ($type);? >

Of course, this simple concept can easily be extended to populate this type of information into the $_SERVER Super global variable array.

    Php_embed_start_block (argc, argv)        zval    **server_pp, *type;        /* Register $_SERVER Super Global variable *        /Zend_is_auto_global_quick ("_server", sizeof ("_server")-1, 0 tsrmls_cc);        /* Find $_server Super global variable */        Zend_hash_find (&eg (symbol_table), "_server", sizeof ("_server"), (void * *) &server_ PP);        /* $_server[' sapi_type '] = "Embedded"; *        /Alloc_init_zval (type);        Zval_string (Type, "Embedded", 1);        Zend_set_symbol (Z_ARRVAL_PP (SERVER_PP), "Sapi_type", TYPE);        Php_execute_script (&script tsrmls_cc);    Php_embed_end_block ()

Translator's environment in the Code run to Zend_hash_find () $_server has not been registered, after tracking, found that it is not until the user space code compiled, found that user space using the $_server variable to register. Therefore, the above code adds the Zend_is_auto_global_quick () call, which will complete the registration of the $_server.

Overwrite INI option

In the 13th chapter "INI Settings", there is a part of the INI modification processor, where you see the INI phase of processing. The Php_embed_start_block () macro puts the code in the run-time phase. This means that it is a bit late to modify certain settings (such as REGISTER_GLOBALS/MAGIC_QUOTES_GPC).

But there's nothing wrong with internal access. The so-called "management settings" such as Safe_mode can be turned on or off using the following zend_alter_ini_entry () command at this slightly later stage:

int Zend_alter_ini_entry (char *name, uint name_length,                         char *new_value, uint new_value_length,                         int Modify_type , int stage);

The meaning of name, New_value, and their corresponding length parameter is as you would expect: The value of the INI setting named name is modified to New_value. Note that name_length contains the null byte at the end, whereas New_value_length is not included; However, in any case, two strings must be null-terminated.

The Modify_type provides simplified access control checks. Review each INI setting has a modifiable property, which is a combined value of Php_ini_system, Php_ini_perdir, Php_ini_user, and so on. When you modify the INI setting by using Zend_alter_ini_entry (), the Modify_type parameter must contain at least one INI-set modifiable property value.

The Ini_set () function of the user space takes advantage of this feature by passing php_ini_user, which means that only the modifiable property contains the INI setting of the php_ini_user tag in order to use this function modification. When using this API call in your embedded application, you can short-circuit the access control system by passing the Php_ini_all tag, which will contain all the INI access levels.

The stage must correspond to the current state of the Zend engine; For these simple embedded examples, always php_ini_stage_runtime. If this is an extended or higher-end embedded application, you may need to set this value to Php_ini_stage_startup or php_ini_stage_active.

The following is an extension of the embed1.c source file, which forces the Safe_mode to open before executing the script file.

    Php_embed_start_block (argc, argv)        zval    **server_pp, *type;        /* Regardless of how the settings in PHP.ini are forced to open Safe_mode *        /Zend_alter_ini_entry ("Safe_mode", sizeof ("Safe_mode"), "1", sizeof ("1")-1, Php_ini_all, php_ini_stage_runtime);                /* Register $_SERVER Super Global variable *        /Zend_is_auto_global_quick ("_server", sizeof ("_server")-1, 0 tsrmls_cc);        /* Find $_server Super global variable */        Zend_hash_find (&eg (symbol_table), "_server", sizeof ("_server"), (void * *) &server_ PP);                /* $_server[' sapi_type '] = "Embedded"; *        /Alloc_init_zval (type);        Zval_string (Type, "Embedded", 1);        Zend_set_symbol (Z_ARRVAL_PP (SERVER_PP), "Sapi_type", TYPE);                Php_execute_script (&script tsrmls_cc);    Php_embed_end_block ()

Defining additional super-global variables

In the 12th chapter "Start, Terminate, and some of these points", you know that the user space global variables and the super global variables can be defined at the start (minit) stage. Similarly, this chapter describes the embedded directly skipping the startup phase, at run time. and overwrite INI, this does not seem too late.

The definition of a super global variable actually needs to be defined only before the script is compiled, and it should only occur once during the PHP process life cycle. Under normal circumstances in the extension, Minit is the only place where these conditions can be guaranteed.

Since your wrapper application is now in control, you can guarantee that the points that define the automatic global variables for user space are located before the Php_execute_script () command that actually compiles the script source files. We define a $_embed super global variable and set it to an initial value for testing:

    Php_embed_start_block (argc, argv) zval **server_pp, *type, *embed, *foo;        /* Create $_embed array in global scope */Alloc_init_zval (EMBED);        Array_init (EMBED);        Zend_set_symbol (&eg (symbol_table), "_embed", EMBED); /* $_embed[' foo '] = ' Bar ';        */Alloc_init_zval (foo);         Zval_string (foo, "Bar", 1);        ADD_ASSOC_ZVAL_EX (EMBED, "foo", sizeof ("foo"), foo);  /* Register SUPER global variable $_embed */Zend_register_auto_global ("_embed", sizeof ("_embed") #ifdef zend_engine_2, 1, NULL TSRMLS_CC), #else, 1 tsrmls_cc), #endif/* Force on Safe_mode */zend_alter_ini_entry regardless of php.ini settings ("        Safe_mode ", sizeof (" Safe_mode ")," 1 ", sizeof (" 1 ")-1, Php_ini_all, php_ini_stage_runtime);        /* Register $_SERVER SUPER global variable */Zend_is_auto_global_quick ("_server", sizeof ("_server")-1, 0 TSRMLS_CC);  /* Find $_server Super global variable */zend_hash_find (&eg (symbol_table), "_server", sizeof ("_server"), (void * *) &server_pp)        ; /* $_server[' sapi_type '] = "Embedded";        */Alloc_init_zval (type);         Zval_string (Type, "Embedded", 1);        Zend_set_symbol (Z_ARRVAL_PP (SERVER_PP), "Sapi_type", TYPE);    Php_execute_script (&script tsrmls_cc); Php_embed_end_block ()

Keep in mind that Zend Engine 2 (PHP 5.0 or higher) uses a different zend_register_auto_global () element, so you'll need to use the #ifdef mentioned in the previous PHP 4 compatibility. If you don't care about the compatibility of older versions of PHP, you can discard the instructions to make the code neater.

Summary

As you can see, it takes less work to embed the full Zend engine and PHP language into your app than to extend new functionality. Because they share the same underlying API, we can learn to try to make other instances accessible.

With this chapter, you learned the simplest format for embedded scripting code, along with All-in-one macros Php_ebed_start_block () and Php_embed_end_block (). In the next chapter you will go back to the use of these macro layers and use them to combine PHP with your hosting system.

The above is [translation][php extended development and embedded] Chapter 19th-Set up the contents of the hosting environment, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.