How to make an extension for PHP7 harder than “hello, world”, and not become a red-eyed. Part 2

 3r33737. 3r3-31.

Summary of the first part

3r3704.  3r33737. In first part 3r3707. I made a blank of the extension, made it work correctly in IDE Clion, wrote the analog function my_array_fill () and checked its efficiency in php. 3r3704.  3r33737.

Now what?

3r3704.  3r33737. Now I will fill in the library code
in our extension. 3r3704.  3r33737. I’ll tell you a little how you can make old php5 extensions work in php7. 3r3704.  3r33737. Then I will do a few basic functions from this library in php and check what happened. 3r3704.  3r33737. 3r3704.  3r33737. 3r3704.  3r33737. How to make an extension for PHP7 harder than “hello, world”, and not become a red-eyed. Part 2 php_libtrie.c and the library code file 3r33590. libtrie /src /libtrie.c . 3r3704.  3r33737. 3r3633. 3r3704.  3r33737. 3r3704.  3r33737. I will use the last one to check the names and syntax of functions. I will use the same functions in php as in the library itself. 3r3704.  3r33737. First of all, we need to include the header file of the library in the code of our extension. 3r3704.  3r33737. We write in php_libtrie.c:
 3r33737. 3r3704.  3r33737. #include "libtrie /src /libtrie.h"
 3r33737. 3r3704.  3r33737. 3r33464. Function yatrie_new
3r3704.  3r33737. I do the first function that will create a prefix tree. In the library, it is called
 3r33737. 3r3704.  3r33737. 3r3693. 3r33590. trie_s * yatrie_new (uint32_t max_nodes, uint32_t max_refs, uint32_t max_deallocated_size) {}
3r3704.  3r33737. 3r3704.  3r33737. As can be seen from the code, the function takes as input 3 numeric arguments and returns a pointer to the structure 3r3704.  3r33737. 3r33590. trie_s . Simply put, returns a link to the created prefix tree. 3r3704.  3r33737. 3r3704.  3r33737. In order to pull out our prefix tree in PHP, PHP has a special data type called resource. When PHP executes function 3r3704.  3r33737. 3r3693. 3r3669. fopen ("filename.ext"); 3r33737. 3r369595.
3r3704.  3r33737. Speaking in C, the program asks the operating system to open the specified file, creates a pointer to this file, which as a resource and returns to PHP. 3r3704.  3r33737. We will do the same with our tree. 3r3704.  3r33737. Make a function in php_libtrie.c:
 3r33737. 3r3602.
Function code 3r3604.
3r3693. 3r33590. PHP_FUNCTION (yatrie_new) {3r3373718. /* This is a pointer to a tree * /
trie_s * trie; 3r33737. //these are variables for function arguments
zend_long max_nodes; //maximum number of nodes available in our tree
zend_long max_refs; /* maximum number of links in the tree. 3r33737. * The need depends on the density of the words in the tree. The number of nodes + 25% should be enough for any tree. 3r33737. * For example, the dictionary of the Russian language OpenCorpora ~ 3 million. words fit into 5 million. nodes and 5 million. references * /
zend_long max_deallocated_size; /* maximum size of parcels to be freed in the link block 3r3373718. * Depends on the recording density. In total we have 96 bits in the node mask, 1 bit is reserved, 95 remains. 3r33718. * This means that for any node, the memory area in a block of links cannot be greater than 9? which means, 3r-3718. * what is max. the size of the freed reference section cannot be greater than 94. * /
3r33737. //get the arguments from PHP
if (zend_parse_parameters (ZEND_NUM_ARGS (), "lll", & max_nodes, & max_refs, & max_deallocated_size) == FAILURE) {
RETURN_FALSE; 3r33737.}
3r33737. //create a tree and write its address in memory into the pointer created for this
trie = yatrie_new ((uint32_t) max_nodes, (uint32_t) max_refs, (uint32_t) max_deallocated_size); 3r33737. 3r33737. //If We Failed, Finish
if (! trie) {
RETURN_NULL (); 3r33737.}
//2 actions
are performed here. /* the zend_register_resource () function registers a resource in the depths of Zend, 3r-3718. * writes the number of this resource to the global variable le_libtrie, and the macro ZVAL_RES ()
* saves the created resource to zval return_value * /
ZVAL_RES (return_value, zend_register_resource (trie, le_libtrie)); 3r33737.}
3r3704.  3r33737. 3r33714. 3r33714. 3r3704.  3r33737. Now you need to add the created function to the array of extension functions, otherwise the function will not be visible from PHP. 3r3704.  3r33737. 3r3704.  3r33737. 3r3693. 3r33590. PHP_FE (yatrie_new, NULL)
3r3704.  3r33737. 3r3176. 3r3704.  3r33737. To make it quite beautiful, I will add a function declaration to the header file. This is not necessary because our PHP functions do not interact with each other, but I still prefer to declare all the functions in the header file. 3r3704.  3r33737. Just add the lines:
 3r33737. 3r3693. 3r33590. PHP_FUNCTION (confirm_libtrie_compiled); 3r33737. PHP_FUNCTION (my_array_fill); 3r33737. PHP_FUNCTION (yatrie_new); 3r33737. 3r369595.
to the php_libtrie.h file. Somewhere in between:
 3r33737. 3r3693. 3r33590. #ifndef PHP_LIBTRIE_H
and 3r3704.  3r33737. 3r3693. 3r33590. #endif /* PHP_LIBTRIE_H * /
3r3704.  3r33737. 3r3704.  3r33737. 3r3208. 3r3704.  3r33737. 3r3704.  3r33737. 3r33464. the destructor of the created PHP resource
3r3704.  3r33737. The created yatrie_new () function creates a tree and also registers a PHP resource. Now we need a function that will close the created resource and free the memory occupied by the prefix tree. 3r3704.  3r33737. 3r3704.  3r33737. 3r3693. 3r33590. /
* @brief destructor of a resource, it takes as input a pointer to a resource and closes it with 3r-3718. * @param rsrc: zend_resource * pointer
* @return void
* /
static void php_libtrie_dtor (zend_resource * rsrc TSRMLS_DC) {
//here we take a pointer to a trie from the resource 3r33737. trie_s * trie = (trie_s *) rsrc-> ptr; 3r33737. //here is the library function that frees the memory, 3r33718. //selected for trie
yatrie_free (trie); 3r33737.}
3r3704.  3r33737. Since the function is internal to the array of expansion functions, it is not included. I will add her declaration in php_libtrie.h:
 3r33737. 3r3704.  3r33737. 3r3704.  3r33737. 3r3704.  3r33737. Now you need to register the created destructor function in PHP. This is done through a special extension initialization function. Before that, this function simply returned SUCCESS immediately. It is necessary to add registration of destructor there. 3r3704.  3r33737. 3r3704.  3r33737. 3r3693. 3r33590. //Register the destructor of our resource trie
in PHP. PHP_MINIT_FUNCTION (libtrie) {
le_libtrie = zend_register_list_destructors_ex (
NULL, PHP_LIBTRIE_RES_NAME, module_number); 3r33737. return SUCCESS; 3r33737.}
3r3704.  3r33737. 3r3704.  3r33737. Like function 3r33590. fopen () r3r3695. there is a pair of 3r33590. fclose () , and my function of creating a tree should be a friend who will balance it. 3r3704.  3r33737. 3r3704.  3r33737. 3r3602.
Code [/b]
3r3693. 3r33590. /
* @brief Removes a tree from memory
* @param trie: resource
* @return true /false: bool
* /
PHP_FUNCTION (yatrie_free) {
zval * resource; //pointer to zval structure with resource
3r33737. //get the resource type argument r3r3718. if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "r", & resource) == FAILURE) {3r-3718. RETURN_FALSE; 3r33737.}
3r33737. /* here the closing of the resource is called, at the input is taken zend_resource,
* which you first need to get from zval. This makes the macro Z_RES_P ()
* /
if (zend_list_close (Z_RES_P (resource)) == SUCCESS) {
//the macro writes true in return_vale and makes return
RETURN_TRUE; 3r33737.}
//the macro writes false in return_vale and makes return
RETURN_FALSE; 3r33737.}
3r3704.  3r33737. 3r33714. 3r33714. 3r3704.  3r33737. Add a function to the array of extension functions:
 3r33737. 3r3693. 3r33590. PHP_FE (yatrie_free, NULL)
3r3704.  3r33737. 3r3704.  3r33737. I add the function declaration to the header file:
 3r33737. 3r3693. 3r33590. PHP_FUNCTION (yatrie_free); 3r33737. 3r369595.
3r3704.  3r33737. 3r3704.  3r33737. 3r3704.  3r33737. As you can see in the screenshot, I added to the header file the internal name of the resource in PHP, as well as the PHP5 macros, which for some reason were deleted from PHP7. I do not use them, but if someone wants with them, you can easily build a PHP5 extension on PHP7. 3r3704.  3r33737. 3r3704.  3r33737. 3r3693. 3r33590. #define PHP_LIBTRIE_VERSION "???" /* Replace with your extension * /
#define PHP_LIBTRIE_RES_NAME "libtrie data structure" /* PHP resource name * /
3r33737. //previously (php5) used MACROS
#define ZEND_FETCH_RESOURCE (rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type)
(rsrc = (rsrc_type) zend_fetch_resource (Z_RES_P (* passed_id), resource_type_name, resource_type))
#define ZEND_REGISTER_RESOURCE (return_value, result, le_result) ZVAL_RES (return_value, zend_register_resource (result, le_result))
3r3704.  3r33737. 3r3704.  3r33737. 3r33464. The function is to add words to trie
3r3704.  3r33737. Now let's make the function of adding a word to the prefix tree. 3r3704.  3r33737.
 3r33737. 3r33565. 3r3704.  3r33737. 3r3602.
Code [/b]
3r3693. 3r33590. 3r33737. /
* @brief Adds a word to trie and returns the node_id of the last letter of the added word
* @param trie: resource
* @param word: string
* @return node_id: int
* /
PHP_FUNCTION (yatrie_add) {3r3373718. trie_s * trie; //pointer to the tree
zval * resource; //pointer to zval structure with resource
unsigned char * word = NULL; //pointer to the string of the added word
size_t word_len; //word length word
uint32_t node_id; //id of the last node of the added word
3r33737. //get the arguments
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "rs", & resource, & word, & word_len) == FAILURE) {
3r33737. /* get the resource from the depths of PHP, the function takes: 3r3718. * 1 argument is the PHP resource itself (not a zval, but a resource), 3r-3718. * 2 arguments resource name
* I set it through a constant in the header file
* 3 argument is the numeric id of the resource that was assigned when registering the resource
* The function returns a pointer of type void *, so you need to bring it to the correct type trie_s
* In PHP? the macro ZEND_FETCH_RESOURCE () was used in this place, which for some reason was decided to be removed in PHP7. 3r33737. * /
trie = (trie_s *) zend_fetch_resource (Z_RES_P (resource), PHP_LIBTRIE_RES_NAME, le_libtrie); 3r33737. 3r33737. 3r33737. /* add the word to trie
* the first argument is a pointer to the string of the added word
* the second argument is the id of the node from which to start adding, we add
from the root node. * the third argument is a pointer to our tree. 3r33737. * /
node_id = yatrie_add (word, ? trie); 3r33737. 3r33737. //return the numeric value
RETURN_LONG (node_id); 3r33737.}
3r3704.  3r33737. 3r33714. 3r33714. 3r3704.  3r33737. 3r? 3577.  3r33737. 3r33565. I add an entry to the array of functions:
 3r33737. 3r3704.  3r33737. 3r3693. 3r33590. PHP_FE (yatrie_add, NULL)
3r3704.  3r33737. 3r? 3577.  3r33737. 3r33565. Add a declaration to the header file:
 3r33737. 3r3704.  3r33737. 3r3693. 3r33590. PHP_FUNCTION (yatrie_add)
3r3704.  3r33737. 3r? 3577.  3r33737. 3r???. 3r3704.  3r33737. 3r3704.  3r33737. 3r33464. Function output all the words from the dictionary
3r3704.  3r33737. Now we will make a function that will select all words from the prefix tree and output them in PHP as an array. 3r3704.  3r33737. 3r3704.  3r33737.
 3r33737. 3r33565. 3r3704.  3r33737. 3r3602.
Code [/b]
3r3693. 3r33590. /
* @brief bypasses all branches of the tree, starting with the specified node, and outputs all
to the array. * words encountered on your way
* @param trie: resource
* @param node_id: int
* @param head (optional): a string string that will be
* added to the beginning of each found word
* @return array
* /
PHP_FUNCTION (node_traverse) {3r3373718. trie_s * trie; //pointer to trie
words_s * words; //structure for saving words from trie
zval * resource; //pointer to zval resource
zend_long node_id; //start node
unsigned char * head = NULL; //pointer to the string prefix
size_t head_len; //prefix length
3r33737. //get the arguments from PHP
if (zend_parse_parameters (ZEND_NUM_ARGS (), "rl | s", & resource, & node_id, & head, & head_len) == FAILURE) {
RETURN_NULL (); //return null in case of failure
3r33737. //get our tree from
trie = (trie_s *) zend_fetch_resource (Z_RES_P (resource), PHP_LIBTRIE_RES_NAME, le_libtrie); 3r33737. 3r33737. //to save words from trie, the node_traverse () function uses the special structure words_s
//allocate memory for it
words = (words_s *) calloc (? sizeof (words_s)); 3r33737. words-> counter = 0; //set the word count to 0
3r33737. //one more structure is needed to pass the prefix
string_s * head_libtrie = calloc (? sizeof (string_s)); 3r33737. 3r33737. //if the head is set to
if (head! = NULL) {
head_libtrie-> length = (uint32_t) head_len; //set the length to
memcpy (& head_libtrie-> letters, head, head_len); //copy the line to head_libtrie
//now get the words from trie
node_traverse (words, (uint32_t) node_id, head_libtrie, trie); 3r33737. //now create a PHP array, take the size from the word counter in words
array_init_size (return_value, words-> counter); 3r33737. 3r33737. //add words to the php
array. while (words-> counter--) {
//since the letters in trie are stored as codes, you need to decode them
//this is the array for the decoded word
uint8_t dst[256]; 3r33737. //function from libtrie
decode_string (dst, words-> words[words->counter]); 3r33737. 3r33737. //this function is Zend API, which adds to the array an element of type php string of type C char * 3r3187. add_next_index_string (return_value, (const char *) dst); 3r33737.}
//now we need to free up the memory allocated for words and head_libtrie
free (words); 3r33737. free (head_libtrie); 3r33737.}
3r3704.  3r33737. 3r33714. 3r33714. 3r3704.  3r33737. 3r? 3577.  3r33737. 3r33565. I add an entry to the array of functions:
 3r33737. 3r3704.  3r33737. 3r3693. 3r33590. PHP_FE (node_traverse, NULL)
3r3704.  3r33737. 3r? 3577.  3r33737. 3r33565. Add a declaration to the header file:
 3r33737. 3r3704.  3r33737. 3r3693. 3r33590. PHP_FUNCTION (node_traverse)
3r3704.  3r33737. 3r? 3577.  3r33737. 3r???. 3r3704.  3r33737. 3r3704.  3r33737. 3r3653. Build expansion
3r3704.  3r33737. Since the extension now uses files from a third-party library, these files must also be compiled. I open the file config.m4 and add there 2 source files of libtrie:
 3r33737. 3r33590. libtrie /src /libtrie.c
 3r33737. libtrie /src /single_list.c
 3r33737. 3r369595. 3r3704.  3r33737. 3r3704.  3r33737. Here is the full contents of the file after the changes. 3r3704.  3r33737. 3r3602.
config.m4 [/b]
3r3693. PHP_ARG_ENABLE (libtrie, whether to enable libtrie support,
3r33737. if test "$ PHP_LIBTRIE"! = "no"; then
# if you need to include any additional headers
# PHP_ADD_INCLUDE (libtrie /src /)
# key line
Libtrie /src /libtrie.c
Libtrie /src /single_list.c
, $ Ext_shared)
# PHP_NEW_EXTENSION (libtrie, php_libtrie.c libtrie /src /libtrie.c libtrie /src /single_list.c, $ ext_shared ,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE = 1)
fi 3r3373718. 3r369595.
3r3704.  3r33737. 3r33714. 3r33714. 3r3704.  3r33737. 3r3630. 3r3704.  3r33737. 3r3704.  3r33737. Now you need to re-do the ./configure script. Run from the root directory of the extension:
 3r33737. 3r3693. phpize && ./configure
Now I am compiling an extension:
 3r33737. 3r3704.  3r33737. 3r3693. make
3r3704.  3r33737. 3r3653. We are testing
3r3704.  3r33737. For the test, it's best to make a php script so that you don’t have to write a lot to the console I will do this:
 3r33737. 3r3693. nano yatrie_test.php
3r3704.  3r33737. And this is the contents of the file:
 3r33737. 3r3693. 3r3669. 3r3670. echo "Create a tree for 500 nodes and 500 linksnn"; 3r33737. $ trie = yatrie_new (50? 50? 100); 3r33737. echo "Done! n Add words, saving the id of the nodes to the $ nodesn array"; 3r33737. $ nodes[]= yatrie_add ($ trie, "uh"); 3r33737. $ nodes[]= yatrie_add ($ trie, "ear"); 3r33737. $ nodes[]= yatrie_add ($ trie, "ear"); 3r33737. echo "The tree.n
works well here. The first word is of 2 letters, so the last node is 2.n
The second word is of 3 letters, but 2 letters coincide with the first word, n
Therefore, only 1 node is added"; 3r33737. print_r ($ nodes); 3r33737. print_r (node_traverse ($ trie, 0)); 3r33737. yatrie_free ($ trie); 3r33737. 3r369595.
3r3704.  3r33737. 3r3704.  3r33737. Perform in the console:
 3r33737. 3r3693. php -d extension = modules / yatrie_test.php
3r3704.  3r33737. This is what should happen:
 3r33737. 3r33737. 3r3704.  3r33737. 3r3704.  3r33737. The resulting expansion source code take from here . Do not hesitate and put asterisks. :-)
3r33737. 3r33737. 3r33737. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//"""_mediator") () (); 3r33712. 3r33737. 3r33714. 3r33737. 3r33737. 3r33737. 3r33737.
+ 0 -

Comments 3

Ross Alisha
Ross Alisha 12 November 2018 09:39
Pretty much all screen capture plugins can take screenshots of a whole page. I am using Nimbus but they can pretty much all do it. With Nimbus, you can select between capturing the whole page, only the visible part or a selected area ... then you can edit it if you need (crop it, blur some parts, add arrows to point something, add texts, circle things, etc...). I really recommend it instead of the one you talked about in the article.


Alisha Ross
Alisha Ross 14 January 2019 11:12
I would add three adds into the most useful:
1) Like everyone said an Ad Blocker, I like ABP only because it was the first one I've used and never run into any issue.
2) Disconnect, it will block any Analytics, Advertisement, or Social features within a webpage.
3) I would change Pocket for Google Keep. My logic behind it, is if people are using chrome, they probably are using a google account. Google Keep is a note keeping, tracking and filtering made by Google. It can be accessed via Web, Android or iPhone and with the extension all it takes is a click and it will add your page as a note into it.
Victoria Tegg
Victoria Tegg 22 January 2019 11:11
Here to pay tribute to the hacking spirit! This is a really nice skill to learn. I imagine it is possible to use the developer console in chrome to just download some data table from a website? Sometimes they are separated by pages. Anyway I'm fairly comfortable with Python, how can I improve my JS skills to get to a point where I can treat any webpage as something hackable? Any recommendations for JS tutorial / class to catch up with you back in 2019?

<a href=""> </a>

Add comment