Matching a search with a regex and four context lines

For example, I have a code like this:

<?php /** * Order * * The WooCommerce order class handles order data. * * @class WC_Order * @version 1.6.4 * @package WooCommerce/Classes * @category Class * @author WooThemes */ class WC_Order { /** @public int Order (post) ID */ public $id; /** @public string Order status. */ public $status; /** @public string Order date (placed). */ public $order_date; /** @public string Order date (paid). */ public $modified_date; /** @public string Note added by the customer. */ public $customer_note; /** @public array Order (post) meta/custom fields. */ public $order_custom_fields; global $wpdb, $woocommerce; if ( empty( $type ) ) $type = array( 'line_item' ); if ( ! is_array( $type ) ) $type = array( $type ); $items = $this->get_items( $type ); $count = 0; foreach ( $items as $item ) { if ( ! empty( $item['qty'] ) ) $count += $item['qty']; else $count ++; } return apply_filters( 'woocommerce_get_item_count', $count, $type, $this ); } /** * Return an array of fees within this order. * * @access public * @return array */ public function get_fees() { return $this->get_items( 'fee' ); } /** * Return an array of taxes within this order. * * @access public * @return void */ public function get_taxes() { return $this->get_items( 'tax' ); } /** * Get taxes, merged by code, formatted ready for output. * * @access public * @return void */ public function get_tax_totals() { $taxes = $this->get_items( 'tax' ); $tax_totals = array(); foreach ( $taxes as $key => $tax ) { $code = $tax[ 'name' ]; if ( ! isset( $tax_totals[ $code ] ) ) { $tax_totals[ $code ] = new stdClass(); $tax_totals[ $code ]->amount = 0; } $tax_totals[ $code ]->is_compound = $tax[ 'compound' ]; $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ]; $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ]; $tax_totals[ $code ]->formatted_amount = woocommerce_price( $tax_totals[ $code ]->amount ); } return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ); } /** * has_meta function for order items. * * @access public * @return array of meta data */ public function has_meta( $order_item_id ) { global $wpdb; return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d ORDER BY meta_key,meta_id", absint( $order_item_id ) ), ARRAY_A ); } /** * Get order item meta. * * @access public * @param mixed $item_id * @param string $key (default: '') * @param bool $single (default: false) * @return void */ public function get_item_meta( $order_item_id, $key = '', $single = false ) { return get_metadata( 'order_item', $order_item_id, $key, $single ); } 

I want to combine all Wordpress hooks: "do_action" and "apply_filters" with three parameters: apply_filters ('woocommerce_order_tax_totals', $ tax_totals, $ this), file, line number

An example of what I'm trying to do can be seen here: http://etivite.com/api-hooks/buddypress/trigger/apply_filters/bp_get_total_mention_count_for_user/

http://adambrown.info/p/wp_hooks/hook/activated_plugin?version=3.6&file=wp-admin/includes/plugin.php

I tried to pull something, but without success:

 <?php $path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder'; foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) { if (substr($filename, -3) == 'php') { $file = file($filename); if ($file !== false) { $matches1 = preg_grep( '/do_action\((.+)\);/', $file); $matches2 = preg_grep( '/apply_filters\((.+)\);/', $file ); $arr = array_filter(array_merge($matches1, $matches2)); $out = ''; echo "found in $filename:"; echo "<pre>"; foreach ($arr as $key => $value) { $out .= $file[$key-2]; $out .= $file[$key-1]; $out .= $file[$key]; $out .= $file[$key+1]; $out .= $file[$key+2]; } echo htmlentities($out); echo "</pre>"; } else { echo "failed reading to array"; } } } 
+4
source share
3 answers

This can be done very simply using the built-in shell commands.

 <?php $path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder'; foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) { if (substr($filename, -3) == 'php') { $context = shell_exec('grep -H -n -C4 do_action ' . escapeshellarg($filename)); if (!empty($context)) { echo "found in $filename:"; echo "<pre>"; echo htmlentities($context); echo "</pre>"; } else { echo "failed reading to array"; } } } 

Relevant documentation:

php shell_exec

Run the command through the shell and return the full output as a string

php escapeshellarg

Print string to be used as shell argument

bash grep

  Grep searches the named input FILEs (or standard input if no files are named, or the file name - is given) for lines containing a match to the given PATTERN. By default, grep prints the matching lines. -C NUM, --context=NUM Print NUM lines of output context. Places a line containing -- between contiguous groups of matches. -H, --with-filename Print the filename for each match. -n, --line-number Prefix each line of output with the line number within its input file. 

Edit

Depending on how many directories and files you have in your project, it may be inefficient. You basically create a new process in a new shell for each file. This is not great. If you prefer to get a large data dump and analyze it later, do this instead:

 <?php $path = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/plugins/iphorm-form-builder'; $grep = shell_exec('grep --include=*.php -RHn -C4 do_action ' . escapeshellarg($path)); $matches = explode("\n--\n", $grep); if (empty($matches)) { echo "failed reading to array"; } else { foreach ($matches as $match) { echo "<pre>"; echo htmlentities($match); echo "</pre>"; } } 
+1
source

You do not need to cycle through the file data line by line. Just read the data in the variable and apply regex:

 $data = file_get_contents( $filename ); if (preg_match_all( '~((?:[^\n]*\n){0,4}) *do_action\s*\(\s*([^)]+)\s*\)\s*;[^\n]*\n((?:[^\n]*\n){0,4})~', $data, $arr)) { // match found, now dump the results // $arr[1] will print 4 lines before the match // $arr[2] will print function arguments for do_action // $arr[3] will print 4 lines after the match print_r($arr); } 
0
source

This cannot be done only with regular expressions, given the limitations of the PHP regular expression mechanism. In particular, and this came as a surprise to me, you cannot have an appearance of variable length.

The reason you need to peek is if you had do_action or apply_filters appear in consecutive lines, then the first match will prevent the second match if you did not look ahead, and even if you use perspective, there is no way to get the previous two lines second match without appearance. Not to mention that I don’t even know if you can even include the content of the look around the statement as a result.

This solution creates a regular expression to find the strings in which this function occurs, and then uses two more regular expressions to search for strings before and after. I tried to keep track of the beginning and end of the file when developing regular expressions.

 $offset = 0; while (preg_match('/^.*?(?:apply_filters|do_action)\s*\(.+?\)\s*;.*(?:\n\r|\n|\r|$)/m', $file, $match, PREG_OFFSET_CAPTURE, $offset)) { $index = $match[0][1]; $offset = $index + strlen($match[0][0]); $hasBefore = preg_match('/(?:.*(?:\n\r|\n|\r).*$)|[^\n\r].*$/', substr($file, 0, $index), $beforeMatch); $hasAfter = preg_match('/^(?:.*(?:\n\r|\n|\r|$)){0,2}/', substr($file, $offset), $afterMatch); if ($hasBefore) print_r($beforeMatch); print_r($match[0][0]); if ($hasAfter) print_r($afterMatch); } 

phpFiddle

This displays only two lines before and two lines after. You can use repetition if you want more, but it seems to me that this is an attempt, that this is what about .p. really wanted to.

0
source

Source: https://habr.com/ru/post/1501640/


All Articles