123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- <?php
- // Misc help functions and utilities.
- /**
- * Returns a string of the required length containing random characters. Note that
- * the maximum possible string length is 32.
- *
- * @param int $len Optional. The required length. Default 32.
- * @return string The string.
- */
- function rand_str( $len = 32 ) {
- return substr( md5( uniqid( rand() ) ), 0, $len );
- }
- /**
- * Returns a string of the required length containing random characters.
- *
- * @param int $len The required length.
- * @return string The string.
- */
- function rand_long_str( $length ) {
- $chars = 'abcdefghijklmnopqrstuvwxyz';
- $string = '';
- for ( $i = 0; $i < $length; $i++ ) {
- $rand = rand( 0, strlen( $chars ) - 1 );
- $string .= substr( $chars, $rand, 1 );
- }
- return $string;
- }
- /**
- * Strips leading and trailing whitespace from each line in the string.
- *
- * @param string $txt The text.
- * @return string Text with line-leading and line-trailing whitespace stripped.
- */
- function strip_ws( $txt ) {
- $lines = explode( "\n", $txt );
- $result = array();
- foreach ( $lines as $line ) {
- if ( trim( $line ) ) {
- $result[] = trim( $line );
- }
- }
- return trim( implode( "\n", $result ) );
- }
- /*
- * Helper class for testing code that involves actions and filters.
- *
- * Typical use:
- *
- * $ma = new MockAction();
- * add_action( 'foo', array( &$ma, 'action' ) );
- */
- class MockAction {
- public $events;
- public $debug;
- /**
- * PHP5 constructor.
- */
- function __construct( $debug = 0 ) {
- $this->reset();
- $this->debug = $debug;
- }
- function reset() {
- $this->events = array();
- }
- function current_filter() {
- if ( is_callable( 'current_filter' ) ) {
- return current_filter();
- }
- global $wp_actions;
- return end( $wp_actions );
- }
- function action( $arg ) {
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $args = func_get_args();
- $this->events[] = array(
- 'action' => __FUNCTION__,
- 'tag' => $this->current_filter(),
- 'args' => $args,
- );
- return $arg;
- }
- function action2( $arg ) {
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $args = func_get_args();
- $this->events[] = array(
- 'action' => __FUNCTION__,
- 'tag' => $this->current_filter(),
- 'args' => $args,
- );
- return $arg;
- }
- function filter( $arg ) {
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $args = func_get_args();
- $this->events[] = array(
- 'filter' => __FUNCTION__,
- 'tag' => $this->current_filter(),
- 'args' => $args,
- );
- return $arg;
- }
- function filter2( $arg ) {
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $args = func_get_args();
- $this->events[] = array(
- 'filter' => __FUNCTION__,
- 'tag' => $this->current_filter(),
- 'args' => $args,
- );
- return $arg;
- }
- function filter_append( $arg ) {
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $args = func_get_args();
- $this->events[] = array(
- 'filter' => __FUNCTION__,
- 'tag' => $this->current_filter(),
- 'args' => $args,
- );
- return $arg . '_append';
- }
- function filterall( $tag, ...$args ) {
- // This one doesn't return the result, so it's safe to use with the new 'all' filter.
- if ( $this->debug ) {
- dmp( __FUNCTION__, $this->current_filter() );
- }
- $this->events[] = array(
- 'filter' => __FUNCTION__,
- 'tag' => $tag,
- 'args' => $args,
- );
- }
- // Return a list of all the actions, tags and args.
- function get_events() {
- return $this->events;
- }
- // Return a count of the number of times the action was called since the last reset.
- function get_call_count( $tag = '' ) {
- if ( $tag ) {
- $count = 0;
- foreach ( $this->events as $e ) {
- if ( $e['action'] === $tag ) {
- ++$count;
- }
- }
- return $count;
- }
- return count( $this->events );
- }
- // Return an array of the tags that triggered calls to this action.
- function get_tags() {
- $out = array();
- foreach ( $this->events as $e ) {
- $out[] = $e['tag'];
- }
- return $out;
- }
- // Return an array of args passed in calls to this action.
- function get_args() {
- $out = array();
- foreach ( $this->events as $e ) {
- $out[] = $e['args'];
- }
- return $out;
- }
- }
- // Convert valid XML to an array tree structure.
- // Kinda lame, but it works with a default PHP 4 installation.
- class TestXMLParser {
- public $xml;
- public $data = array();
- /**
- * PHP5 constructor.
- */
- function __construct( $in ) {
- $this->xml = xml_parser_create();
- xml_set_object( $this->xml, $this );
- xml_parser_set_option( $this->xml, XML_OPTION_CASE_FOLDING, 0 );
- xml_set_element_handler( $this->xml, array( $this, 'start_handler' ), array( $this, 'end_handler' ) );
- xml_set_character_data_handler( $this->xml, array( $this, 'data_handler' ) );
- $this->parse( $in );
- }
- function parse( $in ) {
- $parse = xml_parse( $this->xml, $in, true );
- if ( ! $parse ) {
- trigger_error(
- sprintf(
- 'XML error: %s at line %d',
- xml_error_string( xml_get_error_code( $this->xml ) ),
- xml_get_current_line_number( $this->xml )
- ),
- E_USER_ERROR
- );
- xml_parser_free( $this->xml );
- }
- return true;
- }
- function start_handler( $parser, $name, $attributes ) {
- $data['name'] = $name;
- if ( $attributes ) {
- $data['attributes'] = $attributes; }
- $this->data[] = $data;
- }
- function data_handler( $parser, $data ) {
- $index = count( $this->data ) - 1;
- if ( ! isset( $this->data[ $index ]['content'] ) ) {
- $this->data[ $index ]['content'] = '';
- }
- $this->data[ $index ]['content'] .= $data;
- }
- function end_handler( $parser, $name ) {
- if ( count( $this->data ) > 1 ) {
- $data = array_pop( $this->data );
- $index = count( $this->data ) - 1;
- $this->data[ $index ]['child'][] = $data;
- }
- }
- }
- /**
- * Converts an XML string into an array tree structure.
- *
- * The output of this function can be passed to xml_find() to find nodes by their path.
- *
- * @param string $in The XML string.
- * @return array XML as an array.
- */
- function xml_to_array( $in ) {
- $p = new TestXMLParser( $in );
- return $p->data;
- }
- /**
- * Finds XML nodes by a given "path".
- *
- * Example usage:
- *
- * $tree = xml_to_array( $rss );
- * $items = xml_find( $tree, 'rss', 'channel', 'item' );
- *
- * @param array $tree An array tree structure of XML, typically from xml_to_array().
- * @param string ...$elements Names of XML nodes to create a "path" to find within the XML.
- * @return array Array of matching XML node information.
- */
- function xml_find( $tree, ...$elements ) {
- $n = count( $elements );
- $out = array();
- if ( $n < 1 ) {
- return $out;
- }
- for ( $i = 0; $i < count( $tree ); $i++ ) {
- # echo "checking '{$tree[$i][name]}' == '{$elements[0]}'\n";
- # var_dump( $tree[$i]['name'], $elements[0] );
- if ( $tree[ $i ]['name'] === $elements[0] ) {
- # echo "n == {$n}\n";
- if ( 1 === $n ) {
- $out[] = $tree[ $i ];
- } else {
- $subtree =& $tree[ $i ]['child'];
- $out = array_merge( $out, xml_find( $subtree, ...array_slice( $elements, 1 ) ) );
- }
- }
- }
- return $out;
- }
- function xml_join_atts( $atts ) {
- $a = array();
- foreach ( $atts as $k => $v ) {
- $a[] = $k . '="' . $v . '"';
- }
- return implode( ' ', $a );
- }
- function xml_array_dumbdown( &$data ) {
- $out = array();
- foreach ( array_keys( $data ) as $i ) {
- $name = $data[ $i ]['name'];
- if ( ! empty( $data[ $i ]['attributes'] ) ) {
- $name .= ' ' . xml_join_atts( $data[ $i ]['attributes'] );
- }
- if ( ! empty( $data[ $i ]['child'] ) ) {
- $out[ $name ][] = xml_array_dumbdown( $data[ $i ]['child'] );
- } else {
- $out[ $name ] = $data[ $i ]['content'];
- }
- }
- return $out;
- }
- function dmp( ...$args ) {
- foreach ( $args as $thing ) {
- echo ( is_scalar( $thing ) ? (string) $thing : var_export( $thing, true ) ), "\n";
- }
- }
- function dmp_filter( $a ) {
- dmp( $a );
- return $a;
- }
- function get_echo( $callable, $args = array() ) {
- ob_start();
- call_user_func_array( $callable, $args );
- return ob_get_clean();
- }
- // Recursively generate some quick assertEquals() tests based on an array.
- function gen_tests_array( $name, $array ) {
- $out = array();
- foreach ( $array as $k => $v ) {
- if ( is_numeric( $k ) ) {
- $index = (string) $k;
- } else {
- $index = "'" . addcslashes( $k, "\n\r\t'\\" ) . "'";
- }
- if ( is_string( $v ) ) {
- $out[] = '$this->assertEquals( \'' . addcslashes( $v, "\n\r\t'\\" ) . '\', $' . $name . '[' . $index . '] );';
- } elseif ( is_numeric( $v ) ) {
- $out[] = '$this->assertEquals( ' . $v . ', $' . $name . '[' . $index . '] );';
- } elseif ( is_array( $v ) ) {
- $out[] = gen_tests_array( "{$name}[{$index}]", $v );
- }
- }
- return implode( "\n", $out ) . "\n";
- }
- /**
- * Use to create objects by yourself
- */
- class MockClass {};
- /**
- * Drops all tables from the WordPress database
- */
- function drop_tables() {
- global $wpdb;
- $tables = $wpdb->get_col( 'SHOW TABLES;' );
- foreach ( $tables as $table ) {
- // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $wpdb->query( "DROP TABLE IF EXISTS {$table}" );
- }
- }
- function print_backtrace() {
- $bt = debug_backtrace();
- echo "Backtrace:\n";
- $i = 0;
- foreach ( $bt as $stack ) {
- echo ++$i, ': ';
- if ( isset( $stack['class'] ) ) {
- echo $stack['class'] . '::';
- }
- if ( isset( $stack['function'] ) ) {
- echo $stack['function'] . '() ';
- }
- echo "line {$stack[line]} in {$stack[file]}\n";
- }
- echo "\n";
- }
- // Mask out any input fields matching the given name.
- function mask_input_value( $in, $name = '_wpnonce' ) {
- return preg_replace( '@<input([^>]*) name="' . preg_quote( $name ) . '"([^>]*) value="[^>]*" />@', '<input$1 name="' . preg_quote( $name ) . '"$2 value="***" />', $in );
- }
- /**
- * Removes the post type and its taxonomy associations.
- */
- function _unregister_post_type( $cpt_name ) {
- unregister_post_type( $cpt_name );
- }
- function _unregister_taxonomy( $taxonomy_name ) {
- unregister_taxonomy( $taxonomy_name );
- }
- /**
- * Unregister a post status.
- *
- * @since 4.2.0
- *
- * @param string $status
- */
- function _unregister_post_status( $status ) {
- unset( $GLOBALS['wp_post_statuses'][ $status ] );
- }
- function _cleanup_query_vars() {
- // Clean out globals to stop them polluting wp and wp_query.
- foreach ( $GLOBALS['wp']->public_query_vars as $v ) {
- unset( $GLOBALS[ $v ] );
- }
- foreach ( $GLOBALS['wp']->private_query_vars as $v ) {
- unset( $GLOBALS[ $v ] );
- }
- foreach ( get_taxonomies( array(), 'objects' ) as $t ) {
- if ( $t->publicly_queryable && ! empty( $t->query_var ) ) {
- $GLOBALS['wp']->add_query_var( $t->query_var );
- }
- }
- foreach ( get_post_types( array(), 'objects' ) as $t ) {
- if ( is_post_type_viewable( $t ) && ! empty( $t->query_var ) ) {
- $GLOBALS['wp']->add_query_var( $t->query_var );
- }
- }
- }
- function _clean_term_filters() {
- remove_filter( 'get_terms', array( 'Featured_Content', 'hide_featured_term' ), 10, 2 );
- remove_filter( 'get_the_terms', array( 'Featured_Content', 'hide_the_featured_term' ), 10, 3 );
- }
- /**
- * Special class for exposing protected wpdb methods we need to access
- */
- class WpdbExposedMethodsForTesting extends wpdb {
- public function __construct() {
- global $wpdb;
- $this->dbh = $wpdb->dbh;
- $this->use_mysqli = $wpdb->use_mysqli;
- $this->is_mysql = $wpdb->is_mysql;
- $this->ready = true;
- $this->field_types = $wpdb->field_types;
- $this->charset = $wpdb->charset;
- $this->dbuser = $wpdb->dbuser;
- $this->dbpassword = $wpdb->dbpassword;
- $this->dbname = $wpdb->dbname;
- $this->dbhost = $wpdb->dbhost;
- }
- public function __call( $name, $arguments ) {
- return call_user_func_array( array( $this, $name ), $arguments );
- }
- }
- /**
- * Determine approximate backtrack count when running PCRE.
- *
- * @return int The backtrack count.
- */
- function benchmark_pcre_backtracking( $pattern, $subject, $strategy ) {
- $saved_config = ini_get( 'pcre.backtrack_limit' );
- // Attempt to prevent PHP crashes. Adjust lower when needed.
- $limit = 1000000;
- // Start with small numbers, so if a crash is encountered at higher numbers we can still debug the problem.
- for ( $i = 4; $i <= $limit; $i *= 2 ) {
- ini_set( 'pcre.backtrack_limit', $i );
- switch ( $strategy ) {
- case 'split':
- preg_split( $pattern, $subject );
- break;
- case 'match':
- preg_match( $pattern, $subject );
- break;
- case 'match_all':
- $matches = array();
- preg_match_all( $pattern, $subject, $matches );
- break;
- }
- ini_set( 'pcre.backtrack_limit', $saved_config );
- switch ( preg_last_error() ) {
- case PREG_NO_ERROR:
- return $i;
- case PREG_BACKTRACK_LIMIT_ERROR:
- break;
- case PREG_RECURSION_LIMIT_ERROR:
- trigger_error( 'PCRE recursion limit encountered before backtrack limit.' );
- return;
- case PREG_BAD_UTF8_ERROR:
- trigger_error( 'UTF-8 error during PCRE benchmark.' );
- return;
- case PREG_INTERNAL_ERROR:
- trigger_error( 'Internal error during PCRE benchmark.' );
- return;
- default:
- trigger_error( 'Unexpected error during PCRE benchmark.' );
- return;
- }
- }
- return $i;
- }
- function test_rest_expand_compact_links( $links ) {
- if ( empty( $links['curies'] ) ) {
- return $links;
- }
- foreach ( $links as $rel => $links_array ) {
- if ( ! strpos( $rel, ':' ) ) {
- continue;
- }
- $name = explode( ':', $rel );
- $curie = wp_list_filter( $links['curies'], array( 'name' => $name[0] ) );
- $full_uri = str_replace( '{rel}', $name[1], $curie[0]['href'] );
- $links[ $full_uri ] = $links_array;
- unset( $links[ $rel ] );
- }
- return $links;
- }
|