From 6d64a3747b6543c6009c0f1de46f973549ee1570 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sat, 19 Mar 2022 19:44:51 +0100 Subject: [PATCH 001/184] first draft of new 3.0 branch with the basic bootstrapping project and build processes --- .editorconfig | 22 + .eslintrc | 20 + .eslintrc.json | 21 - .gitignore | 4 + .stylelintrc.json | 6 - antispam_bee.php | 3080 +---------- composer.json | 22 +- composer.lock | 8171 ------------------------------ css/dashboard.css | 19 - css/styles.css | 265 - inc/columns.class.php | 160 - inc/gui.class.php | 573 --- js/dashboard.js | 112 - js/raphael.helper.js | 140 - js/raphael.min.js | 3 - js/scripts.js | 20 - lib/Helpers/AssetsLoader.php | 91 + lib/load.php | 29 + package.json | 39 +- phpcs.xml | 128 +- src/backend.js | 1 + src/backend.scss | 1 + src/images/icons/filter.svg | 1 + src/images/icons/share-nodes.svg | 1 + src/images/icons/sliders.svg | 1 + webpack.config.js | 44 + 26 files changed, 410 insertions(+), 12564 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc delete mode 100644 .eslintrc.json mode change 100755 => 100644 antispam_bee.php delete mode 100644 composer.lock delete mode 100644 css/dashboard.css delete mode 100644 css/styles.css delete mode 100644 inc/columns.class.php delete mode 100644 inc/gui.class.php delete mode 100644 js/dashboard.js delete mode 100644 js/raphael.helper.js delete mode 100644 js/raphael.min.js delete mode 100644 js/scripts.js create mode 100644 lib/Helpers/AssetsLoader.php create mode 100644 lib/load.php create mode 100644 src/backend.js create mode 100644 src/backend.scss create mode 100644 src/images/icons/filter.svg create mode 100644 src/images/icons/share-nodes.svg create mode 100644 src/images/icons/sliders.svg create mode 100644 webpack.config.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..79207a40 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 4 + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..6379d068 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,20 @@ +{ + "extends": [ + "plugin:@wordpress/eslint-plugin/recommended" + ], + "env": { + "browser": true + }, + "rules": { + "max-len": [ + "error", + { + "code": 160 + } + ], + "prettier/prettier": 0 + }, + "parserOptions": { + "requireConfigFile": false + } +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 782125e7..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "plugin:@wordpress/eslint-plugin/es5", - "env": { - "browser": true, - "jquery": true - }, - "globals": { - "Raphael": "readonly", - "getAnchors": "readonly" - }, - "rules": { - "camelcase": 0, - "eqeqeq": 0, - "no-mixed-operators": 0, - "no-redeclare": 0, - "no-shadow": 0, - "no-unused-expressions": 0, - "no-unused-vars": 0, - "vars-on-top": 0 - } -} diff --git a/.gitignore b/.gitignore index 0436199f..35f41dba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,16 @@ +*.css.map css/*.min.css js/*.min.js .idea/ +build/ node_modules/ tmp/ vendor/ chromedriver +composer.lock driver.tar.gz driver.zip geckodrier nohup.out package-lock.json +yarn.lock diff --git a/.stylelintrc.json b/.stylelintrc.json index 68e038b0..829a7dcf 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,11 +1,5 @@ { "extends": "@wordpress/stylelint-config", "rules": { - "declaration-property-unit-allowed-list": null, - "font-weight-notation": null, - "font-family-no-missing-generic-family-keyword": null, - "no-descending-specificity": null, - "selector-class-pattern": null, - "selector-id-pattern": null } } diff --git a/antispam_bee.php b/antispam_bee.php old mode 100755 new mode 100644 index 008c0060..6af04132 --- a/antispam_bee.php +++ b/antispam_bee.php @@ -1,3041 +1,87 @@ 0, - ), - '', - 'no' - ); - - if ( self::get_option( 'cronjob_enable' ) ) { - self::init_scheduled_hook(); - } - } - - - /** - * Action to deactivate the plugin - * - * @since 0.1 - * @since 2.4 - */ - public static function deactivate() { - self::clear_scheduled_hook(); - } - - - /** - * Action deleting the plugin - * - * @since 2.4 - */ - public static function uninstall() { - if ( ! self::get_option( 'delete_data_on_uninstall' ) ) { - return; - } - global $wpdb; - - delete_option( 'antispam_bee' ); - $wpdb->query( 'OPTIMIZE TABLE `' . $wpdb->options . '`' ); - - //phpcs:disable WordPress.DB.PreparedSQL.NotPrepared - $sql = 'delete from `' . $wpdb->commentmeta . '` where `meta_key` IN ("antispam_bee_iphash", "antispam_bee_reason")'; - $wpdb->query( $sql ); - //phpcs:enable WordPress.DB.PreparedSQL.NotPrepared - } - - - - /* - * ############################ - * ######## INTERNAL ######## - * ############################ - */ - - /** - * Initialization of the internal variables - * - * @since 2.4 - * @since 2.7.0 - * @since 2.10.0 Change renamed country option names in options array - */ - private static function _init_internal_vars() { - self::$_base = plugin_basename( __FILE__ ); - - $salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : ABSPATH; - self::$_salt = substr( sha1( $salt ), 0, 10 ); - - self::$defaults = array( - 'options' => array( - 'regexp_check' => 1, - 'spam_ip' => 1, - 'already_commented' => 1, - 'gravatar_check' => 0, - 'time_check' => 0, - 'ignore_pings' => 0, - - 'dashboard_chart' => 0, - 'dashboard_count' => 0, - - 'country_code' => 0, - 'country_denied' => '', - 'country_allowed' => '', - - 'translate_api' => 0, - 'translate_lang' => array(), - - 'bbcode_check' => 1, - - 'flag_spam' => 1, - 'email_notify' => 0, - 'no_notice' => 0, - 'cronjob_enable' => 0, - 'cronjob_interval' => 0, - - 'ignore_filter' => 0, - 'ignore_type' => 0, - - 'reasons_enable' => 0, - 'ignore_reasons' => array(), - - 'delete_data_on_uninstall' => 1, - ), - 'reasons' => array( - 'css' => esc_attr__( 'Honeypot', 'antispam-bee' ), - 'time' => esc_attr__( 'Comment time', 'antispam-bee' ), - 'empty' => esc_attr__( 'Empty Data', 'antispam-bee' ), - 'localdb' => esc_attr__( 'Local DB Spam', 'antispam-bee' ), - 'server' => esc_attr__( 'Fake IP', 'antispam-bee' ), - 'country' => esc_attr__( 'Country Check', 'antispam-bee' ), - 'bbcode' => esc_attr__( 'BBCode', 'antispam-bee' ), - 'lang' => esc_attr__( 'Comment Language', 'antispam-bee' ), - 'regexp' => esc_attr__( 'Regular Expression', 'antispam-bee' ), - 'title_is_name' => esc_attr__( 'Identical Post title and blog title', 'antispam-bee' ), - 'manually' => esc_attr__( 'Manually', 'antispam-bee' ), - ), - ); - } - - /** - * Check and return an array key - * - * @since 2.4.2 - * @since 2.10.0 Only return `null` if option does not exist. - * - * @param array $array Array with values. - * @param string $key Name of the key. - * @return mixed Value of the requested key. - */ - public static function get_key( $array, $key ) { - if ( empty( $array ) || empty( $key ) || ! isset( $array[ $key ] ) ) { - return null; - } - - return $array[ $key ]; - } - - /** - * Check if comment is a ping (pingback, trackback or something similar) - * - * @since 2.10.0 - * - * @param array $comment Treated commentary data. - * @return boolean `true` if ping and `false` if classic comment - */ - public static function is_ping( $comment ) { - $types = array( 'pingback', 'trackback', 'pings' ); - $is_ping = false; - - if ( in_array( self::get_key( $comment, 'comment_type' ), $types, true ) ) { - $is_ping = true; - } - - return apply_filters( 'antispam_bee_is_ping', $is_ping, $comment ); - } - - /** - * Localization of the admin pages - * - * @since 0.1 - * @since 2.4 - * - * @param string $page Mark the page. - * @return boolean True on success. - */ - private static function _current_page( $page ) { - // phpcs:disable WordPress.CSRF.NonceVerification.NoNonceVerification - switch ( $page ) { - case 'dashboard': - return ( empty( $GLOBALS['pagenow'] ) || ( ! empty( $GLOBALS['pagenow'] ) && 'index.php' === $GLOBALS['pagenow'] ) ); - - case 'options': - return ( ! empty( $_GET['page'] ) && 'antispam_bee' === $_GET['page'] ); - - case 'plugins': - return ( ! empty( $GLOBALS['pagenow'] ) && 'plugins.php' === $GLOBALS['pagenow'] ); - - case 'admin-post': - return ( ! empty( $GLOBALS['pagenow'] ) && 'admin-post.php' === $GLOBALS['pagenow'] ); - - case 'edit-comments': - return ( ! empty( $GLOBALS['pagenow'] ) && 'edit-comments.php' === $GLOBALS['pagenow'] ); - - default: - return false; - } - // phpcs:enable WordPress.CSRF.NonceVerification.NoNonceVerification - } - - - /** - * Integration of the localization file - * - * @since 0.1 - * @since 2.4 - */ - public static function load_plugin_lang() { - load_plugin_textdomain( - 'antispam-bee' - ); - } - - - /** - * Add the link to the settings - * - * @since 1.1 - * - * @param array $data The action link array. - * @return array $data The action link array. - */ - public static function init_action_links( $data ) { - if ( ! current_user_can( 'manage_options' ) ) { - return $data; - } - - return array_merge( - $data, - array( - sprintf( - '%s', - add_query_arg( - array( - 'page' => 'antispam_bee', - ), - admin_url( 'options-general.php' ) - ), - esc_attr__( 'Settings', 'antispam-bee' ) - ), - ) - ); - } - - /** - * Meta links of the plugin - * - * @since 0.1 - * @since 2.6.2 - * - * @param array $input Existing links. - * @param string $file Current page. - * @return array $data Modified links. - */ - public static function init_row_meta( $input, $file ) { - if ( $file !== self::$_base ) { - return $input; - } - - return array_merge( - $input, - array( - '' . esc_html__( 'Donate', 'antispam-bee' ) . '', - '' . esc_html__( 'Support', 'antispam-bee' ) . '', - ) - ); - } - - /* - * ############################ - * ####### RESOURCES ######## - * ############################ - */ - - /** - * Registration of resources (CSS & JS) - * - * @since 1.6 - * @since 2.4.5 - */ - public static function init_plugin_sources() { - $plugin = get_plugin_data( __FILE__ ); - - wp_register_script( - 'ab_script', - plugins_url( 'js/scripts.min.js', __FILE__ ), - array( 'jquery' ), - $plugin['Version'] - ); - - wp_register_style( - 'ab_style', - plugins_url( 'css/styles.min.css', __FILE__ ), - array( 'dashicons' ), - $plugin['Version'] - ); - } - - - /** - * Initialization of the option page - * - * @since 0.1 - * @since 2.4.3 - */ - public static function add_sidebar_menu() { - $page = add_options_page( - 'Antispam Bee', - 'Antispam Bee', - 'manage_options', - 'antispam_bee', - array( - 'Antispam_Bee_GUI', - 'options_page', - ) - ); - - add_action( - 'admin_print_scripts-' . $page, - array( - __CLASS__, - 'add_options_script', - ) - ); - - add_action( - 'admin_print_styles-' . $page, - array( - __CLASS__, - 'add_options_style', - ) - ); - - add_action( - 'load-' . $page, - array( - __CLASS__, - 'init_options_page', - ) - ); - } - - - /** - * Initialization of JavaScript - * - * @since 1.6 - * @since 2.4 - */ - public static function add_options_script() { - wp_enqueue_script( 'ab_script' ); - } - - - /** - * Initialization of Stylesheets - * - * @since 1.6 - * @since 2.4 - */ - public static function add_options_style() { - wp_enqueue_style( 'ab_style' ); - } - - - /** - * Integration of the GUI - * - * @since 2.4 - */ - public static function init_options_page() { - require_once dirname( __FILE__ ) . '/inc/gui.class.php'; - } - - - - /* - * ############################ - * ####### DASHBOARD ######## - * ############################ - */ - - /** - * Display the spam counter on the dashboard - * - * @since 0.1 - * @since 2.6.5 - * - * @param array $items Initial array with dashboard items. - * @return array $items Merged array with dashboard items. - */ - public static function add_dashboard_count( $items = array() ) { - if ( ! current_user_can( 'manage_options' ) || ! self::get_option( 'dashboard_count' ) ) { - return $items; - } - - echo ''; - - $items[] = '' . esc_html( - sprintf( - // translators: The number of spam comments Antispam Bee blocked so far. - __( '%s Blocked', 'antispam-bee' ), - self::_get_spam_count() - ) - ) . ''; - - return $items; - } - - /** - * Initialize the dashboard chart - * - * @since 1.9 - * @since 2.5.6 - */ - public static function add_dashboard_chart() { - if ( ! current_user_can( 'publish_posts' ) || ! self::get_option( 'dashboard_chart' ) ) { - return; - } - - wp_add_dashboard_widget( - 'ab_widget', - 'Antispam Bee', - array( - __CLASS__, - 'show_spam_chart', - ) - ); - - add_action( - 'admin_head', - array( - __CLASS__, - 'add_dashboard_style', - ) - ); - } - - /** - * Print dashboard styles - * - * @since 1.9.0 - * @since 2.5.8 - */ - public static function add_dashboard_style() { - $plugin = get_plugin_data( __FILE__ ); - - wp_register_style( - 'ab_chart', - plugins_url( 'css/dashboard.min.css', __FILE__ ), - array(), - $plugin['Version'] - ); - - wp_print_styles( 'ab_chart' ); - } - - - /** - * Print dashboard scripts - * - * @since 1.9.0 - * @since 2.5.8 - */ - public static function add_dashboard_script() { - if ( ! self::get_option( 'daily_stats' ) ) { - return; - } - - $plugin = get_plugin_data( __FILE__ ); - - wp_enqueue_script( - 'raphael', - plugins_url( 'js/raphael.min.js', __FILE__ ), - array(), - '2.1.0', - true - ); - - wp_enqueue_script( - 'ab-raphael', - plugins_url( 'js/raphael.helper.min.js', __FILE__ ), - array( 'raphael' ), - $plugin['Version'], - true - ); - - wp_enqueue_script( - 'ab_chart_js', - plugins_url( 'js/dashboard.min.js', __FILE__ ), - array( 'jquery', 'ab-raphael' ), - $plugin['Version'], - true - ); - } - - /** - * Print dashboard html - * - * @since 1.9.0 - * @since 2.5.8 - */ - public static function show_spam_chart() { - $items = (array) self::get_option( 'daily_stats' ); - - if ( empty( $items ) ) { - echo sprintf( - '

%s

', - esc_html__( 'No data available.', 'antispam-bee' ) - ); - - return; - } - - self::add_dashboard_script(); - - ksort( $items, SORT_NUMERIC ); - - $html = "\n"; - - $html .= "\n"; - foreach ( $items as $date => $count ) { - $html .= '\n"; - } - $html .= "\n"; - - $html .= "\n"; - foreach ( $items as $date => $count ) { - $html .= '\n"; - } - $html .= "\n"; - - $html .= "
' . date_i18n( 'j. F Y', $date ) . "
' . (int) $count . "
\n"; - - echo wp_kses_post( '
' . $html . '
' ); - } - - /* - * ############################ - * ######## OPTIONS ######### - * ############################ - */ - - /** - * Get all plugin options - * - * @since 2.4 - * @since 2.6.1 - * - * @return array $options Array with option fields. - */ - public static function get_options() { - $options = wp_cache_get( 'antispam_bee' ); - if ( ! $options ) { - wp_cache_set( - 'antispam_bee', - $options = get_option( 'antispam_bee' ) - ); - } - - if ( null === self::$defaults ) { - self::_init_internal_vars(); - } - - return wp_parse_args( - $options, - self::$defaults['options'] - ); - } - - /** - * Get single option field - * - * @since 0.1 - * @since 2.4.2 - * - * @param string $field Field name. - * @return mixed Field value. - */ - public static function get_option( $field ) { - $options = self::get_options(); - - return self::get_key( $options, $field ); - } - - - /** - * Update single option field - * - * @since 0.1 - * @since 2.4 - * - * @param string $field Field name. - * @param mixed $value The Field value. - */ - private static function _update_option( $field, $value ) { - self::update_options( - array( - $field => $value, - ) - ); - } - - - /** - * Update multiple option fields - * - * @since 0.1 - * @since 2.6.1 - * - * @param array $data Array with plugin option fields. - */ - public static function update_options( $data ) { - $options = get_option( 'antispam_bee' ); - - if ( is_array( $options ) ) { - $options = array_merge( - $options, - $data - ); - } else { - $options = $data; - } - - update_option( - 'antispam_bee', - $options - ); - - wp_cache_set( - 'antispam_bee', - $options - ); - } - - - - /* - * ############################ - * ######## CRONJOBS ######## - * ############################ - */ - - /** - * Execution of the daily cronjobs - * - * @since 0.1 - * @since 2.4 - */ - public static function start_daily_cronjob() { - if ( ! self::get_option( 'cronjob_enable' ) ) { - return; - } - - self::_update_option( - 'cronjob_timestamp', - time() - ); - - self::_delete_old_spam(); - } - - - /** - * Delete old spam comments - * - * @since 0.1 - * @since 2.4 - */ - private static function _delete_old_spam() { - $days = (int) self::get_option( 'cronjob_interval' ); - - if ( empty( $days ) ) { - return false; - } - - global $wpdb; - - $wpdb->query( - $wpdb->prepare( - "DELETE c, cm FROM `$wpdb->comments` AS c LEFT JOIN `$wpdb->commentmeta` AS cm ON (c.comment_ID = cm.comment_id) WHERE c.comment_approved = 'spam' AND SUBDATE(NOW(), %d) > c.comment_date_gmt", - $days - ) - ); +function antispam_bee_pre_init() { + // Load the translation, as they might be needed in pre_init. + add_action( 'plugins_loaded', 'antispam_bee_load_textdomain' ); - $wpdb->query( "OPTIMIZE TABLE `$wpdb->comments`" ); - } - - - /** - * Initialization of the cronjobs - * - * @since 0.1 - * @since 2.4 - */ - public static function init_scheduled_hook() { - if ( ! wp_next_scheduled( 'antispam_bee_daily_cronjob' ) ) { - wp_schedule_event( - time(), - 'daily', - 'antispam_bee_daily_cronjob' - ); - } - } - - - /** - * Deletion of the cronjobs - * - * @since 0.1 - * @since 2.4 - */ - public static function clear_scheduled_hook() { - if ( wp_next_scheduled( 'antispam_bee_daily_cronjob' ) ) { - wp_clear_scheduled_hook( 'antispam_bee_daily_cronjob' ); - } - } - - - - /* - * ############################ - * ###### SPAM CHECK ######## - * ############################ - */ - - /** - * Check POST values - * - * @since 0.1 - * @since 2.6.3 - */ - public static function precheck_incoming_request() { - // phpcs:disable WordPress.Security.NonceVerification.Missing - if ( is_feed() || is_trackback() || empty( $_POST ) || self::_is_mobile() ) { - return; - } - - $request_uri = self::get_key( $_SERVER, 'REQUEST_URI' ); - $request_path = self::parse_url( $request_uri, 'path' ); - - if ( strpos( $request_path, 'wp-comments-post.php' ) === false ) { - return; - } - - $post_id = (int) self::get_key( $_POST, 'comment_post_ID' ); - $hidden_field = self::get_key( $_POST, 'comment' ); - $plugin_field = self::get_key( $_POST, self::get_secret_name_for_post( $post_id ) ); - - if ( ! empty( $hidden_field ) ) { - $_POST['ab_spam__hidden_field'] = 1; - } else { - $_POST['comment'] = $plugin_field; - unset( $_POST[ self::get_secret_name_for_post( $post_id ) ] ); - } - // phpcs:enable WordPress.Security.NonceVerification.Missing - } - - - /** - * Check incoming requests for spam - * - * @since 0.1 - * @since 2.6.3 - * @since 2.10.0 Refactoring of code if pings are allowed and if is ping - * - * @param array $comment Untreated comment. - * @return array $comment Treated comment. - */ - public static function handle_incoming_request( $comment ) { - $comment['comment_author_IP'] = self::get_client_ip(); - - $request_uri = self::get_key( $_SERVER, 'REQUEST_URI' ); - $request_path = self::parse_url( $request_uri, 'path' ); - - if ( empty( $request_path ) ) { - return self::_handle_spam_request( - $comment, - 'empty' - ); - } - - $pings_allowed = ! self::get_option( 'ignore_pings' ); - - // phpcs:disable WordPress.Security.NonceVerification.Missing - // Everybody can post. - if ( strpos( $request_path, 'wp-comments-post.php' ) !== false && ! empty( $_POST ) ) { - // phpcs:enable WordPress.Security.NonceVerification.Missing - $status = self::_verify_comment_request( $comment ); - - if ( ! empty( $status['reason'] ) ) { - return self::_handle_spam_request( - $comment, - $status['reason'] - ); - } - } elseif ( self::is_ping( $comment ) && $pings_allowed ) { - $status = self::_verify_trackback_request( $comment ); - - if ( ! empty( $status['reason'] ) ) { - return self::_handle_spam_request( - $comment, - $status['reason'], - true - ); - } - } - - return $comment; - } - - /** - * Prepares the replacement of the comment field with output buffering. - * - * @since 2.10.0 - */ - public static function prepare_comment_field_output_buffering() { - if ( is_feed() || is_trackback() || is_robots() || self::_is_mobile() ) { - return; - } - - ob_start( - array( - 'Antispam_Bee', - 'prepare_comment_field', - ) - ); - } - - - /** - * Prepares the replacement of the comment field - * - * @since 0.1 - * @since 2.4 - * @since 2.10.0 Changes needed because of new way to add the honeypot field via filter instead of output buffering - * - * @param string $data Markup of the comment field or whole page (depending on ob option). - */ - public static function prepare_comment_field( $data ) { - if ( empty( $data ) ) { - return $data; - } + // Check, if the min. required PHP version is available and if not, show an admin notice. + if ( version_compare( PHP_VERSION, '7.2', '<' ) ) { + add_action( 'admin_notices', 'antispam_bee_min_php_version_error' ); - if ( ! preg_match( '# (?# match the whole textarea tag ) - '; - - $output .= $id_script; - $output .= $init_time_field; - - return $output; } + // If all checks were successful, load the plugin. + require_once ANTISPAM_BEE_PATH . 'lib/load.php'; +} - /** - * Check the trackbacks - * - * @since 2.4 - * @since 2.7.0 - * - * @param array $comment Trackback data. - * @return array Array with suspected reason. - */ - private static function _verify_trackback_request( $comment ) { - $ip = self::get_key( $comment, 'comment_author_IP' ); - $url = self::get_key( $comment, 'comment_author_url' ); - $body = self::get_key( $comment, 'comment_content' ); - $post_id = self::get_key( $comment, 'comment_post_ID' ); - $type = self::get_key( $comment, 'comment_type' ); - $blog_name = self::get_key( $comment, 'comment_author' ); - - if ( empty( $url ) || empty( $body ) ) { - return array( - 'reason' => 'empty', - ); - } - - if ( empty( $ip ) ) { - return array( - 'reason' => 'empty', - ); - } - - if ( 'pingback' === $type && self::_pingback_from_myself( $url, $post_id ) ) { - return; - } - - if ( self::is_trackback_post_title_blog_name_spam( $body, $blog_name ) ) { - return array( - 'reason' => 'title_is_name', - ); - } - - $options = self::get_options(); +/** + * Load plugin textdomain. + * + * @since 1.0.0 + */ +function antispam_bee_load_textdomain() { + load_plugin_textdomain( 'antispam-bee', false, basename( dirname( __FILE__ ) ) . '/languages' ); +} - if ( $options['bbcode_check'] && self::_is_bbcode_spam( $body ) ) { - return array( - 'reason' => 'bbcode', - ); - } +/** + * Show a admin notice error message, if the PHP version is too low + */ +function antispam_bee_min_php_version_error() { + echo '

'; + esc_html_e( 'Antispam Bee requires PHP version 7.2 or higher to function properly. Please upgrade PHP or deactivate Antispam Bee.', 'antispam-bee' ); + echo '

'; +} - if ( $options['spam_ip'] && self::_is_db_spam( $ip, $url ) ) { - return array( - 'reason' => 'localdb', - ); - } - - if ( $options['country_code'] && self::_is_country_spam( $ip ) ) { - return array( - 'reason' => 'country', - ); - } - - if ( $options['translate_api'] && self::_is_lang_spam( $body ) ) { - return array( - 'reason' => 'lang', - ); - } - - if ( $options['regexp_check'] && self::_is_regexp_spam( - array( - 'ip' => $ip, - 'rawurl' => $url, - 'host' => self::parse_url( $url, 'host' ), - 'body' => $body, - 'email' => '', - 'author' => '', - ) - ) ) { - return array( - 'reason' => 'regexp', - ); - } - } - - /** - * Check, if I pinged myself. - * - * @since 2.8.2 - * - * @param string $url The URL from where the ping came. - * @param int $target_post_id The post ID which has been pinged. - * - * @return bool - */ - private static function _pingback_from_myself( $url, $target_post_id ) { - - if ( 0 !== strpos( $url, home_url() ) ) { - return false; - } - - $original_post_id = (int) url_to_postid( $url ); - if ( ! $original_post_id ) { - return false; - } - - $post = get_post( $original_post_id ); - if ( ! $post ) { - return false; - } - - $urls = wp_extract_urls( $post->post_content ); - $url_to_find = get_permalink( $target_post_id ); - if ( ! $url_to_find ) { - return false; - } - foreach ( $urls as $url ) { - if ( strpos( $url, $url_to_find ) === 0 ) { - return true; - } - } - return false; - } - - /** - * Check the comment - * - * @since 2.4 - * @since 2.7.0 - * @since 2.10.0 Add useragent as data to regex check - * - * @param array $comment Data of the comment. - * @return array|void Array with suspected reason - */ - private static function _verify_comment_request( $comment ) { - $ip = self::get_key( $comment, 'comment_author_IP' ); - $url = self::get_key( $comment, 'comment_author_url' ); - $body = self::get_key( $comment, 'comment_content' ); - $email = self::get_key( $comment, 'comment_author_email' ); - $author = self::get_key( $comment, 'comment_author' ); - $useragent = self::get_key( $comment, 'comment_agent' ); - - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - $allow_empty_comment = apply_filters( 'allow_empty_comment', false, $comment ); - - if ( empty( $body ) && ! $allow_empty_comment ) { - return array( - 'reason' => 'empty', - ); - } - - if ( empty( $ip ) ) { - return array( - 'reason' => 'empty', - ); - } - - if ( get_option( 'require_name_email' ) && ( empty( $email ) || empty( $author ) ) ) { - return array( - 'reason' => 'empty', - ); - } - - $options = self::get_options(); - - if ( $options['already_commented'] && ! empty( $email ) && self::_is_approved_email( $email ) ) { - return; - } - - if ( $options['gravatar_check'] && ! empty( $email ) && 1 === (int) get_option( 'show_avatars', 0 ) && self::_has_valid_gravatar( $email ) ) { - return; - } - - // phpcs:disable WordPress.Security.NonceVerification.Missing - if ( ! empty( $_POST['ab_spam__hidden_field'] ) ) { - return array( - 'reason' => 'css', - ); - } - // phpcs:enable WordPress.Security.NonceVerification.Missing - - if ( $options['time_check'] && self::_is_shortest_time() ) { - return array( - 'reason' => 'time', - ); - } - - if ( $options['bbcode_check'] && self::_is_bbcode_spam( $body ) ) { - return array( - 'reason' => 'bbcode', - ); - } - - if ( $options['regexp_check'] && self::_is_regexp_spam( - array( - 'ip' => $ip, - 'rawurl' => $url, - 'host' => self::parse_url( $url, 'host' ), - 'body' => $body, - 'email' => $email, - 'author' => $author, - 'useragent' => $useragent, - ) - ) ) { - return array( - 'reason' => 'regexp', - ); - } - - if ( $options['spam_ip'] && self::_is_db_spam( $ip, $url, $email ) ) { - return array( - 'reason' => 'localdb', - ); - } - - if ( $options['country_code'] && self::_is_country_spam( $ip ) ) { - return array( - 'reason' => 'country', - ); - } - - if ( $options['translate_api'] && self::_is_lang_spam( $body ) ) { - return array( - 'reason' => 'lang', - ); - } - } - - - /** - * Check for a Gravatar image - * - * @since 2.6.5 - * - * @param string $email Input email. - * @return boolean Check status (true = Gravatar available). - */ - private static function _has_valid_gravatar( $email ) { - $response = wp_safe_remote_get( - sprintf( - 'https://www.gravatar.com/avatar/%s?d=404', - md5( strtolower( trim( $email ) ) ) - ) - ); - - if ( is_wp_error( $response ) ) { - return null; - } - - if ( wp_remote_retrieve_response_code( $response ) === 200 ) { - return true; - } - - return false; - } - - - /** - * Check for comment action time - * - * @since 2.6.4 - * - * @return boolean TRUE if the action time is less than 5 seconds - */ - private static function _is_shortest_time() { - // phpcs:disable WordPress.Security.NonceVerification.Missing - // Everybody can Post. - $init_time = (int) self::get_key( $_POST, 'ab_init_time' ); - // phpcs:enable WordPress.Security.NonceVerification.Missing - if ( 0 === $init_time ) { - return false; - } - - if ( time() - $init_time < apply_filters( 'ab_action_time_limit', 5 ) ) { - return true; - } - - return false; - } - - /** - * Check if the blog name and the title of the blog post from which the trackback originates are equal. - * - * @since 2.6.4 - * - * @param string $body The comment body. - * @param string $blog_name The name of the blog. - * - * @return bool - */ - private static function is_trackback_post_title_blog_name_spam( $body, $blog_name ) { - preg_match( '/(.*)<\/strong>\\n\\n/', $body, $matches ); - if ( ! isset( $matches[1] ) ) { - return false; - } - return trim( $matches[1] ) === trim( $blog_name ); - } - - - /** - * Usage of regexp, also custom - * - * @since 2.5.2 - * @since 2.5.6 - * @since 2.10.0 Use useragent in check - * - * @param array $comment Array with commentary data. - * @return boolean True for suspicious comment. - */ - private static function _is_regexp_spam( $comment ) { - $fields = array( - 'ip', - 'host', - 'body', - 'email', - 'author', - 'useragent', - ); - - $patterns = array( - array( - 'host' => '^(www\.)?\d+\w+\.com$', - 'body' => '^\w+\s\d+$', - 'email' => '@gmail.com$', - ), - array( - 'body' => '\b[a-z]{30}\b', - 'author' => '\b[a-z]{10}\b', - 'host' => '\b[a-z]{10}\b', - ), - array( - 'body' => '\<\!.+?mfunc.+?\>', - ), - array( - 'author' => 'moncler|north face|vuitton|handbag|burberry|outlet|prada|cialis|viagra|maillot|oakley|ralph lauren|ray ban|iphone|プラダ', - ), - array( - 'host' => '^(www\.)?fkbook\.co\.uk$|^(www\.)?nsru\.net$|^(www\.)?goo\.gl$|^(www\.)?bit\.ly$', - ), - array( - 'body' => 'target[t]?ed (visitors|traffic)|viagra|cialis', - ), - array( - 'body' => 'purchase amazing|buy amazing|luxurybrandsale', - ), - array( - 'body' => 'dating|sex|lotto|pharmacy', - 'email' => '@mail\.ru|@yandex\.', - ), - ); - - $quoted_author = preg_quote( $comment['author'], '/' ); - if ( $quoted_author ) { - $patterns[] = array( - 'body' => sprintf( - '%s<\/a>$', - $quoted_author - ), - ); - $patterns[] = array( - 'body' => sprintf( - '%s https?:.+?$', - $quoted_author - ), - ); - $patterns[] = array( - 'email' => '@gmail.com$', - 'author' => '^[a-z0-9-\.]+\.[a-z]{2,6}$', - 'host' => sprintf( - '^%s$', - $quoted_author - ), - ); - } - - $patterns = apply_filters( - 'antispam_bee_patterns', - $patterns - ); - - if ( ! $patterns ) { - return false; - } - - foreach ( $patterns as $pattern ) { - $hits = array(); - - foreach ( $pattern as $field => $regexp ) { - if ( empty( $field ) || ! in_array( $field, $fields, true ) || empty( $regexp ) ) { - continue; - } - - $comment[ $field ] = ( function_exists( 'iconv' ) ? iconv( 'utf-8', 'utf-8//TRANSLIT', $comment[ $field ] ) : $comment[ $field ] ); - - if ( empty( $comment[ $field ] ) ) { - continue; - } - - if ( preg_match( '/' . $regexp . '/isu', $comment[ $field ] ) ) { - $hits[ $field ] = true; - } - } - - if ( count( $hits ) === count( $pattern ) ) { - return true; - } - } - - return false; - } - - - /** - * Review a comment on its existence in the local spam - * - * @since 2.0.0 - * @since 2.5.4 - * - * @param string $ip Comment IP. - * @param string $url Comment URL (optional). - * @param string $email Comment Email (optional). - * @return boolean True for suspicious comment. - */ - private static function _is_db_spam( $ip, $url = '', $email = '' ) { - global $wpdb; - - $params = array(); - $filter = array(); - if ( ! empty( $url ) ) { - $filter[] = '`comment_author_url` = %s'; - $params[] = wp_unslash( $url ); - } - if ( ! empty( $ip ) ) { - $filter[] = '`comment_author_IP` = %s'; - $params[] = wp_unslash( $ip ); - } - - if ( ! empty( $email ) ) { - $filter[] = '`comment_author_email` = %s'; - $params[] = wp_unslash( $email ); - } - if ( empty( $params ) ) { - return false; - } - - // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared - // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber - $filter_sql = implode( ' OR ', $filter ); - - $result = $wpdb->get_var( - $wpdb->prepare( - sprintf( - "SELECT `comment_ID` FROM `$wpdb->comments` WHERE `comment_approved` = 'spam' AND (%s) LIMIT 1", - $filter_sql - ), - $params - ) - ); - // phpcs:enable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber - // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared - - return ! empty( $result ); - } - - - /** - * Check for country spam by (anonymized) IP - * - * @since 2.6.9 - * @since 2.10.0 Make country check API filterable and use iplocate.io instead of ip2country.info - * - * @param string $ip IP address. - * @return boolean True if the comment is spam based on country filter. - */ - private static function _is_country_spam( $ip ) { - $options = self::get_options(); - - $allowed = preg_split( - '/[\s,;]+/', - $options['country_allowed'], - -1, - PREG_SPLIT_NO_EMPTY - ); - $denied = preg_split( - '/[\s,;]+/', - $options['country_denied'], - -1, - PREG_SPLIT_NO_EMPTY - ); - - if ( empty( $allowed ) && empty( $denied ) ) { - return false; - } - - /** - * Filter to hook into the `_is_country_spam` functionality, to implement for example a custom IP check. - * - * @since 2.10.0 - * - * @param null $is_country_spam The `is_country_spam` result. - * @param string $ip The IP address. - * @param array $allowed The list of allowed country codes. - * @param array $denied The list of denied country codes. - * - * @return null|boolean The `is_country_spam` result or null. - */ - $is_country_spam = apply_filters( 'antispam_bee_is_country_spam', null, $ip, $allowed, $denied ); - - if ( is_bool( $is_country_spam ) ) { - return $is_country_spam; - } - - /** - * Filters the IPLocate API key. With this filter, you can add your own IPLocate API key. - * - * @since 2.10.0 - * - * @param string The current IPLocate API key. Default is `null`. - * - * @return string The changed IPLocate API key or null. - */ - $apikey = apply_filters( 'antispam_bee_country_spam_apikey', '' ); - - $response = wp_safe_remote_get( - esc_url_raw( - sprintf( - 'https://www.iplocate.io/api/lookup/%s?apikey=%s', - self::_anonymize_ip( $ip ), - $apikey - ), - 'https' - ) - ); - - if ( is_wp_error( $response ) ) { - return false; - } - - if ( wp_remote_retrieve_response_code( $response ) !== 200 ) { - return false; - } - - $body = (string) wp_remote_retrieve_body( $response ); - - $json = json_decode( $body, true ); - - // Check if response is valid json. - if ( ! is_array( $json ) ) { - return false; - } - - if ( empty( $json['country_code'] ) ) { - return false; - } - - $country = strtoupper( $json['country_code'] ); - - if ( empty( $country ) || strlen( $country ) !== 2 ) { - return false; - } - - if ( ! empty( $denied ) ) { - return ( in_array( $country, $denied, true ) ); - } - - return ( ! in_array( $country, $allowed, true ) ); - } - - - /** - * Check for BBCode spam - * - * @since 2.5.1 - * - * @param string $body Content of a comment. - * @return boolean True for BBCode in content - */ - private static function _is_bbcode_spam( $body ) { - return (bool) preg_match( '/\[url[=\]].*\[\/url\]/is', $body ); - } - - - /** - * Check for an already approved e-mail address - * - * @since 2.0 - * @since 2.5.1 - * - * @param string $email E-mail address. - * @return boolean True for a found entry. - */ - private static function _is_approved_email( $email ) { - global $wpdb; - - $result = $wpdb->get_var( - $wpdb->prepare( - "SELECT `comment_ID` FROM `$wpdb->comments` WHERE `comment_approved` = '1' AND `comment_author_email` = %s LIMIT 1", - wp_unslash( $email ) - ) - ); - - if ( $result ) { - return true; - } - - return false; - } - - /** - * Check for unwanted languages - * - * @since 2.0 - * @since 2.6.6 - * @since 2.8.2 - * - * @param string $comment_content Content of the comment. - * - * @return boolean TRUE if it is spam. - */ - private static function _is_lang_spam( $comment_content ) { - $allowed_lang = (array) self::get_option( 'translate_lang' ); - - $comment_text = wp_strip_all_tags( $comment_content ); - - if ( empty( $allowed_lang ) || empty( $comment_text ) ) { - return false; - } - - /** - * Filters the detected language. With this filter, other detection methods can skip in and detect the language. - * - * @since 2.8.2 - * - * @param null $detected_lang The detected language. - * @param string $comment_text The text, to detect the language. - * - * @return null|string The detected language or null. - */ - $detected_lang = apply_filters( 'antispam_bee_detected_lang', null, $comment_text ); - if ( null !== $detected_lang ) { - return ! in_array( $detected_lang, $allowed_lang, true ); - } - - $word_count = 0; - $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $comment_text ), ' ' ); - - /* - * translators: If your word count is based on single characters (e.g. East Asian characters), - * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. - * Do not translate into your own language. - */ - if ( strpos( _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0 && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) { // phpcs:ignore WordPress.WP.I18n.MissingArgDomain - preg_match_all( '/./u', $text, $words_array ); - if ( isset( $words_array[0] ) ) { - $word_count = count( $words_array[0] ); - } - } else { - $words_array = preg_split( "/[\n\r\t ]+/", $text, -1, PREG_SPLIT_NO_EMPTY ); - $word_count = count( $words_array ); - } - - if ( $word_count < 10 ) { - return false; - } - - $response = wp_safe_remote_post( - 'https://api.pluginkollektiv.org/language/v1/', - array( 'body' => wp_json_encode( array( 'body' => $comment_text ) ) ) - ); - - if ( is_wp_error( $response ) - || wp_remote_retrieve_response_code( $response ) !== 200 ) { - return false; - } - - $detected_lang = wp_remote_retrieve_body( $response ); - if ( ! $detected_lang ) { - return false; - } - - $detected_lang = json_decode( $detected_lang ); - if ( ! $detected_lang || ! isset( $detected_lang->code ) ) { - return false; - } - - return ! in_array( self::_map_lang_code( $detected_lang->code ), $allowed_lang, true ); - } - - /** - * Map franc language codes - * - * @since 2.9.0 - * - * @param string $franc_code The franc code, received from the service. - * - * @return string Mapped ISO code - */ - private static function _map_lang_code( $franc_code ) { - $codes = array( - 'zha' => 'za', - 'zho' => 'zh', - 'zul' => 'zu', - 'yid' => 'yi', - 'yor' => 'yo', - 'xho' => 'xh', - 'wln' => 'wa', - 'wol' => 'wo', - 'ven' => 've', - 'vie' => 'vi', - 'vol' => 'vo', - 'uig' => 'ug', - 'ukr' => 'uk', - 'urd' => 'ur', - 'uzb' => 'uz', - 'tah' => 'ty', - 'tam' => 'ta', - 'tat' => 'tt', - 'tel' => 'te', - 'tgk' => 'tg', - 'tgl' => 'tl', - 'tha' => 'th', - 'tir' => 'ti', - 'ton' => 'to', - 'tsn' => 'tn', - 'tso' => 'ts', - 'tuk' => 'tk', - 'tur' => 'tr', - 'twi' => 'tw', - 'sag' => 'sg', - 'san' => 'sa', - 'sin' => 'si', - 'slk' => 'sk', - 'slv' => 'sl', - 'sme' => 'se', - 'smo' => 'sm', - 'sna' => 'sn', - 'snd' => 'sd', - 'som' => 'so', - 'sot' => 'st', - 'spa' => 'es', - 'sqi' => 'sq', - 'srd' => 'sc', - 'srp' => 'sr', - 'ssw' => 'ss', - 'sun' => 'su', - 'swa' => 'sw', - 'swe' => 'sv', - 'roh' => 'rm', - 'ron' => 'ro', - 'run' => 'rn', - 'rus' => 'ru', - 'que' => 'qu', - 'pan' => 'pa', - 'pli' => 'pi', - 'pol' => 'pl', - 'por' => 'pt', - 'pus' => 'ps', - 'oci' => 'oc', - 'oji' => 'oj', - 'ori' => 'or', - 'orm' => 'om', - 'oss' => 'os', - 'nau' => 'na', - 'nav' => 'nv', - 'nbl' => 'nr', - 'nde' => 'nd', - 'ndo' => 'ng', - 'nep' => 'ne', - 'nld' => 'nl', - 'nno' => 'nn', - 'nob' => 'nb', - 'nor' => 'no', - 'nya' => 'ny', - 'mah' => 'mh', - 'mal' => 'ml', - 'mar' => 'mr', - 'mkd' => 'mk', - 'mlg' => 'mg', - 'mlt' => 'mt', - 'mon' => 'mn', - 'mri' => 'mi', - 'msa' => 'ms', - 'mya' => 'my', - 'lao' => 'lo', - 'lat' => 'la', - 'lav' => 'lv', - 'lim' => 'li', - 'lin' => 'ln', - 'lit' => 'lt', - 'ltz' => 'lb', - 'lub' => 'lu', - 'lug' => 'lg', - 'kal' => 'kl', - 'kan' => 'kn', - 'kas' => 'ks', - 'kat' => 'ka', - 'kau' => 'kr', - 'kaz' => 'kk', - 'khm' => 'km', - 'kik' => 'ki', - 'kin' => 'rw', - 'kir' => 'ky', - 'kom' => 'kv', - 'kon' => 'kg', - 'kor' => 'ko', - 'kua' => 'kj', - 'kur' => 'ku', - 'jav' => 'jv', - 'jpn' => 'ja', - 'ibo' => 'ig', - 'ido' => 'io', - 'iii' => 'ii', - 'iku' => 'iu', - 'ile' => 'ie', - 'ina' => 'ia', - 'ind' => 'id', - 'ipk' => 'ik', - 'isl' => 'is', - 'ita' => 'it', - 'hat' => 'ht', - 'hau' => 'ha', - 'hbs' => 'sh', - 'heb' => 'he', - 'her' => 'hz', - 'hin' => 'hi', - 'hmo' => 'ho', - 'hrv' => 'hr', - 'hun' => 'hu', - 'hye' => 'hy', - 'gla' => 'gd', - 'gle' => 'ga', - 'glg' => 'gl', - 'glv' => 'gv', - 'grn' => 'gn', - 'guj' => 'gu', - 'fao' => 'fo', - 'fas' => 'fa', - 'fij' => 'fj', - 'fin' => 'fi', - 'fra' => 'fr', - 'fry' => 'fy', - 'ful' => 'ff', - 'ell' => 'el', - 'eng' => 'en', - 'epo' => 'eo', - 'est' => 'et', - 'eus' => 'eu', - 'ewe' => 'ee', - 'dan' => 'da', - 'deu' => 'de', - 'div' => 'dv', - 'dzo' => 'dz', - 'cat' => 'ca', - 'ces' => 'cs', - 'cha' => 'ch', - 'che' => 'ce', - 'chu' => 'cu', - 'chv' => 'cv', - 'cor' => 'kw', - 'cos' => 'co', - 'cre' => 'cr', - 'cym' => 'cy', - 'bak' => 'ba', - 'bam' => 'bm', - 'bel' => 'be', - 'ben' => 'bn', - 'bis' => 'bi', - 'bod' => 'bo', - 'bos' => 'bs', - 'bre' => 'br', - 'bul' => 'bg', - 'aar' => 'aa', - 'abk' => 'ab', - 'afr' => 'af', - 'aka' => 'ak', - 'amh' => 'am', - 'ara' => 'ar', - 'arg' => 'an', - 'asm' => 'as', - 'ava' => 'av', - 'ave' => 'ae', - 'aym' => 'ay', - 'aze' => 'az', - 'nds' => 'de', - ); - - if ( array_key_exists( $franc_code, $codes ) ) { - return $codes[ $franc_code ]; - } - - return $franc_code; - } - - /** - * Trim IP addresses - * - * @since 0.1 - * @since 2.5.1 - * - * @param string $ip Original IP. - * @param boolean $cut_end Shortening the end. - * @return string Shortened IP. - */ - private static function _cut_ip( $ip, $cut_end = true ) { - $separator = ( self::_is_ipv4( $ip ) ? '.' : ':' ); - - return str_replace( - ( $cut_end ? strrchr( $ip, $separator ) : strstr( $ip, $separator ) ), - '', - $ip - ); - } - - - /** - * Anonymize the IP addresses - * - * @since 2.5.1 - * - * @param string $ip Original IP. - * @return string Anonymous IP. - */ - private static function _anonymize_ip( $ip ) { - if ( self::_is_ipv4( $ip ) ) { - return self::_cut_ip( $ip ) . '.0'; - } - - return self::_cut_ip( $ip, false ) . ':0:0:0:0:0:0:0'; - } - - - /** - * Rotates the IP address - * - * @since 2.4.5 - * - * @param string $ip IP address. - * @return string Turned IP address. - */ - private static function _reverse_ip( $ip ) { - return implode( - '.', - array_reverse( - explode( - '.', - $ip - ) - ) - ); - } - - - /** - * Check for an IPv4 address - * - * @since 2.4 - * @since 2.6.4 - * - * @param string $ip IP to validate. - * @return integer TRUE if IPv4. - */ - private static function _is_ipv4( $ip ) { - if ( function_exists( 'filter_var' ) ) { - return filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) !== false; - } else { - return preg_match( '/^\d{1,3}(\.\d{1,3}){3}$/', $ip ); - } - } - - - /** - * Check for an IPv6 address - * - * @since 2.6.2 - * @since 2.6.4 - * - * @param string $ip IP to validate. - * @return boolean TRUE if IPv6. - */ - private static function _is_ipv6( $ip ) { - if ( function_exists( 'filter_var' ) ) { - return filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) !== false; - } else { - return ! self::_is_ipv4( $ip ); - } - } - - - /** - * Testing on mobile devices - * - * @since 0.1 - * @since 2.4 - * - * @return boolean TRUE if "wptouch" is active - */ - private static function _is_mobile() { - return strpos( get_template_directory(), 'wptouch' ); - } - - /** - * Testing if we are on an AMP site. - * - * Starting with v2.0, amp_is_request() is the preferred method to check, - * but we fall back to the then deprecated is_amp_endpoint() as needed. - * - * @return bool - */ - private static function _is_amp() { - return ( function_exists( 'amp_is_request' ) && amp_is_request() ) || ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ); - } - - - - /* - * ############################ - * ##### SPAM-TREATMENT ##### - * ############################ - */ - - /** - * Execution of the delete/marking process - * - * @since 0.1 - * @since 2.6.0 - * - * @param array $comment Untreated commentary data. - * @param string $reason Reason for suspicion. - * @param boolean $is_ping Ping (optional). - * @return array $comment Treated commentary data. - */ - private static function _handle_spam_request( $comment, $reason, $is_ping = false ) { - - $options = self::get_options(); - - $spam_remove = ! $options['flag_spam']; - $spam_notice = ! $options['no_notice']; - - // Filter settings. - $ignore_filter = $options['ignore_filter']; - $ignore_type = $options['ignore_type']; - $ignore_reason = in_array( $reason, (array) $options['ignore_reasons'], true ); - - // Remember spam. - self::_update_spam_log( $comment ); - self::_update_spam_count(); - self::_update_daily_stats(); - - // Delete spam. - if ( $spam_remove ) { - self::_go_in_peace(); - } - - if ( $ignore_filter && ( ( 1 === (int) $ignore_type && $is_ping ) || ( 2 === (int) $ignore_type && ! $is_ping ) ) ) { - self::_go_in_peace(); - } - - // Spam reason. - if ( $ignore_reason ) { - self::_go_in_peace(); - } - self::$_reason = $reason; - - // Mark spam. - add_filter( - 'pre_comment_approved', - array( - __CLASS__, - 'return_spam', - ) - ); - - // Send e-mail. - add_action( - 'comment_post', - array( - __CLASS__, - 'send_mail_notification', - ) - ); - - // Spam reason as comment meta. - if ( $spam_notice ) { - add_action( - 'comment_post', - array( - __CLASS__, - 'add_spam_reason_to_comment', - ) - ); - } - - return $comment; - } - - - /** - * Logfile with detected spam - * - * @since 2.5.7 - * @since 2.6.1 - * - * @param array $comment Array with commentary data. - * @return mixed FALSE in case of error - */ - private static function _update_spam_log( $comment ) { - if ( ! defined( 'ANTISPAM_BEE_LOG_FILE' ) || ! ANTISPAM_BEE_LOG_FILE || ! is_writable( ANTISPAM_BEE_LOG_FILE ) || validate_file( ANTISPAM_BEE_LOG_FILE ) === 1 ) { - return false; - } - - $entry = sprintf( - '%s comment for post=%d from host=%s marked as spam%s', - current_time( 'mysql' ), - $comment['comment_post_ID'], - $comment['comment_author_IP'], - PHP_EOL - ); - - file_put_contents( - ANTISPAM_BEE_LOG_FILE, - $entry, - FILE_APPEND | LOCK_EX - ); - } - - - /** - * Sends the 403 header and terminates the connection - * - * @since 2.5.6 - */ - private static function _go_in_peace() { - status_header( 403 ); - die( 'Spam deleted.' ); - } - - - /** - * Return real client IP - * - * @since 2.6.1 - * - * @return mixed $ip Client IP - */ - public static function get_client_ip() { - // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - // Sanitization of $ip takes place further down. - $ip = ''; - - if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) { - $ip = wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ); - } elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { - $ip = wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ); - } elseif ( isset( $_SERVER['HTTP_X_FORWARDED'] ) ) { - $ip = wp_unslash( $_SERVER['HTTP_X_FORWARDED'] ); - } elseif ( isset( $_SERVER['HTTP_FORWARDED_FOR'] ) ) { - $ip = wp_unslash( $_SERVER['HTTP_FORWARDED_FOR'] ); - } elseif ( isset( $_SERVER['HTTP_FORWARDED'] ) ) { - $ip = wp_unslash( $_SERVER['HTTP_FORWARDED'] ); - } - - $ip = self::_sanitize_ip( $ip ); - if ( $ip ) { - return $ip; - } - - if ( isset( $_SERVER['REMOTE_ADDR'] ) ) { - $ip = wp_unslash( $_SERVER['REMOTE_ADDR'] ); - return self::_sanitize_ip( $ip ); - } - - return ''; - // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - } - - /** - * Sanitize an IP string. - * - * @param string $raw_ip The raw IP. - * - * @return string The sanitized IP or an empty string. - */ - private static function _sanitize_ip( $raw_ip ) { - - if ( strpos( $raw_ip, ',' ) !== false ) { - $ips = explode( ',', $raw_ip ); - $raw_ip = trim( $ips[0] ); - } - if ( function_exists( 'filter_var' ) ) { - return (string) filter_var( - $raw_ip, - FILTER_VALIDATE_IP - ); - } - - return (string) preg_replace( - '/[^0-9a-f:. ]/si', - '', - $raw_ip - ); - } - - - /** - * Add spam reason as comment data - * - * @since 2.6.0 - * - * @param integer $comment_id Comment ID. - */ - public static function add_spam_reason_to_comment( $comment_id ) { - add_comment_meta( - $comment_id, - 'antispam_bee_reason', - self::$_reason - ); - } - - - /** - * Delete spam reason as comment data - * - * @since 2.6.0 - * - * @param integer $comment_id Comment ID. - */ - public static function delete_spam_reason_by_comment( $comment_id ) { - delete_comment_meta( - $comment_id, - 'antispam_bee_reason' - ); - } - - /** - * Updates the Antispam Bee reason for manual transitions - * - * @since 2.9.2 - * @param WP_Comment $comment Comment Object. - */ - public static function update_antispam_bee_reason( $comment ) { - update_comment_meta( $comment->comment_ID, 'antispam_bee_reason', 'manually' ); - } - - - /** - * Get the current post ID. - * - * @since 2.7.1 - */ - public static function populate_post_id() { - - if ( null === self::$_current_post_id ) { - self::$_current_post_id = get_the_ID(); - } - } - - - /** - * Send notification via e-mail - * - * @since 0.1 - * @since 2.5.7 - * @since 2.10.0 Change plugin website URL - * - * @hook string antispam_bee_notification_subject Custom subject for notification mails - * - * @param int $id ID of the comment. - * @return int $id ID of the comment. - */ - public static function send_mail_notification( $id ) { - $options = self::get_options(); - - if ( ! $options['email_notify'] ) { - return $id; - } - - $comment = get_comment( $id, ARRAY_A ); - - if ( empty( $comment ) ) { - return $id; - } - - $post = get_post( $comment['comment_post_ID'] ); - if ( ! $post ) { - return $id; - } - - self::load_plugin_lang(); - - $subject = sprintf( - '[%s] %s', - stripslashes_deep( - // phpcs:ignore PHPCompatibility.ParameterValues.NewHTMLEntitiesEncodingDefault.NotSet - html_entity_decode( - get_bloginfo( 'name' ), - ENT_QUOTES - ) - ), - esc_html__( 'Comment marked as spam', 'antispam-bee' ) - ); - - // Content. - $content = strip_tags( stripslashes( $comment['comment_content'] ) ); - if ( ! $content ) { - $content = sprintf( - '-- %s --', - esc_html__( 'Content removed by Antispam Bee', 'antispam-bee' ) - ); - } - - // Prepare Comment Type. - $comment_name = __( 'Comment', 'antispam-bee' ); - if ( 'trackback' === $comment['comment_type'] ) { - $comment_name = __( 'Trackback', 'antispam-bee' ); - } - if ( 'pingback' === $comment['comment_type'] ) { - $comment_name = __( 'Pingback', 'antispam-bee' ); - } - - // Body. - $body = sprintf( - "%s \"%s\"\r\n\r\n", - esc_html__( 'New spam comment on your post', 'antispam-bee' ), - strip_tags( $post->post_title ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Author', 'antispam-bee' ), - ( empty( $comment['comment_author'] ) ? '' : strip_tags( $comment['comment_author'] ) ) - ) . sprintf( - "URL: %s\r\n", - // empty check exists. - esc_url( $comment['comment_author_url'] ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Type', 'antispam-bee' ), - esc_html( $comment_name ) - ) . sprintf( - "Whois: http://whois.arin.net/rest/ip/%s\r\n", - $comment['comment_author_IP'] - ) . sprintf( - "%s: %s\r\n\r\n", - esc_html__( 'Spam Reason', 'antispam-bee' ), - esc_html( self::$defaults['reasons'][ self::$_reason ] ) - ) . sprintf( - "%s\r\n\r\n\r\n", - $content - ) . ( - EMPTY_TRASH_DAYS ? ( - sprintf( - "%s: %s\r\n", - esc_html__( 'Trash it', 'antispam-bee' ), - admin_url( 'comment.php?action=trash&c=' . $id ) - ) - ) : ( - sprintf( - "%s: %s\r\n", - esc_html__( 'Delete it', 'antispam-bee' ), - admin_url( 'comment.php?action=delete&c=' . $id ) - ) - ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Approve it', 'antispam-bee' ), - admin_url( 'comment.php?action=approve&c=' . $id ) - ) . sprintf( - "%s: %s\r\n\r\n", - esc_html__( 'Spam list', 'antispam-bee' ), - admin_url( 'edit-comments.php?comment_status=spam' ) - ) . sprintf( - "%s\r\n%s\r\n", - esc_html__( 'Notify message by Antispam Bee', 'antispam-bee' ), - esc_html__( 'https://antispambee.pluginkollektiv.org/', 'antispam-bee' ) - ); - - wp_mail( - /** - * Filters the recipients of the spam notification. - * - * @param array The recipients array. - */ - apply_filters( - 'antispam_bee_notification_recipients', - array( get_bloginfo( 'admin_email' ) ) - ), - /** - * Filters the subject of the spam notification. - * - * @param string $subject subject line. - */ - apply_filters( - 'antispam_bee_notification_subject', - $subject - ), - $body - ); - - return $id; - } - - - - /* - * ############################ - * ####### STATISTICS ####### - * ############################ - */ - - /** - * Return the number of spam comments - * - * @since 0.1 - * @since 2.4 - */ - private static function _get_spam_count() { - // Init. - $count = self::get_option( 'spam_count' ); - - // Fire. - return ( get_locale() === 'de_DE' ? number_format( $count, 0, '', '.' ) : number_format_i18n( $count ) ); - } - - - /** - * Output the number of spam comments - * - * @since 0.1 - * @since 2.4 - */ - public static function the_spam_count() { - echo esc_html( self::_get_spam_count() ); - } - - - /** - * Update the number of spam comments - * - * @since 0.1 - * @since 2.6.1 - */ - private static function _update_spam_count() { - // Skip if not enabled. - if ( ! self::get_option( 'dashboard_count' ) ) { - return; - } - - self::_update_option( - 'spam_count', - intval( self::get_option( 'spam_count' ) + 1 ) - ); - } - - /** - * Update statistics - * - * @since 1.9 - * @since 2.6.1 - */ - private static function _update_daily_stats() { - // Skip if not enabled. - if ( ! self::get_option( 'dashboard_chart' ) ) { - return; - } - - // Init. - $stats = (array) self::get_option( 'daily_stats' ); - $today = (int) strtotime( 'today' ); - - // Count up. - if ( array_key_exists( $today, $stats ) ) { - $stats[ $today ] ++; - } else { - $stats[ $today ] = 1; - } - - // Sort. - krsort( $stats, SORT_NUMERIC ); - - // Save. - self::_update_option( - 'daily_stats', - array_slice( $stats, 0, 31, true ) - ); - } - - /** - * Returns the secret of a post used in the textarea name attribute. - * - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists - * - * @param int $post_id The Post ID. - * - * @return string - */ - public static function get_secret_name_for_post( $post_id ) { - $secret = substr( sha1( md5( 'comment-id' . self::$_salt ) ), 0, 10 ); - - $secret = self::ensure_secret_starts_with_letter( $secret ); - - /** - * Filters the secret for a post, which is used in the textarea name attribute. - * - * @param string $secret The secret. - * @param int $post_id The post ID. - * @param bool $always_allowed Whether the comment form is used outside of the single post view or not. - */ - return apply_filters( - 'ab_get_secret_name_for_post', - $secret, - (int) $post_id, - (bool) self::get_option( 'always_allowed' ) - ); - - } - - /** - * Returns the secret of a post used in the textarea id attribute. - * - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists - * - * @param int $post_id The post ID. - * - * @return string - */ - public static function get_secret_id_for_post( $post_id ) { - - $secret = substr( sha1( md5( 'comment-id' . self::$_salt ) ), 0, 10 ); - - $secret = self::ensure_secret_starts_with_letter( $secret ); - - /** - * Filters the secret for a post, which is used in the textarea id attribute. - * - * @param string $secret The secret. - * @param int $post_id The post ID. - * @param bool $always_allowed Whether the comment form is used outside of the single post view or not. - */ - return apply_filters( - 'ab_get_secret_id_for_post', - $secret, - (int) $post_id, - (bool) self::get_option( 'always_allowed' ) - ); - } - - /** - * Ensures that the secret starts with a letter. - * - * @param string $secret The secret. - * - * @return string - */ - public static function ensure_secret_starts_with_letter( $secret ) { - - $first_char = substr( $secret, 0, 1 ); - if ( is_numeric( $first_char ) ) { - return chr( $first_char + 97 ) . substr( $secret, 1 ); - } else { - return $secret; - } - } - - /** - * Returns 'spam' - * - * @since 2.7.3 - * - * @return string - */ - public static function return_spam() { - - return 'spam'; - } - - /** - * A wrapper around wp_parse_url(). - * - * @since 2.8.2 - * - * @param string $url The URL to parse. - * @param string $component The component to get back. - * - * @return string - */ - private static function parse_url( $url, $component = 'host' ) { - - $parts = wp_parse_url( $url ); - return ( is_array( $parts ) && isset( $parts[ $component ] ) ) ? $parts[ $component ] : ''; - } - - /** - * Updates the database structure if necessary - * - * @since 2.10.0 Add update routine for country option names - */ - public static function update_database() { - if ( self::db_version_is_current() ) { - return; - } - - $version_from_db = floatval( get_option( 'antispambee_db_version', 0 ) ); - if ( $version_from_db < 1.01 ) { - global $wpdb; - - /** - * In Version 2.9 the IP of the commenter was saved as a hash. We reverted this solution. - * Therefore, we need to delete this unused data. - */ - //phpcs:disable WordPress.DB.PreparedSQL.NotPrepared - $sql = 'delete from `' . $wpdb->commentmeta . '` where `meta_key` IN ("antispam_bee_iphash")'; - $wpdb->query( $sql ); - //phpcs:enable WordPress.DB.PreparedSQL.NotPrepared - } - - // DB version was raised in ASB 2.10.0 to 1.02. - if ( $version_from_db < 1.02 ) { - // Update option names. - $options = self::get_options(); - if ( isset( $options['country_black'] ) ) { - $options['country_denied'] = $options['country_black']; - unset( $options['country_black'] ); - } - if ( isset( $options['country_white'] ) ) { - $options['country_allowed'] = $options['country_white']; - unset( $options['country_white'] ); - } - - update_option( - 'antispam_bee', - $options - ); - - wp_cache_set( - 'antispam_bee', - $options - ); - } - - update_option( 'antispambee_db_version', self::$db_version ); - } - - /** - * Whether the database structure is up to date. - * - * @since 2.10.0 Return a float instead of int - * - * @return bool - */ - private static function db_version_is_current() { - - $current_version = floatval( get_option( 'antispambee_db_version', 0 ) ); - return $current_version === self::$db_version; - - } - - /** - * Runs after upgrades are completed. - * - * @since 2.10.0 - * - * @param \WP_Upgrader $wp_upgrader WP_Upgrader instance. - * @param array $hook_extra Array of bulk item update data. - */ - public static function upgrades_completed( $wp_upgrader, $hook_extra ) { - if ( ! $wp_upgrader instanceof Plugin_Upgrader || ! isset( $hook_extra['plugins'] ) ) { - return; - } - - $updated_plugins = $hook_extra['plugins']; - $asb_updated = false; - foreach ( $updated_plugins as $updated_plugin ) { - if ( $updated_plugin !== self::$_base ) { - continue; - } - $asb_updated = true; - } - - if ( false === $asb_updated ) { - return; - } - - self::asb_updated(); - } - - /** - * Runs after an upgrade via an uploaded ZIP package was completed. - * - * @since 2.10.0 - * - * @param string $package The package file. - * @param array $data The new plugin or theme data. - * @param string $package_type The package type. - */ - public static function uploaded_upgrade_completed( $package, $data, $package_type ) { - if ( 'plugin' !== $package_type ) { - return; - } - - $text_domain = isset( $data['TextDomain'] ) ? $data['TextDomain'] : ''; - - if ( 'antispam-bee' !== $text_domain ) { - return; - } - - self::asb_updated(); - } - - /** - * Runs after ASB was updated. - * - * @since 2.10.0 - * - * @return void - */ - private static function asb_updated() { - self::update_database(); - } +/** + * Show a admin notice error message, if the PHP version is too low + */ +function antispam_bee_autoloader_missing() { + echo '

'; + esc_html_e( 'Antispam Bee is missing the Composer autoloader file. Please run `composer install --no-dev -o` in the root folder of the plugin or use a release version including the `vendor` folder.', 'antispam-bee' ); + echo '

'; } - - -// Fire. -add_action( - 'plugins_loaded', - array( - 'Antispam_Bee', - 'init', - ) -); - -// Activation. -register_activation_hook( - __FILE__, - array( - 'Antispam_Bee', - 'activate', - ) -); - -// Deactivation. -register_deactivation_hook( - __FILE__, - array( - 'Antispam_Bee', - 'deactivate', - ) -); - -// Uninstall. -register_uninstall_hook( - __FILE__, - array( - 'Antispam_Bee', - 'uninstall', - ) -); diff --git a/composer.json b/composer.json index 43ea4454..65b3c8fe 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,9 @@ }, "type": "wordpress-plugin", "license": "GPL-v2", + "require": { + "php": ">=5.6" + }, "require-dev": { "behat/mink": "1.7.1", "behat/mink-goutte-driver": "^1.2", @@ -36,6 +39,11 @@ "wp-cli/wp-cli-bundle": "@stable", "wp-coding-standards/wpcs": "^2.3" }, + "autoload": { + "psr-4": { + "AntispamBee\\": "lib/" + } + }, "autoload-dev": { "classmap": [ "antispam_bee.php", @@ -53,7 +61,7 @@ "@build" ], "build": [ - "@minify" + "npx wp-scripts build" ], "cs": [ "@lint-php" @@ -73,13 +81,11 @@ ], "lint-php": [ "phpcs --standard=phpcs.xml -s" - ], - "minify": [ - "minifycss css/dashboard.css > css/dashboard.min.css", - "minifycss css/styles.css > css/styles.min.css", - "minifyjs js/dashboard.js > js/dashboard.min.js", - "minifyjs js/raphael.helper.js > js/raphael.helper.min.js", - "minifyjs js/scripts.js > js/scripts.min.js" ] + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 83e4d901..00000000 --- a/composer.lock +++ /dev/null @@ -1,8171 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "111c08fbeff06000634003849aa35710", - "packages": [], - "packages-dev": [ - { - "name": "antecedent/patchwork", - "version": "2.0.9", - "source": { - "type": "git", - "url": "https://github.com/antecedent/patchwork.git", - "reference": "cab3be4865e47f1dc447715e76c7b616e48b005d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/antecedent/patchwork/zipball/cab3be4865e47f1dc447715e76c7b616e48b005d", - "reference": "cab3be4865e47f1dc447715e76c7b616e48b005d", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignas Rudaitis", - "email": "ignas.rudaitis@gmail.com" - } - ], - "description": "Method redefinition (monkey-patching) functionality for PHP.", - "homepage": "http://patchwork2.org/", - "keywords": [ - "aop", - "aspect", - "interception", - "monkeypatching", - "redefinition", - "runkit", - "testing" - ], - "support": { - "issues": "https://github.com/antecedent/patchwork/issues", - "source": "https://github.com/antecedent/patchwork/tree/master" - }, - "time": "2017-08-01T11:52:57+00:00" - }, - { - "name": "behat/behat", - "version": "v3.7.0", - "source": { - "type": "git", - "url": "https://github.com/Behat/Behat.git", - "reference": "08052f739619a9e9f62f457a67302f0715e6dd13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/08052f739619a9e9f62f457a67302f0715e6dd13", - "reference": "08052f739619a9e9f62f457a67302f0715e6dd13", - "shasum": "" - }, - "require": { - "behat/gherkin": "^4.6.0", - "behat/transliterator": "^1.2", - "ext-mbstring": "*", - "php": ">=5.3.3", - "psr/container": "^1.0", - "symfony/config": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", - "symfony/console": "^2.7.51 || ^2.8.33 || ^3.3.15 || ^3.4.3 || ^4.0.3 || ^5.0", - "symfony/dependency-injection": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", - "symfony/event-dispatcher": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", - "symfony/translation": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", - "symfony/yaml": "^2.7.51 || ^3.0 || ^4.0 || ^5.0" - }, - "require-dev": { - "container-interop/container-interop": "^1.2", - "herrera-io/box": "~1.6.1", - "phpunit/phpunit": "^4.8.36 || ^6.5.14 || ^7.5.20", - "symfony/process": "~2.5 || ^3.0 || ^4.0 || ^5.0" - }, - "suggest": { - "ext-dom": "Needed to output test results in JUnit format." - }, - "bin": [ - "bin/behat" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Behat\\": "src/Behat/Behat/", - "Behat\\Testwork\\": "src/Behat/Testwork/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Scenario-oriented BDD framework for PHP 5.3", - "homepage": "http://behat.org/", - "keywords": [ - "Agile", - "BDD", - "ScenarioBDD", - "Scrum", - "StoryBDD", - "User story", - "business", - "development", - "documentation", - "examples", - "symfony", - "testing" - ], - "support": { - "issues": "https://github.com/Behat/Behat/issues", - "source": "https://github.com/Behat/Behat/tree/v3.7.0" - }, - "time": "2020-06-03T13:08:44+00:00" - }, - { - "name": "behat/gherkin", - "version": "v4.8.0", - "source": { - "type": "git", - "url": "https://github.com/Behat/Gherkin.git", - "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/2391482cd003dfdc36b679b27e9f5326bd656acd", - "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd", - "shasum": "" - }, - "require": { - "php": "~7.2|~8.0" - }, - "require-dev": { - "cucumber/cucumber": "dev-gherkin-16.0.0", - "phpunit/phpunit": "~8|~9", - "symfony/phpunit-bridge": "~3|~4|~5", - "symfony/yaml": "~3|~4|~5" - }, - "suggest": { - "symfony/yaml": "If you want to parse features, represented in YAML files" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\Gherkin": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Gherkin DSL parser for PHP", - "homepage": "http://behat.org/", - "keywords": [ - "BDD", - "Behat", - "Cucumber", - "DSL", - "gherkin", - "parser" - ], - "support": { - "issues": "https://github.com/Behat/Gherkin/issues", - "source": "https://github.com/Behat/Gherkin/tree/v4.8.0" - }, - "time": "2021-02-04T12:44:21+00:00" - }, - { - "name": "behat/mink", - "version": "v1.7.1", - "source": { - "type": "git", - "url": "https://github.com/minkphp/Mink.git", - "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/Mink/zipball/e6930b9c74693dff7f4e58577e1b1743399f3ff9", - "reference": "e6930b9c74693dff7f4e58577e1b1743399f3ff9", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/css-selector": "~2.1|~3.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "suggest": { - "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", - "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", - "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", - "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Browser controller/emulator abstraction for PHP", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "testing", - "web" - ], - "support": { - "issues": "https://github.com/minkphp/Mink/issues", - "source": "https://github.com/minkphp/Mink/tree/master" - }, - "time": "2016-03-05T08:26:18+00:00" - }, - { - "name": "behat/mink-browserkit-driver", - "version": "v1.3.4", - "source": { - "type": "git", - "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", - "reference": "e3b90840022ebcd544c7b394a3c9597ae242cbee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/e3b90840022ebcd544c7b394a3c9597ae242cbee", - "reference": "e3b90840022ebcd544c7b394a3c9597ae242cbee", - "shasum": "" - }, - "require": { - "behat/mink": "^1.7.1@dev", - "php": ">=5.3.6", - "symfony/browser-kit": "~2.3|~3.0|~4.0", - "symfony/dom-crawler": "~2.3|~3.0|~4.0" - }, - "require-dev": { - "mink/driver-testsuite": "dev-master", - "symfony/debug": "^2.7|^3.0|^4.0", - "symfony/http-kernel": "~2.3|~3.0|~4.0" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\Driver\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Symfony2 BrowserKit driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "Mink", - "Symfony2", - "browser", - "testing" - ], - "support": { - "issues": "https://github.com/minkphp/MinkBrowserKitDriver/issues", - "source": "https://github.com/minkphp/MinkBrowserKitDriver/tree/v1.3.4" - }, - "time": "2020-03-11T09:49:45+00:00" - }, - { - "name": "behat/mink-goutte-driver", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/minkphp/MinkGoutteDriver.git", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", - "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", - "shasum": "" - }, - "require": { - "behat/mink": "~1.6@dev", - "behat/mink-browserkit-driver": "~1.2@dev", - "fabpot/goutte": "~1.0.4|~2.0|~3.1", - "php": ">=5.3.1" - }, - "require-dev": { - "symfony/phpunit-bridge": "~2.7|~3.0" - }, - "type": "mink-driver", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Mink\\Driver\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - } - ], - "description": "Goutte driver for Mink framework", - "homepage": "http://mink.behat.org/", - "keywords": [ - "browser", - "goutte", - "headless", - "testing" - ], - "support": { - "issues": "https://github.com/minkphp/MinkGoutteDriver/issues", - "source": "https://github.com/minkphp/MinkGoutteDriver/tree/master" - }, - "time": "2016-03-05T09:04:22+00:00" - }, - { - "name": "behat/transliterator", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/Behat/Transliterator.git", - "reference": "3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Behat/Transliterator/zipball/3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc", - "reference": "3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "chuyskywalker/rolling-curl": "^3.1", - "php-yaoi/php-yaoi": "^1.0", - "phpunit/phpunit": "^4.8.36|^6.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "psr-4": { - "Behat\\Transliterator\\": "src/Behat/Transliterator" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Artistic-1.0" - ], - "description": "String transliterator", - "keywords": [ - "i18n", - "slug", - "transliterator" - ], - "support": { - "issues": "https://github.com/Behat/Transliterator/issues", - "source": "https://github.com/Behat/Transliterator/tree/v1.3.0" - }, - "time": "2020-01-14T16:39:13+00:00" - }, - { - "name": "brain/monkey", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/Brain-WP/BrainMonkey.git", - "reference": "44b2ea87147803227154c990fa01fd5e82a6bb61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/44b2ea87147803227154c990fa01fd5e82a6bb61", - "reference": "44b2ea87147803227154c990fa01fd5e82a6bb61", - "shasum": "" - }, - "require": { - "antecedent/patchwork": "~2.0.6", - "mockery/mockery": "0.9.*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev", - "dev-version/1": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Brain\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Giuseppe Mazzapica", - "email": "giuseppe.mazzapica@gmail.com", - "homepage": "https://gmazzap.me", - "role": "Developer" - } - ], - "description": "Mocking utility for PHP functions and WordPress plugin API", - "keywords": [ - "Monkey Patching", - "interception", - "mock", - "mock functions", - "mockery", - "patchwork", - "redefinition", - "runkit", - "test", - "testing" - ], - "support": { - "issues": "https://github.com/Giuseppe-Mazzapica/BrainMonkey/issues", - "source": "https://github.com/Giuseppe-Mazzapica/BrainMonkey" - }, - "time": "2017-06-02T09:01:26+00:00" - }, - { - "name": "composer/ca-bundle", - "version": "1.2.9", - "source": { - "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\CaBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": [ - "cabundle", - "cacert", - "certificate", - "ssl", - "tls" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-01-12T12:10:35+00:00" - }, - { - "name": "composer/composer", - "version": "1.10.23", - "source": { - "type": "git", - "url": "https://github.com/composer/composer.git", - "reference": "28c9dfbe2351635961f670773e8d7b17bc5eda25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/28c9dfbe2351635961f670773e8d7b17bc5eda25", - "reference": "28c9dfbe2351635961f670773e8d7b17bc5eda25", - "shasum": "" - }, - "require": { - "composer/ca-bundle": "^1.0", - "composer/semver": "^1.0", - "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^1.1", - "justinrainbow/json-schema": "^5.2.10", - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0", - "seld/jsonlint": "^1.4", - "seld/phar-utils": "^1.0", - "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0", - "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0", - "symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0", - "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" - }, - "conflict": { - "symfony/console": "2.8.38" - }, - "require-dev": { - "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^4.2" - }, - "suggest": { - "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", - "ext-zip": "Enabling the zip extension allows you to unzip archives", - "ext-zlib": "Allow gzip compression of HTTP requests" - }, - "bin": [ - "bin/composer" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\": "src/Composer" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", - "homepage": "https://getcomposer.org/", - "keywords": [ - "autoload", - "dependency", - "package" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/1.10.23" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-04-27T11:10:45+00:00" - }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.1", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2020-11-11T10:22:58+00:00" - }, - { - "name": "composer/semver", - "version": "1.7.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/647490bbcaf7fc4891c58f47b825eb99d19c377a", - "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/1.7.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2020-12-03T15:47:16+00:00" - }, - { - "name": "composer/spdx-licenses", - "version": "1.5.5", - "source": { - "type": "git", - "url": "https://github.com/composer/spdx-licenses.git", - "reference": "de30328a7af8680efdc03e396aad24befd513200" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/de30328a7af8680efdc03e396aad24befd513200", - "reference": "de30328a7af8680efdc03e396aad24befd513200", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Spdx\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "SPDX licenses list and validation library.", - "keywords": [ - "license", - "spdx", - "validator" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2020-12-03T16:04:16+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "1.4.6", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-03-25T17:01:18+00:00" - }, - { - "name": "cweagans/composer-patches", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/cweagans/composer-patches.git", - "reference": "ae02121445ad75f4eaff800cc532b5e6233e2ddf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/ae02121445ad75f4eaff800cc532b5e6233e2ddf", - "reference": "ae02121445ad75f4eaff800cc532b5e6233e2ddf", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3.0" - }, - "require-dev": { - "composer/composer": "~1.0 || ~2.0", - "phpunit/phpunit": "~4.6" - }, - "type": "composer-plugin", - "extra": { - "class": "cweagans\\Composer\\Patches" - }, - "autoload": { - "psr-4": { - "cweagans\\Composer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Cameron Eagans", - "email": "me@cweagans.net" - } - ], - "description": "Provides a way to patch Composer packages.", - "support": { - "issues": "https://github.com/cweagans/composer-patches/issues", - "source": "https://github.com/cweagans/composer-patches/tree/1.7.0" - }, - "time": "2020-09-30T17:56:20+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.1", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "*", - "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" - }, - "time": "2020-12-07T18:04:37+00:00" - }, - { - "name": "dmore/behat-chrome-extension", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://gitlab.com/DMore/behat-chrome-extension.git", - "reference": "6279986ef85ac179f055460502e9b11c3784146c" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.com/api/v4/projects/DMore%2Fbehat-chrome-extension/repository/archive.zip?sha=6279986ef85ac179f055460502e9b11c3784146c", - "reference": "6279986ef85ac179f055460502e9b11c3784146c", - "shasum": "" - }, - "require": { - "behat/behat": "^3.0.4", - "behat/mink-extension": "^2.0", - "dmore/chrome-mink-driver": "^2.4.1", - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "^5.7" - }, - "type": "library", - "autoload": { - "psr-4": { - "DMore\\ChromeExtension\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Dorian More", - "email": "doriancmore@gmail.com" - } - ], - "description": "Behat extension for controlling chrome without selenium", - "keywords": [ - "Behat", - "chrome", - "driver", - "headless" - ], - "time": "2019-03-30T08:57:34+00:00" - }, - { - "name": "dmore/chrome-mink-driver", - "version": "2.8.0", - "source": { - "type": "git", - "url": "https://gitlab.com/DMore/chrome-mink-driver.git", - "reference": "f85c8f86ca2e9000119c310577a6942683f7e280" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.com/api/v4/projects/DMore%2Fchrome-mink-driver/repository/archive.zip?sha=f85c8f86ca2e9000119c310577a6942683f7e280", - "reference": "f85c8f86ca2e9000119c310577a6942683f7e280", - "shasum": "" - }, - "require": { - "behat/mink": "^1.7", - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "textalk/websocket": "^1.2.0" - }, - "require-dev": { - "mink/driver-testsuite": "dev-master", - "phpunit/phpunit": "^5.0.0", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "DMore\\ChromeDriver\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Dorian More", - "email": "doriancmore@gmail.com" - } - ], - "description": "Mink driver for controlling chrome without selenium", - "support": { - "issues": "https://gitlab.com/api/v4/projects/3255077/issues" - }, - "time": "2021-04-25T06:49:32+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^8.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2020-11-10T18:47:58+00:00" - }, - { - "name": "fabpot/goutte", - "version": "v3.2.3", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Goutte.git", - "reference": "3f0eaf0a40181359470651f1565b3e07e3dd31b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/3f0eaf0a40181359470651f1565b3e07e3dd31b8", - "reference": "3f0eaf0a40181359470651f1565b3e07e3dd31b8", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^6.0", - "php": ">=5.5.0", - "symfony/browser-kit": "~2.1|~3.0|~4.0", - "symfony/css-selector": "~2.1|~3.0|~4.0", - "symfony/dom-crawler": "~2.1|~3.0|~4.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3.3 || ^4" - }, - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Goutte\\": "Goutte" - }, - "exclude-from-classmap": [ - "Goutte/Tests" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "A simple PHP Web Scraper", - "homepage": "https://github.com/FriendsOfPHP/Goutte", - "keywords": [ - "scraper" - ], - "support": { - "issues": "https://github.com/FriendsOfPHP/Goutte/issues", - "source": "https://github.com/FriendsOfPHP/Goutte/tree/master" - }, - "time": "2018-06-29T15:13:57+00:00" - }, - { - "name": "friends-of-behat/mink-extension", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfBehat/MinkExtension.git", - "reference": "83119aa70be1f2c63061c29dced9d41775cd9db2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfBehat/MinkExtension/zipball/83119aa70be1f2c63061c29dced9d41775cd9db2", - "reference": "83119aa70be1f2c63061c29dced9d41775cd9db2", - "shasum": "" - }, - "require": { - "behat/behat": "^3.0.5", - "behat/mink": "^1.5", - "php": ">=7.2", - "symfony/config": "^3.4 || ^4.4 || ^5.0" - }, - "replace": { - "behat/mink-extension": "self.version" - }, - "require-dev": { - "behat/mink-goutte-driver": "^1.1", - "phpspec/phpspec": "^6.0 || ^7.0" - }, - "type": "behat-extension", - "extra": { - "branch-alias": { - "dev-master": "2.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Behat\\MinkExtension": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com" - }, - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - } - ], - "description": "Mink extension for Behat", - "homepage": "http://extensions.behat.org/mink", - "keywords": [ - "browser", - "gui", - "test", - "web" - ], - "support": { - "source": "https://github.com/FriendsOfBehat/MinkExtension/tree/v2.5.0" - }, - "time": "2021-01-21T09:27:44+00:00" - }, - { - "name": "gettext/gettext", - "version": "v4.8.4", - "source": { - "type": "git", - "url": "https://github.com/php-gettext/Gettext.git", - "reference": "58bc0f7f37e78efb0f9758f93d4a0f669f0f84a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/58bc0f7f37e78efb0f9758f93d4a0f669f0f84a1", - "reference": "58bc0f7f37e78efb0f9758f93d4a0f669f0f84a1", - "shasum": "" - }, - "require": { - "gettext/languages": "^2.3", - "php": ">=5.4.0" - }, - "require-dev": { - "illuminate/view": "*", - "phpunit/phpunit": "^4.8|^5.7|^6.5", - "squizlabs/php_codesniffer": "^3.0", - "symfony/yaml": "~2", - "twig/extensions": "*", - "twig/twig": "^1.31|^2.0" - }, - "suggest": { - "illuminate/view": "Is necessary if you want to use the Blade extractor", - "symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator", - "twig/extensions": "Is necessary if you want to use the Twig extractor", - "twig/twig": "Is necessary if you want to use the Twig extractor" - }, - "type": "library", - "autoload": { - "psr-4": { - "Gettext\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Oscar Otero", - "email": "oom@oscarotero.com", - "homepage": "http://oscarotero.com", - "role": "Developer" - } - ], - "description": "PHP gettext manager", - "homepage": "https://github.com/oscarotero/Gettext", - "keywords": [ - "JS", - "gettext", - "i18n", - "mo", - "po", - "translation" - ], - "support": { - "email": "oom@oscarotero.com", - "issues": "https://github.com/oscarotero/Gettext/issues", - "source": "https://github.com/php-gettext/Gettext/tree/v4.8.4" - }, - "funding": [ - { - "url": "https://paypal.me/oscarotero", - "type": "custom" - }, - { - "url": "https://github.com/oscarotero", - "type": "github" - }, - { - "url": "https://www.patreon.com/misteroom", - "type": "patreon" - } - ], - "time": "2021-03-10T19:35:49+00:00" - }, - { - "name": "gettext/languages", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/php-gettext/Languages.git", - "reference": "38ea0482f649e0802e475f0ed19fa993bcb7a618" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-gettext/Languages/zipball/38ea0482f649e0802e475f0ed19fa993bcb7a618", - "reference": "38ea0482f649e0802e475f0ed19fa993bcb7a618", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16.0", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4" - }, - "bin": [ - "bin/export-plural-rules" - ], - "type": "library", - "autoload": { - "psr-4": { - "Gettext\\Languages\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michele Locati", - "email": "mlocati@gmail.com", - "role": "Developer" - } - ], - "description": "gettext languages with plural rules", - "homepage": "https://github.com/php-gettext/Languages", - "keywords": [ - "cldr", - "i18n", - "internationalization", - "l10n", - "language", - "languages", - "localization", - "php", - "plural", - "plural rules", - "plurals", - "translate", - "translations", - "unicode" - ], - "support": { - "issues": "https://github.com/php-gettext/Languages/issues", - "source": "https://github.com/php-gettext/Languages/tree/2.6.0" - }, - "time": "2019-11-13T10:30:21+00:00" - }, - { - "name": "guzzlehttp/guzzle", - "version": "6.5.5", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17.0" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5" - }, - "time": "2020-06-16T21:01:06+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.1" - }, - "time": "2021-03-07T09:25:29+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" - }, - "time": "2021-04-26T09:17:50+00:00" - }, - { - "name": "hamcrest/hamcrest-php", - "version": "v1.2.2", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "satooshi/php-coveralls": "dev-master" - }, - "type": "library", - "autoload": { - "classmap": [ - "hamcrest" - ], - "files": [ - "hamcrest/Hamcrest.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "support": { - "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/master" - }, - "time": "2015-05-11T14:41:42+00:00" - }, - { - "name": "justinrainbow/json-schema", - "version": "5.2.10", - "source": { - "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", - "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.10" - }, - "time": "2020-05-27T16:41:55+00:00" - }, - { - "name": "matthiasmullie/minify", - "version": "1.3.66", - "source": { - "type": "git", - "url": "https://github.com/matthiasmullie/minify.git", - "reference": "45fd3b0f1dfa2c965857c6d4a470bea52adc31a6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/45fd3b0f1dfa2c965857c6d4a470bea52adc31a6", - "reference": "45fd3b0f1dfa2c965857c6d4a470bea52adc31a6", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "matthiasmullie/path-converter": "~1.1", - "php": ">=5.3.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2.0", - "matthiasmullie/scrapbook": "dev-master", - "phpunit/phpunit": ">=4.8" - }, - "suggest": { - "psr/cache-implementation": "Cache implementation to use with Minify::cache" - }, - "bin": [ - "bin/minifycss", - "bin/minifyjs" - ], - "type": "library", - "autoload": { - "psr-4": { - "MatthiasMullie\\Minify\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthias Mullie", - "email": "minify@mullie.eu", - "homepage": "http://www.mullie.eu", - "role": "Developer" - } - ], - "description": "CSS & JavaScript minifier, in PHP. Removes whitespace, strips comments, combines files (incl. @import statements and small assets in CSS files), and optimizes/shortens a few common programming patterns.", - "homepage": "http://www.minifier.org", - "keywords": [ - "JS", - "css", - "javascript", - "minifier", - "minify" - ], - "support": { - "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.66" - }, - "funding": [ - { - "url": "https://github.com/[user1", - "type": "github" - }, - { - "url": "https://github.com/matthiasmullie] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g.", - "type": "github" - }, - { - "url": "https://github.com/user2", - "type": "github" - } - ], - "time": "2021-01-06T15:18:10+00:00" - }, - { - "name": "matthiasmullie/path-converter", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/matthiasmullie/path-converter.git", - "reference": "e7d13b2c7e2f2268e1424aaed02085518afa02d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/e7d13b2c7e2f2268e1424aaed02085518afa02d9", - "reference": "e7d13b2c7e2f2268e1424aaed02085518afa02d9", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "MatthiasMullie\\PathConverter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthias Mullie", - "email": "pathconverter@mullie.eu", - "homepage": "http://www.mullie.eu", - "role": "Developer" - } - ], - "description": "Relative path converter", - "homepage": "http://github.com/matthiasmullie/path-converter", - "keywords": [ - "converter", - "path", - "paths", - "relative" - ], - "support": { - "issues": "https://github.com/matthiasmullie/path-converter/issues", - "source": "https://github.com/matthiasmullie/path-converter/tree/1.1.3" - }, - "time": "2019-02-05T23:41:09+00:00" - }, - { - "name": "mck89/peast", - "version": "v1.12.0", - "source": { - "type": "git", - "url": "https://github.com/mck89/peast.git", - "reference": "833be7a294627a8c5b1c482cbf489f73bf9b8086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mck89/peast/zipball/833be7a294627a8c5b1c482cbf489f73bf9b8086", - "reference": "833be7a294627a8c5b1c482cbf489f73bf9b8086", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.12.0-dev" - } - }, - "autoload": { - "psr-4": { - "Peast\\": "lib/Peast/", - "Peast\\test\\": "test/Peast/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Marchiò", - "email": "marco.mm89@gmail.com" - } - ], - "description": "Peast is PHP library that generates AST for JavaScript code", - "support": { - "issues": "https://github.com/mck89/peast/issues", - "source": "https://github.com/mck89/peast/tree/v1.12.0" - }, - "time": "2021-01-08T15:16:19+00:00" - }, - { - "name": "mockery/mockery", - "version": "0.9.11", - "source": { - "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "be9bf28d8e57d67883cba9fcadfcff8caab667f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/be9bf28d8e57d67883cba9fcadfcff8caab667f8", - "reference": "be9bf28d8e57d67883cba9fcadfcff8caab667f8", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "~1.1", - "lib-pcre": ">=7.0", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", - "homepage": "http://github.com/padraic/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "support": { - "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/0.9" - }, - "time": "2019-02-12T16:07:13+00:00" - }, - { - "name": "mustache/mustache", - "version": "v2.14.1", - "source": { - "type": "git", - "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "579ffa5c96e1d292c060b3dd62811ff01ad8c24e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/579ffa5c96e1d292c060b3dd62811ff01ad8c24e", - "reference": "579ffa5c96e1d292c060b3dd62811ff01ad8c24e", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~1.11", - "phpunit/phpunit": "~3.7|~4.0|~5.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Mustache": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" - } - ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", - "keywords": [ - "mustache", - "templating" - ], - "support": { - "issues": "https://github.com/bobthecow/mustache.php/issues", - "source": "https://github.com/bobthecow/mustache.php/tree/v2.14.1" - }, - "time": "2022-01-21T06:08:36+00:00" - }, - { - "name": "nb/oxymel", - "version": "v0.1.0", - "source": { - "type": "git", - "url": "https://github.com/nb/oxymel.git", - "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nb/oxymel/zipball/cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", - "reference": "cbe626ef55d5c4cc9b5e6e3904b395861ea76e3c", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "type": "library", - "autoload": { - "psr-0": { - "Oxymel": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nikolay Bachiyski", - "email": "nb@nikolay.bg", - "homepage": "http://extrapolate.me/" - } - ], - "description": "A sweet XML builder", - "homepage": "https://github.com/nb/oxymel", - "keywords": [ - "xml" - ], - "support": { - "issues": "https://github.com/nb/oxymel/issues", - "source": "https://github.com/nb/oxymel/tree/master" - }, - "time": "2013-02-24T15:01:54+00:00" - }, - { - "name": "ocramius/proxy-manager", - "version": "2.2.3", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/ProxyManager.git", - "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/4d154742e31c35137d5374c998e8f86b54db2e2f", - "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f", - "shasum": "" - }, - "require": { - "ocramius/package-versions": "^1.1.3", - "php": "^7.2.0", - "zendframework/zend-code": "^3.3.0" - }, - "require-dev": { - "couscous/couscous": "^1.6.1", - "ext-phar": "*", - "humbug/humbug": "1.0.0-RC.0@RC", - "nikic/php-parser": "^3.1.1", - "padraic/phpunit-accelerator": "dev-master@DEV", - "phpbench/phpbench": "^0.12.2", - "phpstan/phpstan": "dev-master#856eb10a81c1d27c701a83f167dc870fd8f4236a as 0.9.999", - "phpstan/phpstan-phpunit": "dev-master#5629c0a1f4a9c417cb1077cf6693ad9753895761", - "phpunit/phpunit": "^6.4.3", - "squizlabs/php_codesniffer": "^2.9.1" - }, - "suggest": { - "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects", - "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)", - "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)", - "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "ProxyManager\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.io/" - } - ], - "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies", - "homepage": "https://github.com/Ocramius/ProxyManager", - "keywords": [ - "aop", - "lazy loading", - "proxy", - "proxy pattern", - "service proxies" - ], - "support": { - "issues": "https://github.com/Ocramius/ProxyManager/issues", - "source": "https://github.com/Ocramius/ProxyManager/tree/2.2.x" - }, - "time": "2019-08-10T08:37:15+00:00" - }, - { - "name": "paulgibbs/behat-wordpress-extension", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/paulgibbs/behat-wordpress-extension.git", - "reference": "ebd86dec6e29e827b03e2aff9bbe3de5ad2ec396" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paulgibbs/behat-wordpress-extension/zipball/ebd86dec6e29e827b03e2aff9bbe3de5ad2ec396", - "reference": "ebd86dec6e29e827b03e2aff9bbe3de5ad2ec396", - "shasum": "" - }, - "require": { - "behat/behat": "~3.1", - "behat/mink-extension": "~2.3", - "php": ">=7.2 <7.4", - "sensiolabs/behat-page-object-extension": "~2.1" - }, - "require-dev": { - "behat/mink-goutte-driver": "^1.2", - "dmore/behat-chrome-extension": "^1.3", - "genesis/behat-fail-aid": "^2.0", - "phpstan/phpstan": "~0.9", - "squizlabs/php_codesniffer": "~3.0", - "wp-cli/wp-cli-bundle": "~2.1" - }, - "suggest": { - "behat/mink-goutte-driver": "Headless Mink driver", - "behat/mink-selenium2-driver": "JS-enabled Mink driver (requires Selenium)", - "dmore/behat-chrome-extension": "JS-enabled Mink driver for Chrome (does not require Selenium)", - "genesis/behat-fail-aid": "Get more out of your test suite by getting it to work with you when tests fail." - }, - "type": "behat-extension", - "extra": { - "wordpress-install-dir": "tests/app/www" - }, - "autoload": { - "psr-4": { - "PaulGibbs\\WordpressBehatExtension\\": "src" - }, - "files": [ - "src/Util/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "Paul Gibbs", - "email": "djpaul@gmail.com", - "homepage": "https://byotos.com" - } - ], - "description": "WordHat is a Behat extension for WordPress. It provides WordPress-specific functionality for common testing scenarios specific to WordPress sites.", - "homepage": "https://wordhat.info", - "keywords": [ - "BDD", - "Behat", - "extension", - "wordpress" - ], - "support": { - "issues": "https://github.com/paulgibbs/behat-wordpress-extension/issues", - "source": "https://github.com/paulgibbs/behat-wordpress-extension/tree/v3.3.0" - }, - "abandoned": true, - "time": "2019-06-24T19:27:08+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibility" - }, - "time": "2019-12-27T09:44:58+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "ddabec839cc003651f2ce695c938686d1086cf43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/ddabec839cc003651f2ce695c938686d1086cf43", - "reference": "ddabec839cc003651f2ce695c938686d1086cf43", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" - }, - "time": "2021-02-15T10:24:51+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "b7dc0cd7a8f767ccac5e7637550ea1c50a67b09e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/b7dc0cd7a8f767ccac5e7637550ea1c50a67b09e", - "reference": "b7dc0cd7a8f767ccac5e7637550ea1c50a67b09e", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "phpcs", - "standards", - "wordpress" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" - }, - "time": "2021-02-15T12:58:46+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" - }, - "time": "2020-09-03T19:13:55+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" - }, - "time": "2020-09-17T18:55:26+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.10.3", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "451c3cd1418cf640de218914901e51b064abb093" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", - "reference": "451c3cd1418cf640de218914901e51b064abb093", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" - }, - "time": "2020-03-05T15:02:03+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "2.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/2.2" - }, - "time": "2015-10-06T15:47:00+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" - }, - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" - }, - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/master" - }, - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.12", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.4" - }, - "abandoned": true, - "time": "2017-12-04T08:55:13+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "4.8.36", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.2.2", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.8.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/4.8.36" - }, - "time": "2017-06-21T08:07:12+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", - "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/2.3" - }, - "abandoned": true, - "time": "2015-10-02T06:51:40+00:00" - }, - { - "name": "psr/container", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" - }, - "time": "2021-03-05T17:36:06+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/master" - }, - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "psr/log", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" - }, - "time": "2021-05-03T11:20:27+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "rmccue/requests", - "version": "v1.8.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/Requests.git", - "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/Requests/zipball/afbe4790e4def03581c4a0963a1e8aa01f6030f1", - "reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1", - "shasum": "" - }, - "require": { - "php": ">=5.2" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "php-parallel-lint/php-console-highlighter": "^0.5.0", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpcompatibility/php-compatibility": "^9.0", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5", - "requests/test-server": "dev-master", - "squizlabs/php_codesniffer": "^3.5", - "wp-coding-standards/wpcs": "^2.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Requests": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Ryan McCue", - "homepage": "http://ryanmccue.info" - } - ], - "description": "A HTTP library written in PHP, for human beings.", - "homepage": "http://github.com/WordPress/Requests", - "keywords": [ - "curl", - "fsockopen", - "http", - "idna", - "ipv6", - "iri", - "sockets" - ], - "support": { - "issues": "https://github.com/WordPress/Requests/issues", - "source": "https://github.com/WordPress/Requests/tree/v1.8.0" - }, - "time": "2021-04-27T11:05:25+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" - }, - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/1.4" - }, - "time": "2017-05-22T07:24:03+00:00" - }, - { - "name": "sebastian/environment", - "version": "1.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/1.3" - }, - "time": "2016-08-18T05:49:44+00:00" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/master" - }, - "time": "2016-06-17T09:04:28+00:00" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" - }, - "time": "2015-10-12T03:26:01+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" - }, - "time": "2016-10-03T07:41:43+00:00" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/1.0.6" - }, - "time": "2015-06-21T13:59:46+00:00" - }, - { - "name": "seld/jsonlint", - "version": "1.8.3", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", - "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", - "shasum": "" - }, - "require": { - "php": "^5.3 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "support": { - "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.8.3" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", - "type": "tidelift" - } - ], - "time": "2020-11-11T09:19:24+00:00" - }, - { - "name": "seld/phar-utils", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8674b1d84ffb47cc59a101f5d5a3b61e87d23796", - "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Seld\\PharUtils\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "PHAR file format utilities, for when PHP phars you up", - "keywords": [ - "phar" - ], - "support": { - "issues": "https://github.com/Seldaek/phar-utils/issues", - "source": "https://github.com/Seldaek/phar-utils/tree/master" - }, - "time": "2020-07-07T18:42:57+00:00" - }, - { - "name": "sensiolabs/behat-page-object-extension", - "version": "v2.3.2", - "source": { - "type": "git", - "url": "https://github.com/sensiolabs/BehatPageObjectExtension.git", - "reference": "408bc81cafb824ca8d2a1d9435f3d50b9075d3aa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/BehatPageObjectExtension/zipball/408bc81cafb824ca8d2a1d9435f3d50b9075d3aa", - "reference": "408bc81cafb824ca8d2a1d9435f3d50b9075d3aa", - "shasum": "" - }, - "require": { - "behat/behat": "^3.3", - "behat/mink": "^1.7", - "friends-of-behat/mink-extension": "^2.2", - "ocramius/proxy-manager": "^2.1.1", - "php": "^7.2" - }, - "conflict": { - "guzzlehttp/guzzle": "<6.3" - }, - "require-dev": { - "behat/mink-goutte-driver": "^1.2", - "bossa/phpspec2-expect": "^3.1.1", - "fabpot/goutte": "^3.2", - "phpspec/phpspec": "^6.1", - "symfony/filesystem": "^4.2 || ^5.0", - "symfony/process": "^4.2 || ^5.0", - "symfony/yaml": "^4.2 || ^5.0" - }, - "suggest": { - "bossa/phpspec2-expect": "Allows to use PHPSpec2 matchers in Behat context files" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "SensioLabs\\Behat\\PageObjectExtension\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marcello Duarte", - "email": "mduarte@inviqa.com" - }, - { - "name": "Jakub Zalas", - "email": "jakub@zalas.pl" - } - ], - "description": "Page object extension for Behat", - "homepage": "https://github.com/sensiolabs/BehatPageObjectExtension", - "keywords": [ - "BDD", - "Behat", - "page" - ], - "support": { - "issues": "https://github.com/sensiolabs/BehatPageObjectExtension/issues", - "source": "https://github.com/sensiolabs/BehatPageObjectExtension/tree/v2.3.2" - }, - "time": "2020-06-18T10:20:26+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.6.0", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" - }, - "time": "2021-04-09T00:54:41+00:00" - }, - { - "name": "symfony/browser-kit", - "version": "v4.4.22", - "source": { - "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1", - "reference": "4c8b42b4aae93517e8f67d68c5cbe69413e3e3c1", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/dom-crawler": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/http-client": "^4.3|^5.0", - "symfony/mime": "^4.3|^5.0", - "symfony/process": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/process": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/browser-kit/tree/v4.4.22" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-04-08T07:40:10+00:00" - }, - { - "name": "symfony/config", - "version": "v5.2.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "8dfa5f8adea9cd5155920069224beb04f11d6b7e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8dfa5f8adea9cd5155920069224beb04f11d6b7e", - "reference": "8dfa5f8adea9cd5155920069224beb04f11d6b7e", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15" - }, - "conflict": { - "symfony/finder": "<4.4" - }, - "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/config/tree/v5.2.8" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-07T13:41:16+00:00" - }, - { - "name": "symfony/console", - "version": "v4.4.23", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "1ab187ac21d41d7d34a4f529091a1f5d0bb2924f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ab187ac21d41d7d34a4f529091a1f5d0bb2924f", - "reference": "1ab187ac21d41d7d34a4f529091a1f5d0bb2924f", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2" - }, - "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3|>=5", - "symfony/lock": "<4.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/event-dispatcher": "^4.3", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/var-dumper": "^4.3|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/console/tree/v4.4.23" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-10T12:53:15+00:00" - }, - { - "name": "symfony/css-selector", - "version": "v3.4.47", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "da3d9da2ce0026771f5fe64cb332158f1bd2bc33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/da3d9da2ce0026771f5fe64cb332158f1bd2bc33", - "reference": "da3d9da2ce0026771f5fe64cb332158f1bd2bc33", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/css-selector/tree/v3.4.47" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-24T10:57:07+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v4.3.11", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "468bfb60a60b7caa03e4722c43f5359df47b4349" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/468bfb60a60b7caa03e4722c43f5359df47b4349", - "reference": "468bfb60a60b7caa03e4722c43f5359df47b4349", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "psr/container": "^1.0", - "symfony/service-contracts": "^1.1.6" - }, - "conflict": { - "symfony/config": "<4.3", - "symfony/finder": "<3.4", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0" - }, - "require-dev": { - "symfony/config": "^4.3", - "symfony/expression-language": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DependencyInjection Component", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v4.3.10" - }, - "time": "2020-01-14T16:43:06+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-03-23T23:28:01+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v4.4.20", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "be133557f1b0e6672367325b508e65da5513a311" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/be133557f1b0e6672367325b508e65da5513a311", - "reference": "be133557f1b0e6672367325b508e65da5513a311", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "masterminds/html5": "<2.6" - }, - "require-dev": { - "masterminds/html5": "^2.6", - "symfony/css-selector": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases DOM navigation for HTML and XML documents", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v4.4.20" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-14T12:29:41+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v4.4.20", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/event-dispatcher-contracts": "^1.1" - }, - "conflict": { - "symfony/dependency-injection": "<3.4" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "1.1" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/error-handler": "~3.4|~4.4", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/http-foundation": "^3.4|^4.0|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/stopwatch": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-27T09:09:26+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.9", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", - "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", - "shasum": "" - }, - "require": { - "php": ">=7.1.3" - }, - "suggest": { - "psr/event-dispatcher": "", - "symfony/event-dispatcher-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-07-06T13:19:58+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v5.2.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.7" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-04-01T10:42:13+00:00" - }, - { - "name": "symfony/finder", - "version": "v5.2.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/eccb8be70d7a6a2230d05f6ecede40f3fdd9e252", - "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252", - "shasum": "" - }, - "require": { - "php": ">=7.2.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.8" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-10T14:39:23+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-07T16:49:33+00:00" - }, - { - "name": "symfony/polyfill-intl-idn", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-22T09:19:47+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-22T09:19:47+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-22T09:19:47+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-07T16:49:33+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-07T16:49:33+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.22.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-07T16:49:33+00:00" - }, - { - "name": "symfony/process", - "version": "v5.2.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", - "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v5.3.0-BETA1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-04-08T10:27:02+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v1.1.9", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "b776d18b303a39f56c63747bcb977ad4b27aca26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b776d18b303a39f56c63747bcb977ad4b27aca26", - "reference": "b776d18b303a39f56c63747bcb977ad4b27aca26", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "psr/container": "^1.0" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v1.1.9" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-07-06T13:19:58+00:00" - }, - { - "name": "symfony/translation", - "version": "v4.4.23", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "ff6e63c7b5de874464642969968f61f8dc649ac3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ff6e63c7b5de874464642969968f61f8dc649ac3", - "reference": "ff6e63c7b5de874464642969968f61f8dc649ac3", - "shasum": "" - }, - "require": { - "php": ">=7.1.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^1.1.6|^2" - }, - "conflict": { - "symfony/config": "<3.4", - "symfony/dependency-injection": "<3.4", - "symfony/http-kernel": "<4.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "symfony/translation-implementation": "1.0|2.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/console": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/finder": "~2.8|~3.0|~4.0|^5.0", - "symfony/http-kernel": "^4.4", - "symfony/intl": "^3.4|^4.0|^5.0", - "symfony/service-contracts": "^1.1.2|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" - }, - "suggest": { - "psr/log-implementation": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to internationalize your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.23" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-04-28T06:59:52+00:00" - }, - { - "name": "symfony/translation-contracts", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation-contracts.git", - "reference": "95c812666f3e91db75385749fe219c5e494c7f95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/95c812666f3e91db75385749fe219c5e494c7f95", - "reference": "95c812666f3e91db75385749fe219c5e494c7f95", - "shasum": "" - }, - "require": { - "php": ">=7.2.5" - }, - "suggest": { - "symfony/translation-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Translation\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to translation", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-03-23T23:28:01+00:00" - }, - { - "name": "symfony/yaml", - "version": "v3.4.47", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "88289caa3c166321883f67fe5130188ebbb47094" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094", - "reference": "88289caa3c166321883f67fe5130188ebbb47094", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/console": "<3.4" - }, - "require-dev": { - "symfony/console": "~3.4|~4.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v3.4.47" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-24T10:57:07+00:00" - }, - { - "name": "textalk/websocket", - "version": "1.5.3", - "source": { - "type": "git", - "url": "https://github.com/Textalk/websocket-php.git", - "reference": "25f6e322bfaf978a665391efdddc135d4edd60eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/25f6e322bfaf978a665391efdddc135d4edd60eb", - "reference": "25f6e322bfaf978a665391efdddc135d4edd60eb", - "shasum": "" - }, - "require": { - "php": "^7.2 | ^8.0", - "psr/log": "^1.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^8.0|^9.0", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "WebSocket\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Fredrik Liljegren" - }, - { - "name": "Sören Jensen", - "email": "soren@abicart.se" - } - ], - "description": "WebSocket client and server", - "support": { - "issues": "https://github.com/Textalk/websocket-php/issues", - "source": "https://github.com/Textalk/websocket-php/tree/1.5.3" - }, - "time": "2021-04-18T15:27:16+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" - }, - { - "name": "wp-cli/cache-command", - "version": "v2.0.5", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/cache-command.git", - "reference": "c1a91b35f274e8aa5142eb4d82842421ed89049a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/cache-command/zipball/c1a91b35f274e8aa5142eb4d82842421ed89049a", - "reference": "c1a91b35f274e8aa5142eb4d82842421ed89049a", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "cache", - "cache add", - "cache decr", - "cache delete", - "cache flush", - "cache get", - "cache incr", - "cache replace", - "cache set", - "cache type", - "transient", - "transient delete", - "transient get", - "transient set", - "transient type", - "transient list" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "cache-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Manages object and transient caches.", - "homepage": "https://github.com/wp-cli/cache-command", - "support": { - "issues": "https://github.com/wp-cli/cache-command/issues", - "source": "https://github.com/wp-cli/cache-command/tree/v2.0.5" - }, - "time": "2020-12-07T19:32:47+00:00" - }, - { - "name": "wp-cli/checksum-command", - "version": "v2.0.5", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/checksum-command.git", - "reference": "a03cb058fcb295b8a1b060cc90618e777b86ad49" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/checksum-command/zipball/a03cb058fcb295b8a1b060cc90618e777b86ad49", - "reference": "a03cb058fcb295b8a1b060cc90618e777b86ad49", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "core verify-checksums", - "plugin verify-checksums" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "checksum-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Verifies file integrity by comparing to published checksums.", - "homepage": "https://github.com/wp-cli/checksum-command", - "support": { - "issues": "https://github.com/wp-cli/checksum-command/issues", - "source": "https://github.com/wp-cli/checksum-command/tree/v2.0.5" - }, - "time": "2020-12-07T22:47:40+00:00" - }, - { - "name": "wp-cli/config-command", - "version": "v2.0.7", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/config-command.git", - "reference": "6468e97ab2ace5b0a448d9e19091d42f6461b466" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/config-command/zipball/6468e97ab2ace5b0a448d9e19091d42f6461b466", - "reference": "6468e97ab2ace5b0a448d9e19091d42f6461b466", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2", - "wp-cli/wp-config-transformer": "^1.2.1" - }, - "require-dev": { - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "config", - "config edit", - "config delete", - "config create", - "config get", - "config has", - "config list", - "config path", - "config set", - "config shuffle-salts" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "config-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - }, - { - "name": "Alain Schlesser", - "email": "alain.schlesser@gmail.com", - "homepage": "https://www.alainschlesser.com" - } - ], - "description": "Generates and reads the wp-config.php file.", - "homepage": "https://github.com/wp-cli/config-command", - "support": { - "issues": "https://github.com/wp-cli/config-command/issues", - "source": "https://github.com/wp-cli/config-command/tree/v2.0.7" - }, - "time": "2020-10-31T11:20:34+00:00" - }, - { - "name": "wp-cli/core-command", - "version": "v2.0.12", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/core-command.git", - "reference": "a7001bd43b58fe67decd02c739615102cc0beb51" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/core-command/zipball/a7001bd43b58fe67decd02c739615102cc0beb51", - "reference": "a7001bd43b58fe67decd02c739615102cc0beb51", - "shasum": "" - }, - "require": { - "composer/semver": "^1.4 || ^2 || ^3", - "wp-cli/wp-cli": "^2.4" - }, - "require-dev": { - "wp-cli/checksum-command": "^1 || ^2", - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "core", - "core check-update", - "core download", - "core install", - "core is-installed", - "core multisite-convert", - "core multisite-install", - "core update", - "core update-db", - "core version" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "core-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Downloads, installs, updates, and manages a WordPress installation.", - "homepage": "https://github.com/wp-cli/core-command", - "support": { - "issues": "https://github.com/wp-cli/core-command/issues", - "source": "https://github.com/wp-cli/core-command/tree/v2.0.12" - }, - "time": "2020-12-07T19:31:14+00:00" - }, - { - "name": "wp-cli/cron-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/cron-command.git", - "reference": "668b8c7bc1c1a1930e8a956b1a8325d159cce78c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/cron-command/zipball/668b8c7bc1c1a1930e8a956b1a8325d159cce78c", - "reference": "668b8c7bc1c1a1930e8a956b1a8325d159cce78c", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "cron", - "cron test", - "cron event", - "cron event delete", - "cron event list", - "cron event run", - "cron event schedule", - "cron schedule", - "cron schedule list", - "cron event unschedule" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "cron-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Tests, runs, and deletes WP-Cron events; manages WP-Cron schedules.", - "homepage": "https://github.com/wp-cli/cron-command", - "support": { - "issues": "https://github.com/wp-cli/cron-command/issues", - "source": "https://github.com/wp-cli/cron-command/tree/v2.0.6" - }, - "time": "2020-12-07T19:30:59+00:00" - }, - { - "name": "wp-cli/db-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/db-command.git", - "reference": "8e3cd46987241ed97ddb7f682b3505dff8d6dce4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/db-command/zipball/8e3cd46987241ed97ddb7f682b3505dff8d6dce4", - "reference": "8e3cd46987241ed97ddb7f682b3505dff8d6dce4", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "db", - "db clean", - "db create", - "db drop", - "db reset", - "db check", - "db optimize", - "db prefix", - "db repair", - "db cli", - "db query", - "db export", - "db import", - "db search", - "db tables", - "db size", - "db columns" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "db-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Performs basic database operations using credentials stored in wp-config.php.", - "homepage": "https://github.com/wp-cli/db-command", - "support": { - "issues": "https://github.com/wp-cli/db-command/issues", - "source": "https://github.com/wp-cli/db-command/tree/v2.0.6" - }, - "time": "2020-01-28T16:39:32+00:00" - }, - { - "name": "wp-cli/embed-command", - "version": "v2.0.7", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/embed-command.git", - "reference": "93d5582a9b03e950d3a2fe0869ae2c12d55a6242" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/embed-command/zipball/93d5582a9b03e950d3a2fe0869ae2c12d55a6242", - "reference": "93d5582a9b03e950d3a2fe0869ae2c12d55a6242", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "embed", - "embed fetch", - "embed provider", - "embed provider list", - "embed provider match", - "embed handler", - "embed handler list", - "embed cache", - "embed cache clear", - "embed cache find", - "embed cache trigger" - ] - }, - "autoload": { - "psr-4": { - "WP_CLI\\Embeds\\": "src/" - }, - "files": [ - "embed-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Pascal Birchler", - "homepage": "https://pascalbirchler.com/" - } - ], - "description": "Inspects oEmbed providers, clears embed cache, and more.", - "homepage": "https://github.com/wp-cli/embed-command", - "support": { - "issues": "https://github.com/wp-cli/embed-command/issues", - "source": "https://github.com/wp-cli/embed-command/tree/v2.0.7" - }, - "time": "2020-12-07T19:30:42+00:00" - }, - { - "name": "wp-cli/entity-command", - "version": "v2.0.7", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/entity-command.git", - "reference": "0df89e4fba48177acf768bff9c00cda95a3fe5b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/entity-command/zipball/0df89e4fba48177acf768bff9c00cda95a3fe5b9", - "reference": "0df89e4fba48177acf768bff9c00cda95a3fe5b9", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/cache-command": "^1 || ^2", - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/media-command": "^1.1 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "comment", - "comment approve", - "comment count", - "comment create", - "comment delete", - "comment exists", - "comment generate", - "comment get", - "comment list", - "comment meta", - "comment meta add", - "comment meta delete", - "comment meta get", - "comment meta list", - "comment meta patch", - "comment meta pluck", - "comment meta update", - "comment recount", - "comment spam", - "comment status", - "comment trash", - "comment unapprove", - "comment unspam", - "comment untrash", - "comment update", - "menu", - "menu create", - "menu delete", - "menu item", - "menu item add-custom", - "menu item add-post", - "menu item add-term", - "menu item delete", - "menu item list", - "menu item update", - "menu list", - "menu location", - "menu location assign", - "menu location list", - "menu location remove", - "network meta", - "network meta add", - "network meta delete", - "network meta get", - "network meta list", - "network meta patch", - "network meta pluck", - "network meta update", - "option", - "option add", - "option delete", - "option get", - "option list", - "option patch", - "option pluck", - "option update", - "post", - "post create", - "post delete", - "post edit", - "post exists", - "post generate", - "post get", - "post list", - "post meta", - "post meta add", - "post meta delete", - "post meta get", - "post meta list", - "post meta patch", - "post meta pluck", - "post meta update", - "post term", - "post term add", - "post term list", - "post term remove", - "post term set", - "post update", - "post-type", - "post-type get", - "post-type list", - "site", - "site activate", - "site archive", - "site create", - "site deactivate", - "site delete", - "site empty", - "site list", - "site mature", - "site option", - "site private", - "site public", - "site spam", - "site unarchive", - "site unmature", - "site unspam", - "taxonomy", - "taxonomy get", - "taxonomy list", - "term", - "term create", - "term delete", - "term generate", - "term get", - "term list", - "term meta", - "term meta add", - "term meta delete", - "term meta get", - "term meta list", - "term meta patch", - "term meta pluck", - "term meta update", - "term recount", - "term update", - "user", - "user add-cap", - "user add-role", - "user create", - "user delete", - "user generate", - "user get", - "user import-csv", - "user list", - "user list-caps", - "user meta", - "user meta add", - "user meta delete", - "user meta get", - "user meta list", - "user meta patch", - "user meta pluck", - "user meta update", - "user remove-cap", - "user remove-role", - "user reset-password", - "user session", - "user session destroy", - "user session list", - "user set-role", - "user spam", - "user term", - "user term add", - "user term list", - "user term remove", - "user term set", - "user unspam", - "user update" - ] - }, - "autoload": { - "psr-4": { - "": "src/", - "WP_CLI\\": "src/WP_CLI" - }, - "files": [ - "entity-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Manage WordPress comments, menus, options, posts, sites, terms, and users.", - "homepage": "https://github.com/wp-cli/entity-command", - "support": { - "issues": "https://github.com/wp-cli/entity-command/issues", - "source": "https://github.com/wp-cli/entity-command/tree/master" - }, - "time": "2019-11-12T11:32:14+00:00" - }, - { - "name": "wp-cli/eval-command", - "version": "v2.0.8", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/eval-command.git", - "reference": "8a5e0340e82e1fb2b48a5dedd88cef1fb8b410ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/eval-command/zipball/8a5e0340e82e1fb2b48a5dedd88cef1fb8b410ce", - "reference": "8a5e0340e82e1fb2b48a5dedd88cef1fb8b410ce", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "eval", - "eval-file" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "eval-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Executes arbitrary PHP code or files.", - "homepage": "https://github.com/wp-cli/eval-command", - "support": { - "issues": "https://github.com/wp-cli/eval-command/issues", - "source": "https://github.com/wp-cli/eval-command/tree/v2.0.8" - }, - "time": "2020-12-07T19:30:26+00:00" - }, - { - "name": "wp-cli/export-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/export-command.git", - "reference": "df2e1ff4fb7e969c54c57febccdc9d2de1e5f499" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/export-command/zipball/df2e1ff4fb7e969c54c57febccdc9d2de1e5f499", - "reference": "df2e1ff4fb7e969c54c57febccdc9d2de1e5f499", - "shasum": "" - }, - "require": { - "nb/oxymel": "~0.1.0", - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/import-command": "^1 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "export" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "export-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Exports WordPress content to a WXR file.", - "homepage": "https://github.com/wp-cli/export-command", - "support": { - "issues": "https://github.com/wp-cli/export-command/issues", - "source": "https://github.com/wp-cli/export-command/tree/v2.0.6" - }, - "time": "2021-01-14T12:16:33+00:00" - }, - { - "name": "wp-cli/extension-command", - "version": "v2.0.10", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/extension-command.git", - "reference": "2bc83433707fa4d2127f2ff48357ccbbee39052f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/extension-command/zipball/2bc83433707fa4d2127f2ff48357ccbbee39052f", - "reference": "2bc83433707fa4d2127f2ff48357ccbbee39052f", - "shasum": "" - }, - "require": { - "composer/semver": "^1.4 || ^2.0", - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/scaffold-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1.6" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "plugin", - "plugin activate", - "plugin deactivate", - "plugin delete", - "plugin get", - "plugin install", - "plugin is-installed", - "plugin list", - "plugin path", - "plugin search", - "plugin status", - "plugin toggle", - "plugin uninstall", - "plugin update", - "theme", - "theme activate", - "theme delete", - "theme disable", - "theme enable", - "theme get", - "theme install", - "theme is-installed", - "theme list", - "theme mod", - "theme mod get", - "theme mod set", - "theme mod remove", - "theme path", - "theme search", - "theme status", - "theme update", - "theme mod list" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "extension-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - }, - { - "name": "Alain Schlesser", - "email": "alain.schlesser@gmail.com", - "homepage": "https://www.alainschlesser.com" - } - ], - "description": "Manages plugins and themes, including installs, activations, and updates.", - "homepage": "https://github.com/wp-cli/extension-command", - "support": { - "issues": "https://github.com/wp-cli/extension-command/issues", - "source": "https://github.com/wp-cli/extension-command/tree/master" - }, - "time": "2020-07-05T08:07:53+00:00" - }, - { - "name": "wp-cli/i18n-command", - "version": "v2.2.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/i18n-command.git", - "reference": "a66da3f09f6a728832381012848c3074bf1635c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/i18n-command/zipball/a66da3f09f6a728832381012848c3074bf1635c8", - "reference": "a66da3f09f6a728832381012848c3074bf1635c8", - "shasum": "" - }, - "require": { - "gettext/gettext": "^4.8", - "mck89/peast": "^1.8", - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/scaffold-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1.3" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "i18n", - "i18n make-pot", - "i18n make-json" - ] - }, - "autoload": { - "psr-4": { - "WP_CLI\\I18n\\": "src/" - }, - "files": [ - "i18n-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Pascal Birchler", - "homepage": "https://pascalbirchler.com/" - } - ], - "description": "Provides internationalization tools for WordPress projects.", - "homepage": "https://github.com/wp-cli/i18n-command", - "support": { - "issues": "https://github.com/wp-cli/i18n-command/issues", - "source": "https://github.com/wp-cli/i18n-command/tree/v2.2.6" - }, - "time": "2020-12-07T19:28:27+00:00" - }, - { - "name": "wp-cli/import-command", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/import-command.git", - "reference": "c7438c1eeda5669531c52fc9223fcea5bda39cc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/import-command/zipball/c7438c1eeda5669531c52fc9223fcea5bda39cc8", - "reference": "c7438c1eeda5669531c52fc9223fcea5bda39cc8", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/export-command": "^1 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "import" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "import-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Imports content from a given WXR file.", - "homepage": "https://github.com/wp-cli/import-command", - "support": { - "issues": "https://github.com/wp-cli/import-command/issues", - "source": "https://github.com/wp-cli/import-command/tree/v2.0.4" - }, - "time": "2020-12-07T19:28:45+00:00" - }, - { - "name": "wp-cli/language-command", - "version": "v2.0.8", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/language-command.git", - "reference": "c4f3cddd816e26df2b0e7e7753d786b54a2c95c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/language-command/zipball/c4f3cddd816e26df2b0e7e7753d786b54a2c95c8", - "reference": "c4f3cddd816e26df2b0e7e7753d786b54a2c95c8", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "language", - "language core", - "language core activate", - "language core is-installed", - "language core install", - "language core list", - "language core uninstall", - "language core update", - "language plugin", - "language plugin is-installed", - "language plugin install", - "language plugin list", - "language plugin uninstall", - "language plugin update", - "language theme", - "language theme is-installed", - "language theme install", - "language theme list", - "language theme uninstall", - "language theme update" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "language-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Installs, activates, and manages language packs.", - "homepage": "https://github.com/wp-cli/language-command", - "support": { - "issues": "https://github.com/wp-cli/language-command/issues", - "source": "https://github.com/wp-cli/language-command/tree/v2.0.8" - }, - "time": "2020-12-07T19:29:09+00:00" - }, - { - "name": "wp-cli/maintenance-mode-command", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/maintenance-mode-command.git", - "reference": "1f4f09ad15696f65e713c4c73008f6550318b3bd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/maintenance-mode-command/zipball/1f4f09ad15696f65e713c4c73008f6550318b3bd", - "reference": "1f4f09ad15696f65e713c4c73008f6550318b3bd", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "maintenance-mode", - "maintenance-mode activate", - "maintenance-mode deactivate", - "maintenance-mode status", - "maintenance-mode is-active" - ] - }, - "autoload": { - "psr-4": { - "WP_CLI\\MaintenanceMode\\": "src/" - }, - "files": [ - "maintenance-mode-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Thrijith Thankachan", - "email": "thrijith13@gmail.com", - "homepage": "https://thrijith.com" - } - ], - "description": "Activates, deactivates or checks the status of the maintenance mode of a site.", - "homepage": "https://github.com/wp-cli/maintenance-mode-command", - "support": { - "issues": "https://github.com/wp-cli/maintenance-mode-command/issues", - "source": "https://github.com/wp-cli/maintenance-mode-command/tree/v2.0.4" - }, - "time": "2020-12-07T19:29:39+00:00" - }, - { - "name": "wp-cli/media-command", - "version": "v2.0.9", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/media-command.git", - "reference": "830e72a2cbd3eeec95a97df2c1c17d925d86790d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/media-command/zipball/830e72a2cbd3eeec95a97df2c1c17d925d86790d", - "reference": "830e72a2cbd3eeec95a97df2c1c17d925d86790d", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/extension-command": "^2.0", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "media", - "media import", - "media regenerate", - "media image-size" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "media-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Imports files as attachments, regenerates thumbnails, or lists registered image sizes.", - "homepage": "https://github.com/wp-cli/media-command", - "support": { - "issues": "https://github.com/wp-cli/media-command/issues", - "source": "https://github.com/wp-cli/media-command/tree/master" - }, - "time": "2020-06-11T00:17:12+00:00" - }, - { - "name": "wp-cli/mustangostang-spyc", - "version": "0.6.3", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/spyc.git", - "reference": "6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/spyc/zipball/6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7", - "reference": "6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7", - "shasum": "" - }, - "require": { - "php": ">=5.3.1" - }, - "require-dev": { - "phpunit/phpunit": "4.3.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5.x-dev" - } - }, - "autoload": { - "psr-4": { - "Mustangostang\\": "src/" - }, - "files": [ - "includes/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "mustangostang", - "email": "vlad.andersen@gmail.com" - } - ], - "description": "A simple YAML loader/dumper class for PHP (WP-CLI fork)", - "homepage": "https://github.com/mustangostang/spyc/", - "support": { - "source": "https://github.com/wp-cli/spyc/tree/autoload" - }, - "time": "2017-04-25T11:26:20+00:00" - }, - { - "name": "wp-cli/package-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/package-command.git", - "reference": "92a0d7f2f4b54ad2aeff2292baaa96ba8f93f37a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/package-command/zipball/92a0d7f2f4b54ad2aeff2292baaa96ba8f93f37a", - "reference": "92a0d7f2f4b54ad2aeff2292baaa96ba8f93f37a", - "shasum": "" - }, - "require": { - "composer/composer": ">=1.2.0 <1.7.0 || ^1.7.1", - "ext-json": "*", - "wp-cli/wp-cli": "^2.1" - }, - "require-dev": { - "wp-cli/scaffold-command": "^1 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "package", - "package browse", - "package install", - "package list", - "package update", - "package uninstall" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "package-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Lists, installs, and removes WP-CLI packages.", - "homepage": "https://github.com/wp-cli/package-command", - "support": { - "issues": "https://github.com/wp-cli/package-command/issues", - "source": "https://github.com/wp-cli/package-command/tree/master" - }, - "time": "2020-01-28T12:55:09+00:00" - }, - { - "name": "wp-cli/php-cli-tools", - "version": "v0.11.12", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "e472e08489f7504d9e8c5c5a057e1419cd1b2b3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/e472e08489f7504d9e8c5c5a057e1419cd1b2b3e", - "reference": "e472e08489f7504d9e8c5c5a057e1419cd1b2b3e", - "shasum": "" - }, - "require": { - "php": ">= 5.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "cli": "lib/" - }, - "files": [ - "lib/cli/cli.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@handbuilt.co", - "role": "Maintainer" - }, - { - "name": "James Logsdon", - "email": "jlogsdon@php.net", - "role": "Developer" - } - ], - "description": "Console utilities for PHP", - "homepage": "http://github.com/wp-cli/php-cli-tools", - "keywords": [ - "cli", - "console" - ], - "support": { - "issues": "https://github.com/wp-cli/php-cli-tools/issues", - "source": "https://github.com/wp-cli/php-cli-tools/tree/v0.11.12" - }, - "time": "2021-03-03T12:43:49+00:00" - }, - { - "name": "wp-cli/rewrite-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/rewrite-command.git", - "reference": "6b2c7d186b375976869b8d74f1a3bac1f98aca57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/rewrite-command/zipball/6b2c7d186b375976869b8d74f1a3bac1f98aca57", - "reference": "6b2c7d186b375976869b8d74f1a3bac1f98aca57", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "rewrite", - "rewrite flush", - "rewrite list", - "rewrite structure" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "rewrite-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Lists or flushes the site's rewrite rules, updates the permalink structure.", - "homepage": "https://github.com/wp-cli/rewrite-command", - "support": { - "issues": "https://github.com/wp-cli/rewrite-command/issues", - "source": "https://github.com/wp-cli/rewrite-command/tree/v2.0.6" - }, - "time": "2020-12-07T19:27:22+00:00" - }, - { - "name": "wp-cli/role-command", - "version": "v2.0.5", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/role-command.git", - "reference": "50e563a81f7462c4c5374abf6a1c0e88dfb01c9c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/role-command/zipball/50e563a81f7462c4c5374abf6a1c0e88dfb01c9c", - "reference": "50e563a81f7462c4c5374abf6a1c0e88dfb01c9c", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "role", - "role create", - "role delete", - "role exists", - "role list", - "role reset", - "cap", - "cap add", - "cap list", - "cap remove" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "role-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Adds, removes, lists, and resets roles and capabilities.", - "homepage": "https://github.com/wp-cli/role-command", - "support": { - "issues": "https://github.com/wp-cli/role-command/issues", - "source": "https://github.com/wp-cli/role-command/tree/v2.0.5" - }, - "time": "2020-12-07T19:27:04+00:00" - }, - { - "name": "wp-cli/scaffold-command", - "version": "v2.0.8", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/scaffold-command.git", - "reference": "4814acbdf3d7af499530cc1ae1e82f3ed9f12674" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/scaffold-command/zipball/4814acbdf3d7af499530cc1ae1e82f3ed9f12674", - "reference": "4814acbdf3d7af499530cc1ae1e82f3ed9f12674", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0", - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "scaffold", - "scaffold underscores", - "scaffold block", - "scaffold child-theme", - "scaffold plugin", - "scaffold plugin-tests", - "scaffold post-type", - "scaffold taxonomy", - "scaffold theme-tests" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "scaffold-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Generates code for post types, taxonomies, blocks, plugins, child themes, etc.", - "homepage": "https://github.com/wp-cli/scaffold-command", - "support": { - "issues": "https://github.com/wp-cli/scaffold-command/issues", - "source": "https://github.com/wp-cli/scaffold-command/tree/master" - }, - "time": "2019-11-25T13:26:31+00:00" - }, - { - "name": "wp-cli/search-replace-command", - "version": "v2.0.7", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/search-replace-command.git", - "reference": "1104e4fb7dd83e85dedb8a98ed8f0ac30639694b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/search-replace-command/zipball/1104e4fb7dd83e85dedb8a98ed8f0ac30639694b", - "reference": "1104e4fb7dd83e85dedb8a98ed8f0ac30639694b", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "search-replace" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "search-replace-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Searches/replaces strings in the database.", - "homepage": "https://github.com/wp-cli/search-replace-command", - "support": { - "issues": "https://github.com/wp-cli/search-replace-command/issues", - "source": "https://github.com/wp-cli/search-replace-command/tree/v2.0.7" - }, - "time": "2020-06-10T13:24:39+00:00" - }, - { - "name": "wp-cli/server-command", - "version": "v2.0.6", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/server-command.git", - "reference": "be65465bda181209c95011f15d4575809d039ea9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/server-command/zipball/be65465bda181209c95011f15d4575809d039ea9", - "reference": "be65465bda181209c95011f15d4575809d039ea9", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "server" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "server-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Launches PHP's built-in web server for a specific WordPress installation.", - "homepage": "https://github.com/wp-cli/server-command", - "support": { - "issues": "https://github.com/wp-cli/server-command/issues", - "source": "https://github.com/wp-cli/server-command/tree/v2.0.6" - }, - "time": "2020-12-07T19:26:47+00:00" - }, - { - "name": "wp-cli/shell-command", - "version": "v2.0.7", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/shell-command.git", - "reference": "76088e1ff69855d89454aed886d27c3f62b12c2c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/shell-command/zipball/76088e1ff69855d89454aed886d27c3f62b12c2c", - "reference": "76088e1ff69855d89454aed886d27c3f62b12c2c", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "shell" - ] - }, - "autoload": { - "psr-4": { - "": "src/", - "WP_CLI\\": "src/WP_CLI" - }, - "files": [ - "shell-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Opens an interactive PHP console for running and testing PHP code.", - "homepage": "https://github.com/wp-cli/shell-command", - "support": { - "issues": "https://github.com/wp-cli/shell-command/issues", - "source": "https://github.com/wp-cli/shell-command/tree/v2.0.7" - }, - "time": "2020-12-07T19:26:30+00:00" - }, - { - "name": "wp-cli/super-admin-command", - "version": "v2.0.5", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/super-admin-command.git", - "reference": "23b9a4e6f27d5effe5cfd67db2329e0d58dbb53f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/super-admin-command/zipball/23b9a4e6f27d5effe5cfd67db2329e0d58dbb53f", - "reference": "23b9a4e6f27d5effe5cfd67db2329e0d58dbb53f", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2" - }, - "require-dev": { - "wp-cli/entity-command": "^1.3 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "super-admin", - "super-admin add", - "super-admin list", - "super-admin remove" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "super-admin-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Lists, adds, or removes super admin users on a multisite installation.", - "homepage": "https://github.com/wp-cli/super-admin-command", - "support": { - "issues": "https://github.com/wp-cli/super-admin-command/issues", - "source": "https://github.com/wp-cli/super-admin-command/tree/v2.0.5" - }, - "time": "2020-12-07T19:26:13+00:00" - }, - { - "name": "wp-cli/widget-command", - "version": "v2.1.2", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/widget-command.git", - "reference": "0c73470adbc73b45f4d371e4869672eacca104b3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/widget-command/zipball/0c73470adbc73b45f4d371e4869672eacca104b3", - "reference": "0c73470adbc73b45f4d371e4869672eacca104b3", - "shasum": "" - }, - "require": { - "wp-cli/wp-cli": "^2.4" - }, - "require-dev": { - "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "type": "wp-cli-package", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, - "bundled": true, - "commands": [ - "widget", - "widget add", - "widget deactivate", - "widget delete", - "widget list", - "widget move", - "widget reset", - "widget update", - "sidebar", - "sidebar list" - ] - }, - "autoload": { - "psr-4": { - "": "src/" - }, - "files": [ - "widget-command.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Bachhuber", - "email": "daniel@runcommand.io", - "homepage": "https://runcommand.io" - } - ], - "description": "Adds, moves, and removes widgets; lists sidebars.", - "homepage": "https://github.com/wp-cli/widget-command", - "support": { - "issues": "https://github.com/wp-cli/widget-command/issues", - "source": "https://github.com/wp-cli/widget-command/tree/v2.1.2" - }, - "time": "2020-12-07T19:25:02+00:00" - }, - { - "name": "wp-cli/wp-cli", - "version": "v2.4.1", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/wp-cli.git", - "reference": "ceb18598e79befa9b2a37a51efbb34910628988b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/ceb18598e79befa9b2a37a51efbb34910628988b", - "reference": "ceb18598e79befa9b2a37a51efbb34910628988b", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "mustache/mustache": "~2.13", - "php": "^5.4 || ^7.0", - "rmccue/requests": "~1.6", - "symfony/finder": ">2.7", - "wp-cli/mustangostang-spyc": "^0.6.3", - "wp-cli/php-cli-tools": "~0.11.2" - }, - "require-dev": { - "roave/security-advisories": "dev-master", - "wp-cli/db-command": "^1.3 || ^2", - "wp-cli/entity-command": "^1.2 || ^2", - "wp-cli/extension-command": "^1.1 || ^2", - "wp-cli/package-command": "^1 || ^2", - "wp-cli/wp-cli-tests": "^2.1" - }, - "suggest": { - "ext-readline": "Include for a better --prompt implementation", - "ext-zip": "Needed to support extraction of ZIP archives when doing downloads or updates" - }, - "bin": [ - "bin/wp", - "bin/wp.bat" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "WP_CLI": "php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WP-CLI framework", - "homepage": "https://wp-cli.org", - "keywords": [ - "cli", - "wordpress" - ], - "support": { - "docs": "https://make.wordpress.org/cli/handbook/", - "issues": "https://github.com/wp-cli/wp-cli/issues", - "source": "https://github.com/wp-cli/wp-cli" - }, - "time": "2020-02-18T08:15:37+00:00" - }, - { - "name": "wp-cli/wp-cli-bundle", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/wp-cli-bundle.git", - "reference": "713bc75b2f88550920dedc4f2ad3e1daf9f76326" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-cli-bundle/zipball/713bc75b2f88550920dedc4f2ad3e1daf9f76326", - "reference": "713bc75b2f88550920dedc4f2ad3e1daf9f76326", - "shasum": "" - }, - "require": { - "cweagans/composer-patches": "^1.6", - "php": ">=5.4", - "wp-cli/cache-command": "^2", - "wp-cli/checksum-command": "^2", - "wp-cli/config-command": "^2", - "wp-cli/core-command": "^2", - "wp-cli/cron-command": "^2", - "wp-cli/db-command": "^2", - "wp-cli/embed-command": "^2", - "wp-cli/entity-command": "^2", - "wp-cli/eval-command": "^2", - "wp-cli/export-command": "^2", - "wp-cli/extension-command": "^2", - "wp-cli/i18n-command": "^2", - "wp-cli/import-command": "^2", - "wp-cli/language-command": "^2", - "wp-cli/maintenance-mode-command": "^2", - "wp-cli/media-command": "^2", - "wp-cli/package-command": "^2", - "wp-cli/rewrite-command": "^2", - "wp-cli/role-command": "^2", - "wp-cli/scaffold-command": "^2", - "wp-cli/search-replace-command": "^2", - "wp-cli/server-command": "^2", - "wp-cli/shell-command": "^2", - "wp-cli/super-admin-command": "^2", - "wp-cli/widget-command": "^2", - "wp-cli/wp-cli": "^2.4" - }, - "require-dev": { - "roave/security-advisories": "dev-master", - "wp-cli/wp-cli-tests": "^2.1" - }, - "suggest": { - "psy/psysh": "Enhanced `wp shell` functionality" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1.x-dev" - }, - "enable-patching": true - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WP-CLI bundle package with default commands.", - "homepage": "https://wp-cli.org", - "keywords": [ - "cli", - "wordpress" - ], - "support": { - "docs": "https://make.wordpress.org/cli/handbook/", - "issues": "https://github.com/wp-cli/wp-cli-bundle/issues", - "source": "https://github.com/wp-cli/wp-cli-bundle" - }, - "time": "2019-11-12T17:43:58+00:00" - }, - { - "name": "wp-cli/wp-config-transformer", - "version": "v1.2.8", - "source": { - "type": "git", - "url": "https://github.com/wp-cli/wp-config-transformer.git", - "reference": "0bb2b9162c38ca72370380aea11dc06e431e13a5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-config-transformer/zipball/0bb2b9162c38ca72370380aea11dc06e431e13a5", - "reference": "0bb2b9162c38ca72370380aea11dc06e431e13a5", - "shasum": "" - }, - "require": { - "php": ">=5.3.29" - }, - "require-dev": { - "composer/composer": ">=1.5.6 <1.7.0 || ^1.7.1 || ^2.0.0", - "phpunit/phpunit": "^6.5.5 || ^7.0.0", - "wp-coding-standards/wpcs": "^0.14.0 || ^1.0.0 || ^2.0.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/WPConfigTransformer.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frankie Jarrett", - "email": "fjarrett@gmail.com" - } - ], - "description": "Programmatically edit a wp-config.php file.", - "support": { - "issues": "https://github.com/wp-cli/wp-config-transformer/issues", - "source": "https://github.com/wp-cli/wp-config-transformer/tree/v1.2.8" - }, - "time": "2020-11-12T08:08:10+00:00" - }, - { - "name": "wp-coding-standards/wpcs", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7da1894633f168fe244afc6de00d141f27517b62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", - "reference": "7da1894633f168fe244afc6de00d141f27517b62", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", - "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", - "keywords": [ - "phpcs", - "standards", - "wordpress" - ], - "support": { - "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", - "source": "https://github.com/WordPress/WordPress-Coding-Standards", - "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" - }, - "time": "2020-05-13T23:57:56+00:00" - }, - { - "name": "zendframework/zend-code", - "version": "3.4.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-code.git", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/268040548f92c2bfcba164421c1add2ba43abaaa", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa", - "shasum": "" - }, - "require": { - "php": "^7.1", - "zendframework/zend-eventmanager": "^2.6 || ^3.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "require-dev": { - "doctrine/annotations": "^1.7", - "ext-phar": "*", - "phpunit/phpunit": "^7.5.16 || ^8.4", - "zendframework/zend-coding-standard": "^1.0", - "zendframework/zend-stdlib": "^2.7 || ^3.0" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "zendframework/zend-stdlib": "Zend\\Stdlib component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4.x-dev", - "dev-develop": "3.5.x-dev", - "dev-dev-4.0": "4.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "keywords": [ - "ZendFramework", - "code", - "zf" - ], - "support": { - "chat": "https://zendframework-slack.herokuapp.com", - "docs": "https://docs.zendframework.com/zend-code/", - "forum": "https://discourse.zendframework.com/c/questions/components", - "issues": "https://github.com/zendframework/zend-code/issues", - "rss": "https://github.com/zendframework/zend-code/releases.atom", - "source": "https://github.com/zendframework/zend-code" - }, - "abandoned": "laminas/laminas-code", - "time": "2019-12-10T19:21:15+00:00" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "athletic/athletic": "^0.1", - "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0" - }, - "suggest": { - "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev", - "dev-develop": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Trigger and listen to events within a PHP application", - "homepage": "https://github.com/zendframework/zend-eventmanager", - "keywords": [ - "event", - "eventmanager", - "events", - "zf2" - ], - "support": { - "issues": "https://github.com/zendframework/zend-eventmanager/issues", - "source": "https://github.com/zendframework/zend-eventmanager/tree/master" - }, - "abandoned": "laminas/laminas-eventmanager", - "time": "2018-04-25T15:33:34+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "wp-cli/wp-cli-bundle": 0 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.0.0" -} diff --git a/css/dashboard.css b/css/dashboard.css deleted file mode 100644 index 91a8d62e..00000000 --- a/css/dashboard.css +++ /dev/null @@ -1,19 +0,0 @@ -#ab_chart { - color: #a7aaad; - height: 140px; - margin: 0 -4px; - text-align: center; -} - -#ab_chart_data { - display: none; -} - -#ab_widget .inside { - height: 1%; - margin: 0; - padding-bottom: 0; - overflow: hidden; - position: relative; - white-space: nowrap; -} diff --git a/css/styles.css b/css/styles.css deleted file mode 100644 index a6177e82..00000000 --- a/css/styles.css +++ /dev/null @@ -1,265 +0,0 @@ -/* @group General */ - -.ab-main *, -.ab-main *::after, -.ab-main *::before { - border: 0; - margin: 0; - padding: 0; - outline: 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -/* @end group */ - -/* @group Columns */ - -.ab-wrap { - margin: 0 0 0 -10px; - padding: 20px 0 0 0; - text-rendering: optimizeLegibility; /* stylelint-disable-line value-keyword-case */ -} - -.ab-column { - float: left; - margin: 0 0 0 10px; - position: relative; -} - -/* @end group */ - -/* @group Headlines + Icons */ - -.ab-column h3 { - margin: 0; - font-size: 18px; - font-weight: normal; - line-height: 20px; - color: #1d2327; -} - -.ab-column h3.icon::before { - font: normal 30px/30px Dashicons; - top: 4px; - right: 20px; - speak: none; - width: 1em; - color: #8c8f94; - position: absolute; - text-align: center; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.ab-column.ab-arrow h3.icon::before { - content: "\f536"; -} - -.ab-column.ab-join h3.icon::before { - content: "\f108"; -} - -.ab-column.ab-diff h3.icon::before { - content: "\f237"; -} - -.ab-column h6 { - clear: both; - color: #3c434a; - margin: 0 0 20px; - font-weight: normal; - font-size: 13px; -} - -/* @end group */ - -/* @group Form */ - -.ab-column input[type="text"], -.ab-column input[type="number"], -.ab-column select { - font-size: 13px; - text-align: center; - background: #f6f7f7; -} - -.ab-column input[type="number"] { - padding: 0; -} - -.ab-column select[multiple] { - width: 175px; - min-height: 60px; -} - -.ab-column select[multiple][name="ab_ignore_reasons[]"] { - width: auto; -} - -.ab-column input.ab-mini-field { - width: 40px; -} - -.ab-column .ab-medium-field { - width: 100%; - max-width: 285px; -} - -.ab-column input[type="text"] + label, -.ab-column select + label { - color: #8c8f94; - margin: 0 0 0 7px; - display: inline-block; - text-transform: uppercase; -} - -/* @end group */ - -/* @group Column contents */ - -.ab-column > ul { - padding: 0 20px 0 0; -} - -.ab-column:last-of-type > ul { - border: 0; -} - -.ab-column > ul > li { - width: 330px; - margin: 0 0 36px; - padding: 10px 0 12px 12px; - position: relative; - background: #fff; -} - -.ab-column > ul > li a { - text-decoration: underline; -} - -.ab-column > ul > li a:hover { - border-color: inherit; -} - -.ab-column > ul > li label { - cursor: default; - display: inline-block; - font-size: 14px; - max-width: 286px; - color: #1d2327; -} - -.ab-column > ul > li label span { - color: #3c434a; - display: block; - font-size: 13px; - line-height: 16px; - margin-top: 5px; -} - -/* @end group */ - -/* @group Separator */ - -.ab-column > ul > li::after, -.ab-column > ul > li::before { - width: 0; - content: ""; - position: absolute; -} - -.ab-column.ab-arrow > ul > li::before, -.ab-column.ab-arrow > ul > li::after { - left: 157px; - border-width: 10px 10px 0; - border-style: solid; -} - -.ab-column.ab-arrow > ul > li::before { - bottom: -24px; - border-color: #fff transparent; -} - -.ab-column.ab-arrow > ul > li::after { - bottom: -22px; - border-color: #f0f0f1 transparent; -} - -.ab-column.ab-join > ul > li::before { - left: 171px; - bottom: -27px; - height: 18px; - border-right: 2px solid #fff; -} - -.ab-column.ab-diff > ul > li::before { - left: 162px; - bottom: -19px; - width: 18px; - height: 0; - border-bottom: 2px solid #fff; -} - -/* @end group */ - -/* @group Submit & Service */ - -.ab-column--submit-service { - width: 342px; - margin-top: 20px; - padding-right: 20px; -} - -.ab-column--submit-service p { - padding: 5px 0; - margin: 0; - text-align: center; - width: 100%; -} - -.ab-column--submit-service p:first-of-type { - border-top: 1px solid #dcdcde; -} - -.ab-column--submit-service p:last-of-type { - border-bottom: 1px solid #dcdcde; -} - -.ab-column--submit-service .button { - width: 100%; - margin: 35px 0 10px; -} - -/* @end group */ - -/* @group 2nd level */ - -.ab-column > ul > li:last-of-type::after, -.ab-column > ul > li:last-of-type::before { - display: none; -} - -.ab-column > ul > li > ul { - margin: 10px 10px 0 26px; - display: none; -} - -.ab-column > ul > li > ul li { - padding: 2px 0; -} - -.ab-column > ul > li > ul label { - margin: 0 0 0 7px; -} - -.ab-column > ul > li > ul label[for="ab_ignore_reasons"] { - margin: 0 0 5px 0; -} - -.ab-column > ul > li > input[type="checkbox"]:checked ~ ul { - display: block; -} - -/* @end group */ diff --git a/inc/columns.class.php b/inc/columns.class.php deleted file mode 100644 index f0802fa3..00000000 --- a/inc/columns.class.php +++ /dev/null @@ -1,160 +0,0 @@ - esc_html__( 'Spam Reason', 'antispam-bee' ), - ) - ); - } - - /** - * Display plugin column values on comments screen - * - * @since 2.6.0 - * @change 2.6.0 - * - * @param string $column Currently selected column. - * @param integer $comment_id Comment ID. - */ - public static function print_plugin_column( $column, $comment_id ) { - if ( 'antispam_bee_reason' !== $column ) { - return; - } - - $spam_reason = get_comment_meta( $comment_id, $column, true ); - $spam_reasons = Antispam_Bee::$defaults['reasons']; - - if ( empty( $spam_reason ) || empty( $spam_reasons[ $spam_reason ] ) ) { - return; - } - - echo esc_html( $spam_reasons[ $spam_reason ] ); - } - - /** - * Register plugin sortable columns on comments screen - * - * @since 2.6.3 - * @change 2.6.3 - * - * @param array $columns Registered columns. - * @return array $columns Columns with AB field. - */ - public static function register_sortable_columns( $columns ) { - $columns['antispam_bee_reason'] = 'antispam_bee_reason'; - - return $columns; - } - - // phpcs:disable WordPress.VIP.SlowDBQuery.slow_db_query_meta_key - // phpcs:disable WordPress.CSRF.NonceVerification.NoNonceVerification - /** - * Adjust orderby query - * - * @since 2.6.3 - * @change 2.6.3 - * - * @param \WP_Comment_Query $query Current WordPress query. - */ - public static function set_orderby_query( $query ) { - $orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : ''; - - if ( empty( $orderby ) || 'antispam_bee_reason' !== $orderby ) { - return; - } - - $query->query_vars['meta_key'] = 'antispam_bee_reason'; - $query->query_vars['orderby'] = 'meta_value'; - } - // phpcs:enable WordPress.VIP.SlowDBQuery.slow_db_query_meta_key - // phpcs:enable WordPress.CSRF.NonceVerification.NoNonceVerification - - //phpcs:disable WordPress.CSRF.NonceVerification.NoNonceVerification - /** - * Filter comments by the spam reason - * - * @global \wpdb $wpdb - */ - public static function filter_columns() { - global $wpdb; - ?> - - - query_vars['meta_key'] = 'antispam_bee_reason'; - $query->query_vars['meta_value'] = $spam_reason; - } - //phpcs:enable WordPress.VIP.SlowDBQuery.slow_db_query_meta_key - //phpcs:enable WordPress.VIP.SlowDBQuery.slow_db_query_meta_value - //phpcs:enable WordPress.CSRF.NonceVerification.NoNonceVerification - - /** - * Print CSS for the plugin column - * - * @since 2.6.1 - * @change 2.6.1 - */ - public static function print_column_styles() { - ?> - - (int) ( ! empty( $_POST['ab_flag_spam'] ) ), - 'email_notify' => (int) ( ! empty( $_POST['ab_email_notify'] ) ), - 'cronjob_enable' => (int) ( ! empty( $_POST['ab_cronjob_enable'] ) ), - 'cronjob_interval' => (int) self::get_key( $_POST, 'ab_cronjob_interval' ), - - 'no_notice' => (int) ( ! empty( $_POST['ab_no_notice'] ) ), - - 'dashboard_count' => (int) ( ! empty( $_POST['ab_dashboard_count'] ) ), - 'dashboard_chart' => (int) ( ! empty( $_POST['ab_dashboard_chart'] ) ), - 'regexp_check' => (int) ( ! empty( $_POST['ab_regexp_check'] ) ), - 'spam_ip' => (int) ( ! empty( $_POST['ab_spam_ip'] ) ), - 'already_commented' => (int) ( ! empty( $_POST['ab_already_commented'] ) ), - 'time_check' => (int) ( ! empty( $_POST['ab_time_check'] ) ), - - 'ignore_pings' => (int) ( ! empty( $_POST['ab_ignore_pings'] ) ), - 'ignore_filter' => (int) ( ! empty( $_POST['ab_ignore_filter'] ) ), - 'ignore_type' => (int) self::get_key( $_POST, 'ab_ignore_type' ), - - 'reasons_enable' => (int) ( ! empty( $_POST['ab_reasons_enable'] ) ), - 'ignore_reasons' => (array) self::get_key( $_POST, 'ab_ignore_reasons' ), - - 'bbcode_check' => (int) ( ! empty( $_POST['ab_bbcode_check'] ) ), - 'gravatar_check' => (int) ( ! empty( $_POST['ab_gravatar_check'] ) ), - 'country_code' => (int) ( ! empty( $_POST['ab_country_code'] ) ), - 'country_denied' => sanitize_text_field( wp_unslash( self::get_key( $_POST, 'ab_country_denied' ) ) ), - 'country_allowed' => sanitize_text_field( wp_unslash( self::get_key( $_POST, 'ab_country_allowed' ) ) ), - - 'translate_api' => (int) ( ! empty( $_POST['ab_translate_api'] ) ), - 'translate_lang' => $selected_languages, - - 'delete_data_on_uninstall' => (int) ( ! empty( $_POST['delete_data_on_uninstall'] ) ), - - 'use_output_buffer' => (int) ( ! empty( $_POST['ab_use_output_buffer'] ) ), - - ); - - foreach ( $options['ignore_reasons'] as $key => $val ) { - if ( ! isset( self::$defaults['reasons'][ $val ] ) ) { - unset( $options['ignore_reasons'][ $key ] ); - } - } - - if ( empty( $options['cronjob_interval'] ) ) { - $options['cronjob_enable'] = 0; - } - - if ( empty( $options['translate_lang'] ) ) { - $options['translate_api'] = 0; - } - - if ( empty( $options['reasons_enable'] ) ) { - $options['ignore_reasons'] = array(); - } - - if ( ! empty( $options['country_denied'] ) ) { - $options['country_denied'] = preg_replace( - '/[^A-Z ,;]/', - '', - strtoupper( $options['country_denied'] ) - ); - } - - if ( ! empty( $options['country_allowed'] ) ) { - $options['country_allowed'] = preg_replace( - '/[^A-Z ,;]/', - '', - strtoupper( $options['country_allowed'] ) - ); - } - - if ( empty( $options['country_denied'] ) && empty( $options['country_allowed'] ) ) { - $options['country_code'] = 0; - } - - if ( $options['cronjob_enable'] && ! self::get_option( 'cronjob_enable' ) ) { - self::init_scheduled_hook(); - } elseif ( ! $options['cronjob_enable'] && self::get_option( 'cronjob_enable' ) ) { - self::clear_scheduled_hook(); - } - - self::update_options( $options ); - - wp_safe_redirect( - add_query_arg( - array( - 'updated' => 'true', - ), - wp_get_referer() - ) - ); - - die(); - } - - /** - * Generation of a selectbox - * - * @since 2.4.5 - * - * @param string $name Name of the Selectbox. - * @param array $data Array with values. - * @param string $selected Selected value. - * @return string $html Generated HTML. - */ - private static function _build_select( $name, $data, $selected ) { - $html = ''; - - return $html; - } - - - /** - * Display the GUI - * - * @since 0.1 - * @since 2.7.0 - * @since 2.10.0 Change documentation links, change country option name, and add option to parse complete markup for comment forms - */ - public static function options_page() { ?> -
-

- Antispam Bee -

- -
- - - - - -
- -
-

- -

-
- -
- -
    -
  • - /> - -
  • - - -
  • - /> - -
  • - - -
  • - /> - -
  • - -
  • - /> - -
  • - - -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - - -
      - ', - esc_url( - __( 'https://www.iso.org/iso/country_names_and_code_elements', 'antispam-bee' ), - 'https' - ) - ); - ?> -
    • - - -
    • -
    • - - -
    • -
    -
  • - -
  • - /> - - -
      -
    • - - -
    • -
    -
  • -
-
- -
-

- -

-
- -
- -
    -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - - -
      -
    • - - -
    • -
    -
  • - -
  • - /> - -
  • -
- -
- - -
-

- -

-
- -
- -
    -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - -
  • - -
  • - /> - -
  • -
-
- -
-

- -

-

- -

-

- -

-

- -

- - -
-
-
-
- __( 'German', 'antispam-bee' ), - 'en' => __( 'English', 'antispam-bee' ), - 'fr' => __( 'French', 'antispam-bee' ), - 'it' => __( 'Italian', 'antispam-bee' ), - 'es' => __( 'Spanish', 'antispam-bee' ), - ); - - /** - * Filter the possible languages for the language spam test - * - * @since 2.7.1 - * @param (array) $lang The languages - * @return (array) - */ - return apply_filters( 'ab_get_allowed_translate_languages', $lang ); - } -} diff --git a/js/dashboard.js b/js/dashboard.js deleted file mode 100644 index 94d1783e..00000000 --- a/js/dashboard.js +++ /dev/null @@ -1,112 +0,0 @@ -( function() { - // Grab the data - var labels = [], - data = []; - jQuery( '#ab_chart_data tfoot th' ).each( function() { - labels.push( jQuery( this ).text() ); - } ); - jQuery( '#ab_chart_data tbody td' ).each( function() { - data.push( jQuery( this ).text() ); - } ); - - // Draw - var width = jQuery( '#ab_chart' ).parent().width() + 8, - height = 140, - leftgutter = 0, - bottomgutter = 22, - topgutter = 22, - color = '#135e96', - r = Raphael( 'ab_chart', width, height ), - txt = { font: 'bold 12px "Open Sans", sans-serif', fill: '#1d2327' }, - X = ( width - leftgutter * 2 ) / labels.length, - max = Math.max.apply( Math, data ), - Y = ( height - bottomgutter - topgutter ) / max; - - // Max value - r - .text( 16, 16, max ) - .attr( - { - font: 'normal 10px "Open Sans", sans-serif', - fill: '#a7aaad', - } - ); - - var path = r.path().attr( { stroke: color, 'stroke-width': 2, 'stroke-linejoin': 'round' } ), - bgp = r.path().attr( { stroke: 'none', opacity: .3, fill: color } ), - label = r.set(), - lx = 0, - ly = 0, - is_label_visible = false, - leave_timer, - blanket = r.set(); - label.push( r.text( 60, 12, '' ).attr( txt ) ); - label.push( r.text( 60, 27, '' ).attr( txt ).attr( { fill: color } ) ); - label.hide(); - var frame = r.popup( 100, 100, label, 'right' ).attr( { fill: '#fff', stroke: '#444', 'stroke-width': 1 } ).hide(); - - var p, bgpp; - for ( var i = 0, ii = labels.length; i < ii; i++ ) { - var y = Math.round( height - bottomgutter - Y * data[i] ), - x = Math.round( leftgutter + X * ( i + .5 ) ); - if ( ! i ) { - p = [ 'M', x, y, 'C', x, y ]; - bgpp = [ 'M', leftgutter + X * .5, height - bottomgutter, 'L', x, y, 'C', x, y ]; - } - if ( i && i < ii - 1 ) { - var Y0 = Math.round( height - bottomgutter - Y * data[i - 1] ), - X0 = Math.round( leftgutter + X * ( i - .5 ) ), - Y2 = Math.round( height - bottomgutter - Y * data[i + 1] ), - X2 = Math.round( leftgutter + X * ( i + 1.5 ) ); - var a = getAnchors( X0, Y0, x, y, X2, Y2 ); - p = p.concat( [ a.x1, a.y1, x, y, a.x2, a.y2 ] ); - bgpp = bgpp.concat( [ a.x1, a.y1, x, y, a.x2, a.y2 ] ); - } - var dot = r.circle( x, y, 4 ).attr( { fill: '#fff', stroke: color, 'stroke-width': 1 } ); - blanket.push( r.rect( leftgutter + X * i, 0, X, height - bottomgutter ).attr( { stroke: 'none', fill: '#fff', opacity: .2 } ) ); - var rect = blanket[blanket.length - 1]; - ( function( x, y, data, date, dot ) { - var timer, - i = 0; - rect.hover( function() { - clearTimeout( leave_timer ); - var side = 'right'; - if ( x + frame.getBBox().width > width ) { - side = 'left'; - } - // set label content to determine correct dimensions - label[0].attr( { text: date } ); - label[1].attr( { text: data + '× Spam' } ); - var ppp = r.popup( x, y, label, side, 1 ), - anim = Raphael.animation( { - path: ppp.path, - transform: [ 't', ppp.dx, ppp.dy ], - }, 200 * is_label_visible ); - lx = label[0].transform()[0][1] + ppp.dx; - ly = label[0].transform()[0][2] + ppp.dy; - frame.show().stop().animate( anim ); - - label[0].show().stop().animateWith( frame, anim, { transform: [ 't', lx, ly ] }, 200 * is_label_visible ); - label[1].show().stop().animateWith( frame, anim, { transform: [ 't', lx, ly ] }, 200 * is_label_visible ); - dot.attr( 'r', 6 ); - is_label_visible = true; - }, function() { - dot.attr( 'r', 4 ); - leave_timer = setTimeout( function() { - frame.hide(); - label[0].hide(); - label[1].hide(); - is_label_visible = false; - }, 1 ); - } ); - }( x, y, data[i], labels[i], dot ) ); - } - p = p.concat( [ x, y, x, y ] ); - bgpp = bgpp.concat( [ x, y, x, y, 'L', x, height - bottomgutter, 'z' ] ); - path.attr( { path: p } ); - bgp.attr( { path: bgpp } ); - frame.toFront(); - label[0].toFront(); - label[1].toFront(); - blanket.toFront(); -}() ); diff --git a/js/raphael.helper.js b/js/raphael.helper.js deleted file mode 100644 index b7a066d3..00000000 --- a/js/raphael.helper.js +++ /dev/null @@ -1,140 +0,0 @@ -var tokenRegex = /\{([^\}]+)\}/g, - objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, - replacer = function( all, key, obj ) { - var res = obj; - key.replace( objNotationRegex, function( all, name, quote, quotedName, isFunc ) { - name = name || quotedName; - if ( res ) { - if ( name in res ) { - res = res[name]; - } - typeof res === 'function' && isFunc && ( res = res() ); - } - } ); - res = ( res == null || res == obj ? all : res ) + ''; - return res; - }, - fill = function( str, obj ) { - return String( str ).replace( tokenRegex, function( all, key ) { - return replacer( all, key, obj ); - } ); - }; - -Raphael.fn.popup = function( X, Y, set, pos, ret ) { - pos = String( pos || 'top-middle' ).split( '-' ); - pos[1] = pos[1] || 'middle'; - var r = 5, - bb = set.getBBox(), - w = Math.round( bb.width ), - h = Math.round( bb.height ), - x = Math.round( bb.x ) - r, - y = Math.round( bb.y ) - r, - gap = Math.min( h / 2, w / 2, 10 ), - shapes = { - top: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}l-{right},0-{gap},{gap}-{gap}-{gap}-{left},0a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', - bottom: 'M{x},{y}l{left},0,{gap}-{gap},{gap},{gap},{right},0a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', - right: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}l0-{bottom}-{gap}-{gap},{gap}-{gap},0-{top}a{r},{r},0,0,1,{r}-{r}z', - left: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}l0,{top},{gap},{gap}-{gap},{gap},0,{bottom}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', - }, - offset = { - hx0: X - ( x + r + w - gap * 2 ), - hx1: X - ( x + r + w / 2 - gap ), - hx2: X - ( x + r + gap ), - vhy: Y - ( y + r + h + r + gap ), - '^hy': Y - ( y - gap ), - - }, - mask = [ { - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - right: 0, - left: w - gap * 2, - bottom: 0, - top: h - gap * 2, - r: r, - h: h, - gap: gap, - }, { - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - left: w / 2 - gap, - right: w / 2 - gap, - top: h / 2 - gap, - bottom: h / 2 - gap, - r: r, - h: h, - gap: gap, - }, { - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - left: 0, - right: w - gap * 2, - top: 0, - bottom: h - gap * 2, - r: r, - h: h, - gap: gap, - } ][pos[1] == 'middle' ? 1 : ( pos[1] == 'top' || pos[1] == 'left' ) * 2]; - var dx = 0, - dy = 0, - out = this.path( fill( shapes[pos[0]], mask ) ).insertBefore( set ); - switch ( pos[0] ) { - case 'top': - dx = X - ( x + r + mask.left + gap ); - dy = Y - ( y + r + h + r + gap ); - break; - case 'bottom': - dx = X - ( x + r + mask.left + gap ); - dy = Y - ( y - gap ); - break; - case 'left': - dx = X - ( x + r + w + r + gap ); - dy = Y - ( y + r + mask.top + gap ); - break; - case 'right': - dx = X - ( x - gap ); - dy = Y - ( y + r + mask.top + gap ); - break; - } - out.translate( dx, dy ); - if ( ret ) { - ret = out.attr( 'path' ); - out.remove(); - return { - path: ret, - dx: dx, - dy: dy, - }; - } - set.translate( dx, dy ); - return out; -}; - -function getAnchors( p1x, p1y, p2x, p2y, p3x, p3y ) { - var l1 = ( p2x - p1x ) / 2, - l2 = ( p3x - p2x ) / 2, - a = Math.atan( ( p2x - p1x ) / Math.abs( p2y - p1y ) ), - b = Math.atan( ( p3x - p2x ) / Math.abs( p2y - p3y ) ); - a = p1y < p2y ? Math.PI - a : a; - b = p3y < p2y ? Math.PI - b : b; - var alpha = Math.PI / 2 - ( ( a + b ) % ( Math.PI * 2 ) ) / 2, - dx1 = l1 * Math.sin( alpha + a ), - dy1 = l1 * Math.cos( alpha + a ), - dx2 = l2 * Math.sin( alpha + b ), - dy2 = l2 * Math.cos( alpha + b ); - return { - x1: p2x - dx1, - y1: p2y + dy1, - x2: p2x + dx2, - y2: p2y + dy2, - }; -} diff --git a/js/raphael.min.js b/js/raphael.min.js deleted file mode 100644 index 2fb91046..00000000 --- a/js/raphael.min.js +++ /dev/null @@ -1,3 +0,0 @@ -!function t(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports.Raphael=r():e.Raphael=r()}(this,function(){return function(t){function e(i){if(r[i])return r[i].exports;var n=r[i]={exports:{},id:i,loaded:!1};return t[i].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){var i,n;i=[r(1),r(3),r(4)],n=function(t){return t}.apply(e,i),!(void 0!==n&&(t.exports=n))},function(t,e,r){var i,n;i=[r(2)],n=function(t){function e(r){if(e.is(r,"function"))return w?r():t.on("raphael.DOMload",r);if(e.is(r,Q))return e._engine.create[z](e,r.splice(0,3+e.is(r[0],$))).add(r);var i=Array.prototype.slice.call(arguments,0);if(e.is(i[i.length-1],"function")){var n=i.pop();return w?n.call(e._engine.create[z](e,i)):t.on("raphael.DOMload",function(){n.call(e._engine.create[z](e,i))})}return e._engine.create[z](e,arguments)}function r(t){if("function"==typeof t||Object(t)!==t)return t;var e=new t.constructor;for(var i in t)t[A](i)&&(e[i]=r(t[i]));return e}function i(t,e){for(var r=0,i=t.length;r=1e3&&delete o[l.shift()],l.push(s),o[s]=t[z](e,a),r?r(o[s]):o[s])}return n}function a(){return this.hex}function s(t,e){for(var r=[],i=0,n=t.length;n-2*!e>i;i+=2){var a=[{x:+t[i-2],y:+t[i-1]},{x:+t[i],y:+t[i+1]},{x:+t[i+2],y:+t[i+3]},{x:+t[i+4],y:+t[i+5]}];e?i?n-4==i?a[3]={x:+t[0],y:+t[1]}:n-2==i&&(a[2]={x:+t[0],y:+t[1]},a[3]={x:+t[2],y:+t[3]}):a[0]={x:+t[n-2],y:+t[n-1]}:n-4==i?a[3]=a[2]:i||(a[0]={x:+t[i],y:+t[i+1]}),r.push(["C",(-a[0].x+6*a[1].x+a[2].x)/6,(-a[0].y+6*a[1].y+a[2].y)/6,(a[1].x+6*a[2].x-a[3].x)/6,(a[1].y+6*a[2].y-a[3].y)/6,a[2].x,a[2].y])}return r}function o(t,e,r,i,n){var a=-3*e+9*r-9*i+3*n,s=t*a+6*e-12*r+6*i;return t*s-3*e+3*r}function l(t,e,r,i,n,a,s,l,h){null==h&&(h=1),h=h>1?1:h<0?0:h;for(var u=h/2,c=12,f=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],p=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],d=0,g=0;gd;)c/=2,f+=(pW(n,s)||W(e,i)W(a,o))){var l=(t*i-e*r)*(n-s)-(t-r)*(n*o-a*s),h=(t*i-e*r)*(a-o)-(e-i)*(n*o-a*s),u=(t-r)*(a-o)-(e-i)*(n-s);if(u){var c=l/u,f=h/u,p=+c.toFixed(2),d=+f.toFixed(2);if(!(p<+G(t,r).toFixed(2)||p>+W(t,r).toFixed(2)||p<+G(n,s).toFixed(2)||p>+W(n,s).toFixed(2)||d<+G(e,i).toFixed(2)||d>+W(e,i).toFixed(2)||d<+G(a,o).toFixed(2)||d>+W(a,o).toFixed(2)))return{x:c,y:f}}}}function c(t,e){return p(t,e)}function f(t,e){return p(t,e,1)}function p(t,r,i){var n=e.bezierBBox(t),a=e.bezierBBox(r);if(!e.isBBoxIntersect(n,a))return i?0:[];for(var s=l.apply(0,t),o=l.apply(0,r),h=W(~~(s/5),1),c=W(~~(o/5),1),f=[],p=[],d={},g=i?0:[],v=0;v=0&&S<=1.001&&A>=0&&A<=1.001&&(i?g++:g.push({x:C.x,y:C.y,t1:G(S,1),t2:G(A,1)}))}}return g}function d(t,r,i){t=e._path2curve(t),r=e._path2curve(r);for(var n,a,s,o,l,h,u,c,f,d,g=i?0:[],v=0,x=t.length;vi)return i;for(;ra?r=n:i=n,n=(i-r)/2+r}return n}var h=3*e,u=3*(i-e)-h,c=1-h-u,f=3*r,p=3*(n-r)-f,d=1-f-p;return o(t,1/(200*a))}function m(t,e){var r=[],i={};if(this.ms=e,this.times=1,t){for(var n in t)t[A](n)&&(i[ht(n)]=t[n],r.push(ht(n)));r.sort(Bt)}this.anim=i,this.top=r[r.length-1],this.percents=r}function b(r,i,n,a,s,o){n=ht(n);var l,h,u,c=[],f,p,d,v=r.ms,x={},m={},b={};if(a)for(w=0,B=Ee.length;wa*r.top){n=r.percents[w],p=r.percents[w-1]||0,v=v/r.top*(n-p),f=r.percents[w+1],l=r.anim[n];break}a&&i.attr(r.anim[r.percents[w]])}if(l){if(h)h.initstatus=a,h.start=new Date-h.ms*a;else{for(var C in l)if(l[A](C)&&(pt[A](C)||i.paper.customAttributes[A](C)))switch(x[C]=i.attr(C),null==x[C]&&(x[C]=ft[C]),m[C]=l[C],pt[C]){case $:b[C]=(m[C]-x[C])/v;break;case"colour":x[C]=e.getRGB(x[C]);var S=e.getRGB(m[C]);b[C]={r:(S.r-x[C].r)/v,g:(S.g-x[C].g)/v,b:(S.b-x[C].b)/v};break;case"path":var T=Qt(x[C],m[C]),E=T[1];for(x[C]=T[0],b[C]=[],w=0,B=x[C].length;w',Lt=Nt.firstChild,Lt.style.behavior="url(#default#VML)",!Lt||"object"!=typeof Lt.adj)return e.type=R;Nt=null}e.svg=!(e.vml="VML"==e.type),e._Paper=M,e.fn=N=M.prototype=e.prototype,e._id=0,e.is=function(t,e){return e=O.call(e),"finite"==e?!at[A](+t):"array"==e?t instanceof Array:"null"==e&&null===t||e==typeof t&&null!==t||"object"==e&&t===Object(t)||"array"==e&&Array.isArray&&Array.isArray(t)||tt.call(t).slice(8,-1).toLowerCase()==e},e.angle=function(t,r,i,n,a,s){if(null==a){var o=t-i,l=r-n;return o||l?(180+180*Y.atan2(-l,-o)/U+360)%360:0}return e.angle(t,r,a,s)-e.angle(i,n,a,s)},e.rad=function(t){return t%360*U/180},e.deg=function(t){return Math.round(180*t/U%360*1e3)/1e3},e.snapTo=function(t,r,i){if(i=e.is(i,"finite")?i:10,e.is(t,Q)){for(var n=t.length;n--;)if(H(t[n]-r)<=i)return t[n]}else{t=+t;var a=r%t;if(at-i)return r-a+t}return r};var zt=e.createUUID=function(t,e){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(t,e).toUpperCase()}}(/[xy]/g,function(t){var e=16*Y.random()|0,r="x"==t?e:3&e|8;return r.toString(16)});e.setWindow=function(r){t("raphael.setWindow",e,T.win,r),T.win=r,T.doc=T.win.document,e._engine.initWin&&e._engine.initWin(T.win)};var Pt=function(t){if(e.vml){var r=/^\s+|\s+$/g,i;try{var a=new ActiveXObject("htmlfile");a.write(""),a.close(),i=a.body}catch(s){i=createPopup().document.body}var o=i.createTextRange();Pt=n(function(t){try{i.style.color=I(t).replace(r,R);var e=o.queryCommandValue("ForeColor");return e=(255&e)<<16|65280&e|(16711680&e)>>>16,"#"+("000000"+e.toString(16)).slice(-6)}catch(n){return"none"}})}else{var l=T.doc.createElement("i");l.title="Raphaël Colour Picker",l.style.display="none",T.doc.body.appendChild(l),Pt=n(function(t){return l.style.color=t,T.doc.defaultView.getComputedStyle(l,R).getPropertyValue("color")})}return Pt(t)},Ft=function(){return"hsb("+[this.h,this.s,this.b]+")"},Rt=function(){return"hsl("+[this.h,this.s,this.l]+")"},jt=function(){return this.hex},It=function(t,r,i){if(null==r&&e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t&&(i=t.b,r=t.g,t=t.r),null==r&&e.is(t,Z)){var n=e.getRGB(t);t=n.r,r=n.g,i=n.b}return(t>1||r>1||i>1)&&(t/=255,r/=255,i/=255),[t,r,i]},qt=function(t,r,i,n){t*=255,r*=255,i*=255;var a={r:t,g:r,b:i,hex:e.rgb(t,r,i),toString:jt};return e.is(n,"finite")&&(a.opacity=n),a};e.color=function(t){var r;return e.is(t,"object")&&"h"in t&&"s"in t&&"b"in t?(r=e.hsb2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):e.is(t,"object")&&"h"in t&&"s"in t&&"l"in t?(r=e.hsl2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):(e.is(t,"string")&&(t=e.getRGB(t)),e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t?(r=e.rgb2hsl(t),t.h=r.h,t.s=r.s,t.l=r.l,r=e.rgb2hsb(t),t.v=r.b):(t={hex:"none"},t.r=t.g=t.b=t.h=t.s=t.v=t.l=-1)),t.toString=jt,t},e.hsb2rgb=function(t,e,r,i){this.is(t,"object")&&"h"in t&&"s"in t&&"b"in t&&(r=t.b,e=t.s,i=t.o,t=t.h),t*=360;var n,a,s,o,l;return t=t%360/60,l=r*e,o=l*(1-H(t%2-1)),n=a=s=r-l,t=~~t,n+=[l,o,0,0,o,l][t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],qt(n,a,s,i)},e.hsl2rgb=function(t,e,r,i){this.is(t,"object")&&"h"in t&&"s"in t&&"l"in t&&(r=t.l,e=t.s,t=t.h),(t>1||e>1||r>1)&&(t/=360,e/=100,r/=100),t*=360;var n,a,s,o,l;return t=t%360/60,l=2*e*(r<.5?r:1-r),o=l*(1-H(t%2-1)),n=a=s=r-l/2,t=~~t,n+=[l,o,0,0,o,l][t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],qt(n,a,s,i)},e.rgb2hsb=function(t,e,r){r=It(t,e,r),t=r[0],e=r[1],r=r[2];var i,n,a,s;return a=W(t,e,r),s=a-G(t,e,r),i=0==s?null:a==t?(e-r)/s:a==e?(r-t)/s+2:(t-e)/s+4,i=(i+360)%6*60/360,n=0==s?0:s/a,{h:i,s:n,b:a,toString:Ft}},e.rgb2hsl=function(t,e,r){r=It(t,e,r),t=r[0],e=r[1],r=r[2];var i,n,a,s,o,l;return s=W(t,e,r),o=G(t,e,r),l=s-o,i=0==l?null:s==t?(e-r)/l:s==e?(r-t)/l+2:(t-e)/l+4,i=(i+360)%6*60/360,a=(s+o)/2,n=0==l?0:a<.5?l/(2*a):l/(2-2*a),{h:i,s:n,l:a,toString:Rt}},e._path2string=function(){return this.join(",").replace(xt,"$1")};var Dt=e._preload=function(t,e){var r=T.doc.createElement("img");r.style.cssText="position:absolute;left:-9999em;top:-9999em",r.onload=function(){e.call(this),this.onload=null,T.doc.body.removeChild(this)},r.onerror=function(){T.doc.body.removeChild(this)},T.doc.body.appendChild(r),r.src=t};e.getRGB=n(function(t){if(!t||(t=I(t)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:a};if("none"==t)return{r:-1,g:-1,b:-1,hex:"none",toString:a};!(vt[A](t.toLowerCase().substring(0,2))||"#"==t.charAt())&&(t=Pt(t));var r,i,n,s,o,l,h,u=t.match(nt);return u?(u[2]&&(s=ut(u[2].substring(5),16),n=ut(u[2].substring(3,5),16),i=ut(u[2].substring(1,3),16)),u[3]&&(s=ut((l=u[3].charAt(3))+l,16),n=ut((l=u[3].charAt(2))+l,16),i=ut((l=u[3].charAt(1))+l,16)),u[4]&&(h=u[4][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),"rgba"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100)),u[5]?(h=u[5][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),("deg"==h[0].slice(-3)||"°"==h[0].slice(-1))&&(i/=360),"hsba"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100),e.hsb2rgb(i,n,s,o)):u[6]?(h=u[6][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),("deg"==h[0].slice(-3)||"°"==h[0].slice(-1))&&(i/=360),"hsla"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100),e.hsl2rgb(i,n,s,o)):(u={r:i,g:n,b:s,toString:a},u.hex="#"+(16777216|s|n<<8|i<<16).toString(16).slice(1),e.is(o,"finite")&&(u.opacity=o),u)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:a}},e),e.hsb=n(function(t,r,i){return e.hsb2rgb(t,r,i).hex}),e.hsl=n(function(t,r,i){return e.hsl2rgb(t,r,i).hex}),e.rgb=n(function(t,e,r){function i(t){return t+.5|0}return"#"+(16777216|i(r)|i(e)<<8|i(t)<<16).toString(16).slice(1)}),e.getColor=function(t){var e=this.getColor.start=this.getColor.start||{h:0,s:1,b:t||.75},r=this.hsb2rgb(e.h,e.s,e.b);return e.h+=.075,e.h>1&&(e.h=0,e.s-=.2,e.s<=0&&(this.getColor.start={h:0,s:1,b:e.b})),r.hex},e.getColor.reset=function(){delete this.start},e.parsePathString=function(t){if(!t)return null;var r=Vt(t);if(r.arr)return Yt(r.arr);var i={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},n=[];return e.is(t,Q)&&e.is(t[0],Q)&&(n=Yt(t)),n.length||I(t).replace(yt,function(t,e,r){var a=[],s=e.toLowerCase();if(r.replace(bt,function(t,e){e&&a.push(+e)}),"m"==s&&a.length>2&&(n.push([e][P](a.splice(0,2))),s="l",e="m"==e?"l":"L"),"r"==s)n.push([e][P](a));else for(;a.length>=i[s]&&(n.push([e][P](a.splice(0,i[s]))),i[s]););}),n.toString=e._path2string,r.arr=Yt(n),n},e.parseTransformString=n(function(t){if(!t)return null;var r={r:3,s:4,t:2,m:6},i=[];return e.is(t,Q)&&e.is(t[0],Q)&&(i=Yt(t)),i.length||I(t).replace(mt,function(t,e,r){var n=[],a=O.call(e);r.replace(bt,function(t,e){e&&n.push(+e)}),i.push([e][P](n))}),i.toString=e._path2string,i});var Vt=function(t){var e=Vt.ps=Vt.ps||{};return e[t]?e[t].sleep=100:e[t]={sleep:100},setTimeout(function(){for(var r in e)e[A](r)&&r!=t&&(e[r].sleep--,!e[r].sleep&&delete e[r])}),e[t]};e.findDotsAtSegment=function(t,e,r,i,n,a,s,o,l){var h=1-l,u=X(h,3),c=X(h,2),f=l*l,p=f*l,d=u*t+3*c*l*r+3*h*l*l*n+p*s,g=u*e+3*c*l*i+3*h*l*l*a+p*o,v=t+2*l*(r-t)+f*(n-2*r+t),x=e+2*l*(i-e)+f*(a-2*i+e),y=r+2*l*(n-r)+f*(s-2*n+r),m=i+2*l*(a-i)+f*(o-2*a+i),b=h*t+l*r,_=h*e+l*i,w=h*n+l*s,k=h*a+l*o,B=90-180*Y.atan2(v-y,x-m)/U;return(v>y||x=t.x&&e<=t.x2&&r>=t.y&&r<=t.y2},e.isBBoxIntersect=function(t,r){var i=e.isPointInsideBBox;return i(r,t.x,t.y)||i(r,t.x2,t.y)||i(r,t.x,t.y2)||i(r,t.x2,t.y2)||i(t,r.x,r.y)||i(t,r.x2,r.y)||i(t,r.x,r.y2)||i(t,r.x2,r.y2)||(t.xr.x||r.xt.x)&&(t.yr.y||r.yt.y)},e.pathIntersection=function(t,e){return d(t,e)},e.pathIntersectionNumber=function(t,e){return d(t,e,1)},e.isPointInsidePath=function(t,r,i){var n=e.pathBBox(t);return e.isPointInsideBBox(n,r,i)&&d(t,[["M",r,i],["H",n.x2+10]],1)%2==1},e._removedFactory=function(e){return function(){t("raphael.log",null,"Raphaël: you are calling to method “"+e+"” of removed object",e)}};var Ot=e.pathBBox=function(t){var e=Vt(t);if(e.bbox)return r(e.bbox);if(!t)return{x:0,y:0,width:0,height:0,x2:0,y2:0};t=Qt(t);for(var i=0,n=0,a=[],s=[],o,l=0,h=t.length;l1&&(b=Y.sqrt(b),r=b*r,i=b*i);var _=r*r,w=i*i,k=(s==o?-1:1)*Y.sqrt(H((_*w-_*m*m-w*y*y)/(_*m*m+w*y*y))),B=k*r*m/i+(t+l)/2,C=k*-i*y/r+(e+h)/2,S=Y.asin(((e-C)/i).toFixed(9)),A=Y.asin(((h-C)/i).toFixed(9));S=tA&&(S-=2*U),!o&&A>S&&(A-=2*U)}var T=A-S;if(H(T)>c){var E=A,M=l,N=h;A=S+c*(o&&A>S?1:-1),l=B+r*Y.cos(A),h=C+i*Y.sin(A),p=Ut(l,h,r,i,a,0,o,M,N,[A,E,B,C])}T=A-S;var L=Y.cos(S),z=Y.sin(S),F=Y.cos(A),R=Y.sin(A),j=Y.tan(T/4),I=4/3*r*j,D=4/3*i*j,V=[t,e],O=[t+I*z,e-D*L],W=[l+I*R,h-D*F],G=[l,h];if(O[0]=2*V[0]-O[0],O[1]=2*V[1]-O[1],u)return[O,W,G][P](p);p=[O,W,G][P](p).join()[q](",");for(var X=[],$=0,Z=p.length;$"1e12"&&(c=.5),H(f)>"1e12"&&(f=.5),c>0&&c<1&&(g=$t(t,e,r,i,n,a,s,o,c),d.push(g.x),p.push(g.y)),f>0&&f<1&&(g=$t(t,e,r,i,n,a,s,o,f),d.push(g.x),p.push(g.y)),l=a-2*i+e-(o-2*a+i),h=2*(i-e)-2*(a-i),u=e-i,c=(-h+Y.sqrt(h*h-4*l*u))/2/l,f=(-h-Y.sqrt(h*h-4*l*u))/2/l,H(c)>"1e12"&&(c=.5),H(f)>"1e12"&&(f=.5),c>0&&c<1&&(g=$t(t,e,r,i,n,a,s,o,c),d.push(g.x),p.push(g.y)),f>0&&f<1&&(g=$t(t,e,r,i,n,a,s,o,f),d.push(g.x),p.push(g.y)),{min:{x:G[z](0,d),y:G[z](0,p)},max:{x:W[z](0,d),y:W[z](0,p)}}}),Qt=e._path2curve=n(function(t,e){var r=!e&&Vt(t);if(!e&&r.curve)return Yt(r.curve);for(var i=Gt(t),n=e&&Gt(e),a={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},s={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},o=(function(t,e,r){var i,n,a={T:1,Q:1};if(!t)return["C",e.x,e.y,e.x,e.y,e.x,e.y];switch(!(t[0]in a)&&(e.qx=e.qy=null),t[0]){case"M":e.X=t[1],e.Y=t[2];break;case"A":t=["C"][P](Ut[z](0,[e.x,e.y][P](t.slice(1))));break;case"S":"C"==r||"S"==r?(i=2*e.x-e.bx,n=2*e.y-e.by):(i=e.x,n=e.y),t=["C",i,n][P](t.slice(1));break;case"T":"Q"==r||"T"==r?(e.qx=2*e.x-e.qx,e.qy=2*e.y-e.qy):(e.qx=e.x,e.qy=e.y),t=["C"][P](Xt(e.x,e.y,e.qx,e.qy,t[1],t[2]));break;case"Q":e.qx=t[1],e.qy=t[2],t=["C"][P](Xt(e.x,e.y,t[1],t[2],t[3],t[4]));break;case"L":t=["C"][P](Ht(e.x,e.y,t[1],t[2]));break;case"H":t=["C"][P](Ht(e.x,e.y,t[1],e.y));break;case"V":t=["C"][P](Ht(e.x,e.y,e.x,t[1]));break;case"Z":t=["C"][P](Ht(e.x,e.y,e.X,e.Y))}return t}),l=function(t,e){if(t[e].length>7){t[e].shift();for(var r=t[e];r.length;)u[e]="A",n&&(c[e]="A"),t.splice(e++,0,["C"][P](r.splice(0,6)));t.splice(e,1),g=W(i.length,n&&n.length||0)}},h=function(t,e,r,a,s){t&&e&&"M"==t[s][0]&&"M"!=e[s][0]&&(e.splice(s,0,["M",a.x,a.y]),r.bx=0,r.by=0,r.x=t[s][1],r.y=t[s][2],g=W(i.length,n&&n.length||0))},u=[],c=[],f="",p="",d=0,g=W(i.length,n&&n.length||0);dn){if(r&&!c.start){if(f=ke(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p),u+=["C"+f.start.x,f.start.y,f.m.x,f.m.y,f.x,f.y],a)return u;c.start=u,u=["M"+f.x,f.y+"C"+f.n.x,f.n.y,f.end.x,f.end.y,l[5],l[6]].join(),p+=h,s=+l[5],o=+l[6];continue}if(!t&&!r)return f=ke(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p),{x:f.x,y:f.y,alpha:f.alpha}}p+=h,s=+l[5],o=+l[6]}u+=l.shift()+l}return c.end=u,f=t?p:r?c:e.findDotsAtSegment(s,o,l[0],l[1],l[2],l[3],l[4],l[5],1),f.alpha&&(f={x:f.x,y:f.y,alpha:f.alpha}),f}},Ce=Be(1),Se=Be(),Ae=Be(0,1);e.getTotalLength=Ce,e.getPointAtLength=Se,e.getSubpath=function(t,e,r){if(this.getTotalLength(t)-r<1e-6)return Ae(t,e).end;var i=Ae(t,r,1);return e?Ae(i,e).end:i},ye.getTotalLength=function(){var t=this.getPath();if(t)return this.node.getTotalLength?this.node.getTotalLength():Ce(t)},ye.getPointAtLength=function(t){var e=this.getPath();if(e)return Se(e,t)},ye.getPath=function(){var t,r=e._getPath[this.type];if("text"!=this.type&&"set"!=this.type)return r&&(t=r(this)),t},ye.getSubpath=function(t,r){var i=this.getPath();if(i)return e.getSubpath(i,t,r)};var Te=e.easing_formulas={linear:function(t){return t},"<":function(t){return X(t,1.7)},">":function(t){return X(t,.48)},"<>":function(t){var e=.48-t/1.04,r=Y.sqrt(.1734+e*e),i=r-e,n=X(H(i),1/3)*(i<0?-1:1),a=-r-e,s=X(H(a),1/3)*(a<0?-1:1),o=n+s+.5;return 3*(1-o)*o*o+o*o*o},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){t-=1;var e=1.70158;return t*t*((e+1)*t+e)+1},elastic:function(t){return t==!!t?t:X(2,-10*t)*Y.sin((t-.075)*(2*U)/.3)+1},bounce:function(t){var e=7.5625,r=2.75,i;return t<1/r?i=e*t*t:t<2/r?(t-=1.5/r,i=e*t*t+.75):t<2.5/r?(t-=2.25/r,i=e*t*t+.9375):(t-=2.625/r,i=e*t*t+.984375),i}};Te.easeIn=Te["ease-in"]=Te["<"],Te.easeOut=Te["ease-out"]=Te[">"],Te.easeInOut=Te["ease-in-out"]=Te["<>"],Te["back-in"]=Te.backIn,Te["back-out"]=Te.backOut;var Ee=[],Me=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){setTimeout(t,16)},Ne=function(){for(var r=+new Date,i=0;i1&&!n.next){for(v in u)u[A](v)&&(g[v]=n.totalOrigin[v]);n.el.attr(g),b(n.anim,n.el,n.anim.percents[0],null,n.totalOrigin,n.repeat-1)}n.next&&!n.stop&&b(n.anim,n.el,n.next,null,n.totalOrigin,n.repeat)}}}Ee.length&&Me(Ne)},Le=function(t){return t>255?255:t<0?0:t};ye.animateWith=function(t,r,i,n,a,s){var o=this;if(o.removed)return s&&s.call(o),o;var l=i instanceof m?i:e.animation(i,n,a,s),h,u;b(l,o,l.percents[0],null,o.attr());for(var c=0,f=Ee.length;cl&&(l=u)}l+="%",!t[l].callback&&(t[l].callback=n)}return new m(t,r)},ye.animate=function(t,r,i,n){var a=this;if(a.removed)return n&&n.call(a),a;var s=t instanceof m?t:e.animation(t,r,i,n);return b(s,a,s.percents[0],null,a.attr()),a},ye.setTime=function(t,e){return t&&null!=e&&this.status(t,G(e,t.ms)/t.ms),this},ye.status=function(t,e){var r=[],i=0,n,a;if(null!=e)return b(t,this,-1,G(e,1)),this;for(n=Ee.length;i1)for(var i=0,n=r.length;i.5)-1;l(f-.5,2)+l(p-.5,2)>.25&&(p=a.sqrt(.25-l(f-.5,2))*n+.5)&&.5!=p&&(p=p.toFixed(5)-1e-5*n)}return c}),n=n.split(/\s*\-\s*/),"linear"==h){var b=n.shift();if(b=-i(b),isNaN(b))return null;var _=[0,0,a.cos(t.rad(b)),a.sin(t.rad(b))],w=1/(s(o(_[2]),o(_[3]))||1);_[2]*=w,_[3]*=w,_[2]<0&&(_[0]=-_[2],_[2]=0),_[3]<0&&(_[1]=-_[3],_[3]=0)}var k=t._parseDots(n);if(!k)return null;if(u=u.replace(/[\(\)\s,\xb0#]/g,"_"),e.gradient&&u!=e.gradient.id&&(g.defs.removeChild(e.gradient),delete e.gradient),!e.gradient){y=v(h+"Gradient",{id:u}),e.gradient=y,v(y,"radial"==h?{fx:f,fy:p}:{x1:_[0],y1:_[1],x2:_[2],y2:_[3],gradientTransform:e.matrix.invert()}),g.defs.appendChild(y);for(var B=0,C=k.length;B1?z.opacity/100:z.opacity});case"stroke":z=t.getRGB(g),l.setAttribute(d,z.hex),"stroke"==d&&z[e]("opacity")&&v(l,{"stroke-opacity":z.opacity>1?z.opacity/100:z.opacity}),"stroke"==d&&i._.arrows&&("startString"in i._.arrows&&_(i,i._.arrows.startString),"endString"in i._.arrows&&_(i,i._.arrows.endString,1));break;case"gradient":("circle"==i.type||"ellipse"==i.type||"r"!=r(g).charAt())&&x(i,g);break;case"opacity":u.gradient&&!u[e]("stroke-opacity")&&v(l,{"stroke-opacity":g>1?g/100:g});case"fill-opacity":if(u.gradient){P=t._g.doc.getElementById(l.getAttribute("fill").replace(/^url\(#|\)$/g,c)),P&&(F=P.getElementsByTagName("stop"),v(F[F.length-1],{"stop-opacity":g}));break}default:"font-size"==d&&(g=n(g,10)+"px");var R=d.replace(/(\-.)/g,function(t){return t.substring(1).toUpperCase()});l.style[R]=g,i._.dirty=1,l.setAttribute(d,g)}}S(i,a),l.style.visibility=f},C=1.2,S=function(i,a){if("text"==i.type&&(a[e]("text")||a[e]("font")||a[e]("font-size")||a[e]("x")||a[e]("y"))){var s=i.attrs,o=i.node,l=o.firstChild?n(t._g.doc.defaultView.getComputedStyle(o.firstChild,c).getPropertyValue("font-size"),10):10;if(a[e]("text")){for(s.text=a.text;o.firstChild;)o.removeChild(o.firstChild);for(var h=r(a.text).split("\n"),u=[],f,p=0,d=h.length;p"));var Z=X.getBoundingClientRect();m.W=f.w=(Z.right-Z.left)/U,m.H=f.h=(Z.bottom-Z.top)/U,m.X=f.x,m.Y=f.y+m.H/2,("x"in l||"y"in l)&&(m.path.v=t.format("m{0},{1}l{2},{1}",a(f.x*b),a(f.y*b),a(f.x*b)+1));for(var Q=["x","y","text","font","font-family","font-weight","font-style","font-size"],J=0,K=Q.length;J.25&&(r=n.sqrt(.25-l(e-.5,2))*(2*(r>.5)-1)+.5),f=e+p+r),d}),a=a.split(/\s*\-\s*/),"linear"==c){var g=a.shift();if(g=-i(g),isNaN(g))return null}var v=t._parseDots(a);if(!v)return null;if(e=e.shape||e.node,v.length){e.removeChild(s),s.on=!0,s.method="none",s.color=v[0].color,s.color2=v[v.length-1].color;for(var x=[],y=0,m=v.length;y')}}catch(r){N=function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},t._engine.initWin(t._g.win),t._engine.create=function(){var e=t._getContainer.apply(0,arguments),r=e.container,i=e.height,n,a=e.width,s=e.x,o=e.y;if(!r)throw new Error("VML container not found.");var l=new t._Paper,h=l.canvas=t._g.doc.createElement("div"),u=h.style;return s=s||0,o=o||0,a=a||512,i=i||342,l.width=a,l.height=i,a==+a&&(a+="px"),i==+i&&(i+="px"),l.coordsize=1e3*b+p+1e3*b,l.coordorigin="0 0",l.span=t._g.doc.createElement("span"),l.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",h.appendChild(l.span),u.cssText=t.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",a,i),1==r?(t._g.doc.body.appendChild(h),u.left=s+"px",u.top=o+"px",u.position="absolute"):r.firstChild?r.insertBefore(h,r.firstChild):r.appendChild(h),l.renderfix=function(){},l},t.prototype.clear=function(){t.eve("raphael.clear",this),this.canvas.innerHTML=d,this.span=t._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},t.prototype.remove=function(){t.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var e in this)this[e]="function"==typeof this[e]?t._removedFactory(e):null;return!0};var L=t.st;for(var z in M)M[e](z)&&!L[e](z)&&(L[z]=function(t){return function(){var e=arguments;return this.forEach(function(r){r[t].apply(r,e)})}}(z))}}.apply(e,i),!(void 0!==n&&(t.exports=n))}])}); \ No newline at end of file diff --git a/js/scripts.js b/js/scripts.js deleted file mode 100644 index 545dd8d0..00000000 --- a/js/scripts.js +++ /dev/null @@ -1,20 +0,0 @@ -jQuery( document ).ready( - function( $ ) { - function ab_flag_spam() { - var $$ = $( '#ab_flag_spam' ), - nextAll = $$.parent( 'li' ).nextAll( '.ab_flag_spam_child' ); - - nextAll.css( - 'display', - ( $$.is( ':checked' ) ? 'list-item' : 'none' ) - ); - } - - $( '#ab_flag_spam' ).on( - 'change', - ab_flag_spam - ); - - ab_flag_spam(); - } -); diff --git a/lib/Helpers/AssetsLoader.php b/lib/Helpers/AssetsLoader.php new file mode 100644 index 00000000..36d386aa --- /dev/null +++ b/lib/Helpers/AssetsLoader.php @@ -0,0 +1,91 @@ + [ + 'wp-i18n', + 'wp-element', + 'wp-blocks', + 'wp-components', + 'wp-editor', + 'wp-polyfill', + ], + 'version' => ANTISPAM_BEE_VERSION, + ]; + } + + // Register the bundled block JS file. + if ( file_exists( ANTISPAM_BEE_PATH . $backend_scripts_path ) ) { + wp_register_script( + 'antispam-bee-backend', + ANTISPAM_BEE_URL . $backend_scripts_path, + $backend_asset['dependencies'], + $backend_asset['version'], + true + ); + } + + // Register optional editor only styles. + if ( file_exists( ANTISPAM_BEE_PATH . $backend_style_path ) ) { + wp_register_style( + 'antispam-bee-backend', + ANTISPAM_BEE_URL . $backend_style_path, + [], + $backend_asset['version'] + ); + } + + wp_set_script_translations( 'antispam-bee-backend', 'antispam-bee', plugin_dir_path( ANTISPAM_BEE_FILE ) . 'languages' ); + } + + /** + * Enqueue the backend assets. + */ + public function admin_enqueue_scripts() { + wp_enqueue_script( 'antispam-bee-backend' ); + wp_enqueue_style( 'antispam-bee-backend' ); + } + + /** + * Add SVG definitions to footer. + */ + public function include_svg_icons() { + $svg_icons = ANTISPAM_BEE_PATH . 'build/images/icons/sprite.svg'; + + if ( file_exists( $svg_icons ) ) { + echo '
'; + require_once $svg_icons; + echo '
'; + } + } +} diff --git a/lib/load.php b/lib/load.php new file mode 100644 index 00000000..5ca5ffc6 --- /dev/null +++ b/lib/load.php @@ -0,0 +1,29 @@ + new AssetsLoader(), + ]; + + // Initialize all modules. + foreach ( $modules as $module ) { + if ( is_callable( [ $module, 'init' ] ) ) { + call_user_func( [ $module, 'init' ] ); + } + } +} + +add_action( 'plugins_loaded', 'AntispamBee\init' ); diff --git a/package.json b/package.json index 921cb480..afb14d77 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,33 @@ { - "private": true, - "devDependencies": { - "@wordpress/eslint-plugin": "^10.0.0", - "@wordpress/stylelint-config": "^20.0.0", - "eslint": "^8.4.1", - "prettier": "^2.3.0", - "stylelint": "^14.2.0" - } + "name": "@pluginkollektiv/antispam-bee", + "version": "3.0.0", + "description": "Antispam Bee blocks spam comments and trackbacks effectively and without captchas.", + "author": "pluginkollektiv", + "license": "GPL-2.0-or-later", + "main": "build/index.js", + "scripts": { + "build": "wp-scripts build", + "check-engines": "wp-scripts check-engines", + "check-licenses": "wp-scripts check-licenses", + "format:js": "wp-scripts format-js", + "format:js:src": "wp-scripts format-js ./src", + "lint:css": "wp-scripts lint-style", + "lint:css:src": "wp-scripts lint-style 'src/**/*.css'", + "lint:js": "wp-scripts lint-js", + "lint:js:src": "wp-scripts lint-js ./src", + "lint:md:docs": "wp-scripts lint-md-docs", + "lint:md:js": "wp-scripts lint-md-js", + "lint:pkg-json": "wp-scripts lint-pkg-json", + "packages-update": "wp-scripts packages-update", + "postpackages-update": "npm run build", + "start": "wp-scripts start", + "test:e2e": "wp-scripts test-e2e", + "test:unit": "wp-scripts test-unit-js" + }, + "devDependencies": { + "@wordpress/scripts": "^18.1.0", + "classnames": "^2.3.1", + "svg-spritemap-webpack-plugin": "^4.3.3", + "url-loader": "^4.1.1" + } } diff --git a/phpcs.xml b/phpcs.xml index e5554c64..ae31bec3 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,47 +1,93 @@ - - Coding standard for WordPress plugins + + Generally-applicable sniffs for WordPress plugins. + - - - - - - - - . - /node_modules/* - /tests/* - /vendor/* - *.css - *.js - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + . + + + + /build/ + /vendor/ + /node_modules/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend.js b/src/backend.js new file mode 100644 index 00000000..3b3d7cba --- /dev/null +++ b/src/backend.js @@ -0,0 +1 @@ +import './backend.scss'; diff --git a/src/backend.scss b/src/backend.scss new file mode 100644 index 00000000..5e898599 --- /dev/null +++ b/src/backend.scss @@ -0,0 +1 @@ +/** Backend styles */ diff --git a/src/images/icons/filter.svg b/src/images/icons/filter.svg new file mode 100644 index 00000000..fcf8b416 --- /dev/null +++ b/src/images/icons/filter.svg @@ -0,0 +1 @@ + diff --git a/src/images/icons/share-nodes.svg b/src/images/icons/share-nodes.svg new file mode 100644 index 00000000..c60fdabe --- /dev/null +++ b/src/images/icons/share-nodes.svg @@ -0,0 +1 @@ + diff --git a/src/images/icons/sliders.svg b/src/images/icons/sliders.svg new file mode 100644 index 00000000..8019b40b --- /dev/null +++ b/src/images/icons/sliders.svg @@ -0,0 +1 @@ + diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..27d3aad5 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +const path = require( 'path' ); +const defaultConfig = require( '@wordpress/scripts/config/webpack.config' ); +const SVGSpritemapPlugin = require( 'svg-spritemap-webpack-plugin' ); + +/** + * Webpack config (Development mode) + * + * @see https://developer.wordpress.org/block-editor/packages/packages-scripts/#provide-your-own-webpack-config + */ +module.exports = { + ...defaultConfig, + entry: { + backend: path.resolve( process.cwd(), 'src', 'backend.js' ), + }, + module: { + rules: [ + ...defaultConfig.module.rules, + { + test: /\.svg$/, + use: [ '@svgr/webpack', 'url-loader' ], + }, + ], + }, + plugins: [ + ...defaultConfig.plugins, + + /** + * Generate an SVG sprite. + * + * @see https://github.com/cascornelissen/svg-spritemap-webpack-plugin + */ + new SVGSpritemapPlugin( 'src/images/icons/**/*.svg', { + output: { + filename: 'images/icons/sprite.svg', + }, + sprite: { + prefix: 'antispam-bee-', + }, + } ), + ], +}; From 16a031f70d121ef341458346e86652eba807aee1 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Sun, 20 Mar 2022 09:56:55 +0100 Subject: [PATCH 002/184] wip 3.0: cloudfest hackathon --- inc/ApprovedEmail.php | 60 ++++++++++++ inc/BBCode.php | 45 +++++++++ inc/Controllable.php | 9 ++ inc/CountrySpam.php | 149 ++++++++++++++++++++++++++++ inc/DataHelper.php | 30 ++++++ inc/DbSpam.php | 82 ++++++++++++++++ inc/InitRule.php | 15 +++ inc/LangCodeHelper.php | 213 +++++++++++++++++++++++++++++++++++++++++ inc/LangSpam.php | 122 +++++++++++++++++++++++ inc/RegexpSpam.php | 28 ++++++ inc/ShortestTime.php | 52 ++++++++++ inc/ValidGravatar.php | 81 ++++++++++++++++ inc/Verifiable.php | 17 ++++ 13 files changed, 903 insertions(+) create mode 100644 inc/ApprovedEmail.php create mode 100644 inc/BBCode.php create mode 100644 inc/Controllable.php create mode 100644 inc/CountrySpam.php create mode 100644 inc/DataHelper.php create mode 100644 inc/DbSpam.php create mode 100644 inc/InitRule.php create mode 100644 inc/LangCodeHelper.php create mode 100644 inc/LangSpam.php create mode 100644 inc/RegexpSpam.php create mode 100644 inc/ShortestTime.php create mode 100644 inc/ValidGravatar.php create mode 100644 inc/Verifiable.php diff --git a/inc/ApprovedEmail.php b/inc/ApprovedEmail.php new file mode 100644 index 00000000..d8805c98 --- /dev/null +++ b/inc/ApprovedEmail.php @@ -0,0 +1,60 @@ +get_var( + $wpdb->prepare( + "SELECT `comment_ID` FROM `$wpdb->comments` WHERE `comment_approved` = '1' AND `comment_author_email` = %s LIMIT 1", + wp_unslash( $email ) + ) + ); + + if ( $result ) { + return 1; + } + + return - 1; + } + + public static function get_name() { + return __( 'Approved Email', 'antispam-bee' ); + } + + public static function get_label() { + return __( 'Trust approved commenters', 'antispam-bee' ); + } + + public static function get_description() { + return __( 'No review of already commented users', 'antispam-bee' ); + } + + public static function get_weight() { + return 1.0; + } + + public static function get_slug() { + return 'asb-approved-email'; + } + + public static function is_final() { + return false; + } + + public static function render() { + return ''; + } +} \ No newline at end of file diff --git a/inc/BBCode.php b/inc/BBCode.php new file mode 100644 index 00000000..21bbc69b --- /dev/null +++ b/inc/BBCode.php @@ -0,0 +1,45 @@ +', + esc_url( + __( 'https://antispambee.pluginkollektiv.org/documentation/#block-comments-from-specific-countries', + 'antispam-bee' ), + 'https' + ) + ); + return sprintf( + /* translators: 1: opening tag with link to documentation. 2: closing tag. */ + esc_html__( 'Filtering the requests depending on country. Please note the %1$sprivacy notice%2$s for this option.', + 'antispam-bee' ), + wp_kses_post( $link1 ), + '' + ); + } + + public static function get_weight() { + return 1; + } + + public static function get_slug() { + return 'asb-country-spam'; + } + + public static function is_final() { + return false; + } + + public static function render() { + return ''; + } +} \ No newline at end of file diff --git a/inc/DataHelper.php b/inc/DataHelper.php new file mode 100644 index 00000000..7813d9e0 --- /dev/null +++ b/inc/DataHelper.php @@ -0,0 +1,30 @@ + $value ) { + foreach ( $substrs as $substr ) { + if ( strpos( $key, $substr ) ) { + $results[ $key ] = $value; + } + } + } + + return $results; + } +} \ No newline at end of file diff --git a/inc/DbSpam.php b/inc/DbSpam.php new file mode 100644 index 00000000..fd4fa345 --- /dev/null +++ b/inc/DbSpam.php @@ -0,0 +1,82 @@ +get_var( + $wpdb->prepare( + sprintf( + "SELECT `comment_ID` FROM `$wpdb->comments` WHERE `comment_approved` = 'spam' AND (%s) LIMIT 1", + $filter_sql + ), + $params + ) + ); + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber + // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared + + return ! empty( $result ); + } + + public static function get_name() { + return __( 'Local DB Spam', 'antispam-bee' ); + } + + public static function get_label() { + return __( 'Look in the local spam database', 'antispam-bee' ); + } + + public static function get_description() { + return __( 'Check for spam data on your own blog', 'antispam-bee' ); + } + + public static function get_weight() { + return 1; + } + + public static function get_slug() { + return 'asb-db-spam'; + } + + public static function is_final() { + return false; + } + + public static function render() { + return ''; + } +} \ No newline at end of file diff --git a/inc/InitRule.php b/inc/InitRule.php new file mode 100644 index 00000000..17a05648 --- /dev/null +++ b/inc/InitRule.php @@ -0,0 +1,15 @@ + self::get_weight(), + 'name' => self::get_name(), + 'callable' => array( self::class, 'verify' ), + ]; + } ); + } +} \ No newline at end of file diff --git a/inc/LangCodeHelper.php b/inc/LangCodeHelper.php new file mode 100644 index 00000000..36378a76 --- /dev/null +++ b/inc/LangCodeHelper.php @@ -0,0 +1,213 @@ + 'za', + 'zho' => 'zh', + 'zul' => 'zu', + 'yid' => 'yi', + 'yor' => 'yo', + 'xho' => 'xh', + 'wln' => 'wa', + 'wol' => 'wo', + 'ven' => 've', + 'vie' => 'vi', + 'vol' => 'vo', + 'uig' => 'ug', + 'ukr' => 'uk', + 'urd' => 'ur', + 'uzb' => 'uz', + 'tah' => 'ty', + 'tam' => 'ta', + 'tat' => 'tt', + 'tel' => 'te', + 'tgk' => 'tg', + 'tgl' => 'tl', + 'tha' => 'th', + 'tir' => 'ti', + 'ton' => 'to', + 'tsn' => 'tn', + 'tso' => 'ts', + 'tuk' => 'tk', + 'tur' => 'tr', + 'twi' => 'tw', + 'sag' => 'sg', + 'san' => 'sa', + 'sin' => 'si', + 'slk' => 'sk', + 'slv' => 'sl', + 'sme' => 'se', + 'smo' => 'sm', + 'sna' => 'sn', + 'snd' => 'sd', + 'som' => 'so', + 'sot' => 'st', + 'spa' => 'es', + 'sqi' => 'sq', + 'srd' => 'sc', + 'srp' => 'sr', + 'ssw' => 'ss', + 'sun' => 'su', + 'swa' => 'sw', + 'swe' => 'sv', + 'roh' => 'rm', + 'ron' => 'ro', + 'run' => 'rn', + 'rus' => 'ru', + 'que' => 'qu', + 'pan' => 'pa', + 'pli' => 'pi', + 'pol' => 'pl', + 'por' => 'pt', + 'pus' => 'ps', + 'oci' => 'oc', + 'oji' => 'oj', + 'ori' => 'or', + 'orm' => 'om', + 'oss' => 'os', + 'nau' => 'na', + 'nav' => 'nv', + 'nbl' => 'nr', + 'nde' => 'nd', + 'ndo' => 'ng', + 'nep' => 'ne', + 'nld' => 'nl', + 'nno' => 'nn', + 'nob' => 'nb', + 'nor' => 'no', + 'nya' => 'ny', + 'mah' => 'mh', + 'mal' => 'ml', + 'mar' => 'mr', + 'mkd' => 'mk', + 'mlg' => 'mg', + 'mlt' => 'mt', + 'mon' => 'mn', + 'mri' => 'mi', + 'msa' => 'ms', + 'mya' => 'my', + 'lao' => 'lo', + 'lat' => 'la', + 'lav' => 'lv', + 'lim' => 'li', + 'lin' => 'ln', + 'lit' => 'lt', + 'ltz' => 'lb', + 'lub' => 'lu', + 'lug' => 'lg', + 'kal' => 'kl', + 'kan' => 'kn', + 'kas' => 'ks', + 'kat' => 'ka', + 'kau' => 'kr', + 'kaz' => 'kk', + 'khm' => 'km', + 'kik' => 'ki', + 'kin' => 'rw', + 'kir' => 'ky', + 'kom' => 'kv', + 'kon' => 'kg', + 'kor' => 'ko', + 'kua' => 'kj', + 'kur' => 'ku', + 'jav' => 'jv', + 'jpn' => 'ja', + 'ibo' => 'ig', + 'ido' => 'io', + 'iii' => 'ii', + 'iku' => 'iu', + 'ile' => 'ie', + 'ina' => 'ia', + 'ind' => 'id', + 'ipk' => 'ik', + 'isl' => 'is', + 'ita' => 'it', + 'hat' => 'ht', + 'hau' => 'ha', + 'hbs' => 'sh', + 'heb' => 'he', + 'her' => 'hz', + 'hin' => 'hi', + 'hmo' => 'ho', + 'hrv' => 'hr', + 'hun' => 'hu', + 'hye' => 'hy', + 'gla' => 'gd', + 'gle' => 'ga', + 'glg' => 'gl', + 'glv' => 'gv', + 'grn' => 'gn', + 'guj' => 'gu', + 'fao' => 'fo', + 'fas' => 'fa', + 'fij' => 'fj', + 'fin' => 'fi', + 'fra' => 'fr', + 'fry' => 'fy', + 'ful' => 'ff', + 'ell' => 'el', + 'eng' => 'en', + 'epo' => 'eo', + 'est' => 'et', + 'eus' => 'eu', + 'ewe' => 'ee', + 'dan' => 'da', + 'deu' => 'de', + 'div' => 'dv', + 'dzo' => 'dz', + 'cat' => 'ca', + 'ces' => 'cs', + 'cha' => 'ch', + 'che' => 'ce', + 'chu' => 'cu', + 'chv' => 'cv', + 'cor' => 'kw', + 'cos' => 'co', + 'cre' => 'cr', + 'cym' => 'cy', + 'bak' => 'ba', + 'bam' => 'bm', + 'bel' => 'be', + 'ben' => 'bn', + 'bis' => 'bi', + 'bod' => 'bo', + 'bos' => 'bs', + 'bre' => 'br', + 'bul' => 'bg', + 'aar' => 'aa', + 'abk' => 'ab', + 'afr' => 'af', + 'aka' => 'ak', + 'amh' => 'am', + 'ara' => 'ar', + 'arg' => 'an', + 'asm' => 'as', + 'ava' => 'av', + 'ave' => 'ae', + 'aym' => 'ay', + 'aze' => 'az', + 'nds' => 'de', + ); + + if ( array_key_exists( $franc_code, $codes ) ) { + return $codes[ $franc_code ]; + } + + return $franc_code; + } + + +} \ No newline at end of file diff --git a/inc/LangSpam.php b/inc/LangSpam.php new file mode 100644 index 00000000..f2198f30 --- /dev/null +++ b/inc/LangSpam.php @@ -0,0 +1,122 @@ + wp_json_encode( array( 'body' => $comment_text ) ) ) + ); + + if ( is_wp_error( $response ) + || wp_remote_retrieve_response_code( $response ) !== 200 ) { + return false; + } + + $detected_lang = wp_remote_retrieve_body( $response ); + if ( ! $detected_lang ) { + return false; + } + + $detected_lang = json_decode( $detected_lang ); + if ( ! $detected_lang || ! isset( $detected_lang->code ) ) { + return false; + } + + return ! in_array( Lang_Code_Helper::map ( $detected_lang->code ), $allowed_lang, true ); + } + + public static function get_name() { + return __( 'Comment Language', 'antispam-bee' ); + } + + public static function get_weight() { + return 1; + } + + public static function get_slug() { + return 'asb-lang-spam'; + } + + public static function is_final() { + return false; + } + + public static function get_label() { + __( 'Allow comments only in certain language', 'antispam-bee' ); + } + + public static function get_description() { + $link1 = sprintf( + '', + esc_url( + __( 'https://antispambee.pluginkollektiv.org/documentation/#allow-comments-only-in-certain-language', 'antispam-bee' ), + 'https' + ) + ); + + printf( + /* translators: 1: opening tag with link to documentation. 2: closing tag. */ + esc_html__( 'Detect and approve only the specified language. Please note the %1$sprivacy notice%2$s for this option.', 'antispam-bee' ), + wp_kses_post( $link1 ), + '' + ); + } + + public static function render() { + // TODO: Implement render() method. + } +} \ No newline at end of file diff --git a/inc/RegexpSpam.php b/inc/RegexpSpam.php new file mode 100644 index 00000000..9dffe85b --- /dev/null +++ b/inc/RegexpSpam.php @@ -0,0 +1,28 @@ + self::get_weight(), + 'name' => self::get_name(), + 'callable' => array( self::class, 'verify' ), + ]; + } ); + } + + public static function verify( $data ) { + if ( ! isset( $data['email'] ) ) { + return; + } + + $response = wp_safe_remote_get( + sprintf( + 'https://www.gravatar.com/avatar/%s?d=404', + md5( strtolower( trim( $data['email'] ) ) ) + ) + ); + + if ( is_wp_error( $response ) ) { + return null; + } + + if ( wp_remote_retrieve_response_code( $response ) === 200 ) { + return true; + } + + return false; + } + + public static function get_name() { + return ''; + } + + public static function get_weight() { + return 1; + } + + public static function get_slug() { + return 'asb-valid-gravatar'; + } + + public static function is_final() { + return false; + } + + public static function get_label() { + __( 'Trust commenters with a Gravatar', 'antispam-bee' ); + } + + public static function get_description() { + $link1 = sprintf( + '', + esc_url( + __( 'https://antispambee.pluginkollektiv.org/documentation/#trust-commenters-with-a-gravatar', 'antispam-bee' ), + 'https' + ) + ); + printf( + /* translators: 1: opening tag with link to documentation. 2: closing tag */ + esc_html__( 'Check if commenter has a Gravatar image. Please note the %1$sprivacy notice%2$s for this option.', 'antispam-bee' ), + wp_kses_post( $link1 ), + '' + ); + } + + public static function render() { + return ''; + } +} \ No newline at end of file diff --git a/inc/Verifiable.php b/inc/Verifiable.php new file mode 100644 index 00000000..61c0b9c9 --- /dev/null +++ b/inc/Verifiable.php @@ -0,0 +1,17 @@ + Date: Sat, 19 Mar 2022 19:44:51 +0100 Subject: [PATCH 003/184] ignore the tests folder --- phpcs.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml b/phpcs.xml index ae31bec3..5f7ad6fd 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -38,6 +38,7 @@ /build/ /vendor/ /node_modules/ + /tests/ - + From 5e9b463a4eaf8f88f4c7ba6dc79b14ce9ca8f951 Mon Sep 17 00:00:00 2001 From: Sven Wagener Date: Sun, 20 Mar 2022 18:03:22 +0100 Subject: [PATCH 011/184] Start of new admin pages --- inc/Admin/Fields/Checkbox.php | 18 ++++++ inc/Admin/Fields/Field.php | 87 +++++++++++++++++++++++++++ inc/Admin/Fields/Text.php | 20 +++++++ inc/Admin/RenderElement.php | 15 +++++ inc/Admin/Section.php | 91 ++++++++++++++++++++++++++++ inc/Admin/SettingsPage.php | 109 ++++++++++++++++++++++++++++++++++ inc/Admin/Tab.php | 68 +++++++++++++++++++++ inc/Fields/Checkbox.php | 7 --- inc/Fields/Renderable.php | 7 --- inc/Fields/Select.php | 7 --- lib/load.php | 2 + 11 files changed, 410 insertions(+), 21 deletions(-) create mode 100644 inc/Admin/Fields/Checkbox.php create mode 100644 inc/Admin/Fields/Field.php create mode 100644 inc/Admin/Fields/Text.php create mode 100644 inc/Admin/RenderElement.php create mode 100644 inc/Admin/Section.php create mode 100644 inc/Admin/SettingsPage.php create mode 100644 inc/Admin/Tab.php delete mode 100644 inc/Fields/Checkbox.php delete mode 100644 inc/Fields/Renderable.php delete mode 100644 inc/Fields/Select.php diff --git a/inc/Admin/Fields/Checkbox.php b/inc/Admin/Fields/Checkbox.php new file mode 100644 index 00000000..1566910a --- /dev/null +++ b/inc/Admin/Fields/Checkbox.php @@ -0,0 +1,18 @@ +get_name() . '" value="1" ' . checked( 1, $this->get_value(), true ) . ' />'; + $this->maybe_show_description(); + } +} diff --git a/inc/Admin/Fields/Field.php b/inc/Admin/Fields/Field.php new file mode 100644 index 00000000..7924b6c6 --- /dev/null +++ b/inc/Admin/Fields/Field.php @@ -0,0 +1,87 @@ +name = $name; + $this->label = $label; + $this->description = $description; + } + + /** + * Get Name. + * + * @return string Name of the field. + */ + public function get_name() { + return $this->name; + } + + /** + * Get label. + * + * @return string Label of the field. + */ + public function get_label() { + return $this->label; + } + + /** + * Get Description. + * + * @return string Description of the field. + */ + public function get_description() { + return $this->description; + } + + /** + * Get Value. + * + * @return mixed Value stored in database. + */ + protected function get_value() { + return get_option( $this->name ); + } + + /** + * Show description if not empty. + */ + protected function maybe_show_description() { + if ( ! empty( $this->get_description() ) ) { + echo '' . $this->get_description() . ''; + } + } + + /** + * Get HTML for field. + * + * @return string Elment HTML. + */ + abstract public function render(); +} \ No newline at end of file diff --git a/inc/Admin/Fields/Text.php b/inc/Admin/Fields/Text.php new file mode 100644 index 00000000..a6f30ac3 --- /dev/null +++ b/inc/Admin/Fields/Text.php @@ -0,0 +1,20 @@ +get_name() . '" value="' . $this->get_value() . '" />'; + $this->maybe_show_description(); + } +} diff --git a/inc/Admin/RenderElement.php b/inc/Admin/RenderElement.php new file mode 100644 index 00000000..ff20c3fb --- /dev/null +++ b/inc/Admin/RenderElement.php @@ -0,0 +1,15 @@ +name = $name; + $this->title = $title; + $this->fields = $fields; + $this->description = $description; + } + + /** + * Get Name. + * + * @return string Name of the field. + */ + public function get_name() { + return $this->name; + } + + /** + * Get title. + * + * @return string Title of the field. + */ + public function get_title() { + return $this->title; + } + + /** + * Get description. + * + * @return string Title of the field. + */ + public function get_description() { + return $this->description; + } + + /** + * Get fields. + * + * @return Field[] + */ + public function get_fields() { + return $this->fields; + } + + public function get_callback() { + if ( ! empty( $this->description ) ) { + echo '

' . $this->get_description() . '

'; + } + } +} \ No newline at end of file diff --git a/inc/Admin/SettingsPage.php b/inc/Admin/SettingsPage.php new file mode 100644 index 00000000..8592f459 --- /dev/null +++ b/inc/Admin/SettingsPage.php @@ -0,0 +1,109 @@ + +
+

+ + + +
+ + + + + +
+
+ tabs[] = new Tab( + 'general', __( 'General', 'antispam-bee' ), + [ + new Section( + 'global_settings', + __('Global Settings', 'antispam-bee' ), + __('Setup global plugin spam settings.', 'antispam-bee' ),// @todo Description? + [ + new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), + new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), + new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), + new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ) + ] + ) + ] + ); + + $this->tabs = apply_filters( 'antispam_bee_tabs', $this->tabs ); + + // Register option setting + foreach( $this->tabs as $tab ) { + foreach ( $tab->get_sections() as $section ) { + add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); + + foreach( $section->get_fields() as $field ) { + add_settings_field( + $field->get_name(), + $field->get_label(), + [ $field, 'render' ], + 'antispam_bee', + $section->get_name() + ); + + register_setting( 'antispam_bee', $field->get_name() ); + } + } + } + } +} \ No newline at end of file diff --git a/inc/Admin/Tab.php b/inc/Admin/Tab.php new file mode 100644 index 00000000..b4ce36cc --- /dev/null +++ b/inc/Admin/Tab.php @@ -0,0 +1,68 @@ +name = $name; + $this->title = $title; + $this->sections = $sections; + } + + /** + * Get Name. + * + * @return string Name of the field. + */ + public function get_name() { + return $this->name; + } + + /** + * Get title. + * + * @return string Title of the field. + */ + public function get_title() { + return $this->title; + } + + /** + * Get sections. + * + * @return Section[] + */ + public function get_sections() { + return $this->sections; + } +} \ No newline at end of file diff --git a/inc/Fields/Checkbox.php b/inc/Fields/Checkbox.php deleted file mode 100644 index 0188c44c..00000000 --- a/inc/Fields/Checkbox.php +++ /dev/null @@ -1,7 +0,0 @@ - new AssetsLoader(), + 'settings_page' => new SettingsPage(), ]; // Initialize all modules. From 8e2243eeb95ac4f65038667b6cd3679aa482eb6b Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sun, 20 Mar 2022 18:49:42 +0100 Subject: [PATCH 012/184] implement the helper to activate, deactivate and uninstall the plugin --- antispam_bee.php | 5 +- lib/Helpers/Installer.php | 97 +++++++++++++++++++++++++++++++++++++++ lib/load.php | 6 +++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 lib/Helpers/Installer.php diff --git a/antispam_bee.php b/antispam_bee.php index 6af04132..b3de266d 100644 --- a/antispam_bee.php +++ b/antispam_bee.php @@ -19,7 +19,8 @@ * License URI: http://www.gnu.org/licenses/gpl-2.0.html */ -define( 'ANTISPAM_BEE_VERSION', '1.0.0' ); +define( 'ANTISPAM_BEE_VERSION', '3.0.0' ); +define( 'ANTISPAM_BEE_DB_VERSION', '1.02' ); define( 'ANTISPAM_BEE_FILE', __FILE__ ); define( 'ANTISPAM_BEE_PATH', plugin_dir_path( ANTISPAM_BEE_FILE ) ); define( 'ANTISPAM_BEE_URL', plugin_dir_url( ANTISPAM_BEE_FILE ) ); @@ -65,7 +66,7 @@ function antispam_bee_pre_init() { * @since 1.0.0 */ function antispam_bee_load_textdomain() { - load_plugin_textdomain( 'antispam-bee', false, basename( dirname( __FILE__ ) ) . '/languages' ); + load_plugin_textdomain( 'antispam-bee' ); } /** diff --git a/lib/Helpers/Installer.php b/lib/Helpers/Installer.php new file mode 100644 index 00000000..77d97d88 --- /dev/null +++ b/lib/Helpers/Installer.php @@ -0,0 +1,97 @@ +query( 'OPTIMIZE TABLE `' . $wpdb->options . '`' ); + + //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $sql = 'DELETE FROM `' . $wpdb->commentmeta . '`WHERE `meta_key` IN ("antispam_bee_iphash", "antispam_bee_reason")'; + $wpdb->query( $sql ); + } + + /** + * Set some default antispam-bee options for new installs. + * + * @since 2.10.0 Set `use_output_buffer` option to `0` + */ + public static function set_default_options() { + add_option( 'antispam_bee', [ 'use_output_buffer' => 0 ], '', 'no' ); + } + + /** + * Initialization of the cronjobs. + */ + public static function init_scheduled_hook() { + if ( ! self::get_option( 'cronjob_enable' ) ) { + return; + } + + if ( ! wp_next_scheduled( 'antispam_bee_daily_cronjob' ) ) { + wp_schedule_event( + time(), + 'daily', + 'antispam_bee_daily_cronjob' + ); + } + } + + /** + * Deletion of the cronjobs + * + * @since 0.1 + * @since 2.4 + */ + public static function clear_scheduled_hook() { + if ( wp_next_scheduled( 'antispam_bee_daily_cronjob' ) ) { + wp_clear_scheduled_hook( 'antispam_bee_daily_cronjob' ); + } + } +} diff --git a/lib/load.php b/lib/load.php index 88344f95..15770d5b 100644 --- a/lib/load.php +++ b/lib/load.php @@ -9,6 +9,7 @@ use AntispamBee\Helpers\AssetsLoader; use AntispamBee\Helpers\CommentsColumns; +use AntispamBee\Helpers\Installer; /** * Init function of the plugin @@ -29,3 +30,8 @@ function init() { } add_action( 'plugins_loaded', 'AntispamBee\init' ); + +// Register the activation, deactivation and uninstall hooks. +register_activation_hook( ANTISPAM_BEE_FILE, [ Installer::class, 'activate' ] ); +register_deactivation_hook( ANTISPAM_BEE_FILE, [ Installer::class, 'deactivate' ] ); +register_uninstall_hook( ANTISPAM_BEE_FILE, [ Installer::class, 'uninstall' ] ); From faf12e6c781cc0cb4fc997c1b90f29dc9197e159 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Sun, 20 Mar 2022 18:54:33 +0100 Subject: [PATCH 013/184] add post processors, rules, helpers --- inc/Handlers/Comment.php | 47 +++++ inc/Handlers/PostProcessors.php | 88 +++++++++ inc/Handlers/Rules.php | 118 ++++++++++++ inc/Handlers/Trackback.php | 7 + inc/{Rules => Interfaces}/Controllable.php | 2 +- inc/Interfaces/PostProcessor.php | 15 ++ inc/{Rules => Interfaces}/Verifiable.php | 4 +- inc/PostProcessors/Delete.php | 49 +++++ inc/PostProcessors/DeleteForReasons.php | 50 +++++ inc/PostProcessors/InitPostProcessor.php | 13 ++ inc/PostProcessors/IsActive.php | 11 ++ inc/PostProcessors/SaveReason.php | 58 ++++++ inc/PostProcessors/SendEmail.php | 171 ++++++++++++++++++ inc/PostProcessors/UpdateDailyStats.php | 53 ++++++ inc/PostProcessors/UpdateSpamCount.php | 42 +++++ inc/PostProcessors/UpdateSpamLog.php | 54 ++++++ inc/Rules/ApprovedEmail.php | 11 +- inc/Rules/BBCode.php | 12 +- inc/Rules/CountrySpam.php | 12 +- inc/Rules/DbSpam.php | 19 +- inc/Rules/InitRule.php | 2 - inc/Rules/IsActive.php | 11 ++ inc/Rules/LangSpam.php | 13 +- inc/Rules/RegexpSpam.php | 137 +++++++++++++- inc/Rules/ShortestTime.php | 8 + inc/Rules/TrackbackFromMyself.php | 67 +++++++ inc/Rules/TrackbackPostTitleIsBlogName.php | 41 +++++ inc/Rules/ValidGravatar.php | 18 +- inc/Settings.php | 151 +++++++++++++++- lib/Helpers/DataHelper.php | 9 +- lib/Helpers/IpHelper.php | 68 +++++++ lib/Helpers/ItemTypeHelper.php | 21 +++ .../{LangCodeHelper.php => LangHelper.php} | 11 +- lib/load.php | 34 ++++ 34 files changed, 1379 insertions(+), 48 deletions(-) create mode 100644 inc/Handlers/Comment.php create mode 100644 inc/Handlers/PostProcessors.php create mode 100644 inc/Handlers/Rules.php create mode 100644 inc/Handlers/Trackback.php rename inc/{Rules => Interfaces}/Controllable.php (96%) create mode 100644 inc/Interfaces/PostProcessor.php rename inc/{Rules => Interfaces}/Verifiable.php (73%) create mode 100644 inc/PostProcessors/Delete.php create mode 100644 inc/PostProcessors/DeleteForReasons.php create mode 100644 inc/PostProcessors/InitPostProcessor.php create mode 100644 inc/PostProcessors/IsActive.php create mode 100644 inc/PostProcessors/SaveReason.php create mode 100644 inc/PostProcessors/SendEmail.php create mode 100644 inc/PostProcessors/UpdateDailyStats.php create mode 100644 inc/PostProcessors/UpdateSpamCount.php create mode 100644 inc/PostProcessors/UpdateSpamLog.php create mode 100644 inc/Rules/IsActive.php create mode 100644 inc/Rules/TrackbackFromMyself.php create mode 100644 inc/Rules/TrackbackPostTitleIsBlogName.php create mode 100644 lib/Helpers/IpHelper.php create mode 100644 lib/Helpers/ItemTypeHelper.php rename lib/Helpers/{LangCodeHelper.php => LangHelper.php} (97%) diff --git a/inc/Handlers/Comment.php b/inc/Handlers/Comment.php new file mode 100644 index 00000000..0a3c4c49 --- /dev/null +++ b/inc/Handlers/Comment.php @@ -0,0 +1,47 @@ +apply( $comment ); + + if ( $is_spam ) { + PostProcessors::apply( 'comment', $comment, $rules->get_spam_reasons() ); + } + + // todo: Maybe store no-spam-reasons + } +} diff --git a/inc/Handlers/PostProcessors.php b/inc/Handlers/PostProcessors.php new file mode 100644 index 00000000..a22a15b8 --- /dev/null +++ b/inc/Handlers/PostProcessors.php @@ -0,0 +1,88 @@ + $post_processor ) { + if ( ! self::is_valid_post_processor( $post_processor ) ) { + continue; + } + + $supported_types_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'get_supported_types' ] : $post_processor['get_supported_types']; + $supported_types = (array) call_user_func( $supported_types_function, $type ); + if ( ! in_array( $type, $supported_types ) ) { + continue; + } + + if ( ! $only_active ) { + $post_processors[] = $post_processor; + continue; + } + + $is_active_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'is_active' ] : $post_processor['is_active']; + $is_active = call_user_func( $is_active_function, $type ); + + if ( ! $is_active ) { + continue; + } + + $post_processors[] = $post_processor; + } + + return $post_processors; + } + + private static function is_valid_post_processor( $post_processor ) { + if ( isset( $post_processor['post_processor'] ) ) { + $interfaces = class_implements( $post_processor['post_processor'] ); + if ( false === $interfaces || empty( $interfaces ) ) { + return false; + } + + if ( ! in_array( PostProcessor::class, $interfaces, true ) ) { + return false; + } + + return true; + } + + $post_processor_callables = [ + 'is_active', + 'process', + 'get_slug', + 'get_supported_types', + ]; + + foreach ( $post_processor_callables as $key ) { + if ( ! isset( $post_processor[ $key ] ) || ! is_callable( $post_processor[ $key ] ) ) { + return false; + } + } + + return true; + } +} diff --git a/inc/Handlers/Rules.php b/inc/Handlers/Rules.php new file mode 100644 index 00000000..5df8bc30 --- /dev/null +++ b/inc/Handlers/Rules.php @@ -0,0 +1,118 @@ +type = $type; + } + + public function apply( $item ) { + $rules = self::get( $this->type, true ); + + $score = 0.0; + foreach ( $rules as $rule ) { + $verify_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'verify' ] : $rule['verify']; + $get_weight_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_weight' ] : $rule['get_weight']; + $get_slug_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_slug' ] : $rule['get_slug']; + + $rule_score = call_user_func( $verify_function, $item ) * call_user_func( $get_weight_function ); + if ( $rule_score > 0.0 ) { + $this->spam_reasons[] = call_user_func( $get_slug_function ); + } else { + $this->no_spam_reasons[] = call_user_func( $get_slug_function ); + } + + $score += $rule_score; + + $no_spam_threshold = (float) apply_filters( 'asb_no_spam_threshold', 0.0 ); + $spam_threshold = (float) apply_filters( 'asb_spam_threshold', 0.0 ); + if ( $no_spam_threshold <= 0.0 && $score <= $no_spam_threshold ) { + return false; + } + + if ( $spam_threshold >= 0.0 && $score >= $spam_threshold ) { + return true; + } + } + + return $score > 0.0; + } + + public static function get( $type = null, $only_active = false ) { + $all_rules = apply_filters( 'asb_rules', [] ); + + $rules = []; + foreach ( $all_rules as $rule ) { + if ( self::is_valid_rule( $rule ) ) { + + $get_supported_types_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_supported_types' ] : $rule['get_supported_types']; + $supported_types = call_user_func( $get_supported_types_function ); + + if ( ! in_array( $type, $supported_types ) ) { + continue; + } + + if ( ! $only_active ) { + $rules[] = $rule; + continue; + } + + $is_active_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'is_active' ] : $rule['is_active']; + $is_active = call_user_func( $is_active_function, $type ); + + if ( ! $is_active ) { + continue; + } + + $rules[] = $rule; + } + } + + return $rules; + } + + private static function is_valid_rule( $rule ) { + if ( isset( $rule['verifiable'] ) ) { + $interfaces = class_implements( $rule['verifiable'] ); + if ( false === $interfaces || empty( $interfaces ) ) { + return false; + } + + if ( ! in_array( Verifiable::class, $interfaces, true ) ) { + return false; + } + + return true; + } + + $rule_callables = [ + 'is_active', + 'verify', + 'get_slug', + 'get_supported_types', + ]; + + foreach ( $rule_callables as $key ) { + if ( ! isset( $rule[ $key ] ) || ! is_callable( $rule[ $key ] ) ) { + return false; + } + } + + return true; + } + + public function get_spam_reasons() { + return $this->spam_reasons; + } + + public function get_no_spam_reasons() { + return $this->no_spam_reasons; + } +} diff --git a/inc/Handlers/Trackback.php b/inc/Handlers/Trackback.php new file mode 100644 index 00000000..23eb3de9 --- /dev/null +++ b/inc/Handlers/Trackback.php @@ -0,0 +1,7 @@ + self::class + ]; + } ); + } +} diff --git a/inc/PostProcessors/IsActive.php b/inc/PostProcessors/IsActive.php new file mode 100644 index 00000000..40a61f7f --- /dev/null +++ b/inc/PostProcessors/IsActive.php @@ -0,0 +1,11 @@ +post_title ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Author', 'antispam-bee' ), + ( empty( $comment['comment_author'] ) ? '' : strip_tags( $comment['comment_author'] ) ) + ) . sprintf( + "URL: %s\r\n", + // empty check exists. + esc_url( $comment['comment_author_url'] ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Type', 'antispam-bee' ), + esc_html( $comment_name ) + ) . sprintf( + "Whois: http://whois.arin.net/rest/ip/%s\r\n", + $comment['comment_author_IP'] + ) . sprintf( + "%s: %s\r\n\r\n", + esc_html__( 'Spam Reason', 'antispam-bee' ), + esc_html( self::$defaults['reasons'][ self::$_reason ] ) + ) . sprintf( + "%s\r\n\r\n\r\n", + $content + ) . ( + EMPTY_TRASH_DAYS ? ( + sprintf( + "%s: %s\r\n", + esc_html__( 'Trash it', 'antispam-bee' ), + admin_url( 'comment.php?action=trash&c=' . $id ) + ) + ) : ( + sprintf( + "%s: %s\r\n", + esc_html__( 'Delete it', 'antispam-bee' ), + admin_url( 'comment.php?action=delete&c=' . $id ) + ) + ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Approve it', 'antispam-bee' ), + admin_url( 'comment.php?action=approve&c=' . $id ) + ) . sprintf( + "%s: %s\r\n\r\n", + esc_html__( 'Spam list', 'antispam-bee' ), + admin_url( 'edit-comments.php?comment_status=spam' ) + ) . sprintf( + "%s\r\n%s\r\n", + esc_html__( 'Notify message by Antispam Bee', 'antispam-bee' ), + esc_html__( 'https://antispambee.pluginkollektiv.org/', 'antispam-bee' ) + ); + + wp_mail( + /** + * Filters the recipients of the spam notification. + * + * @param array The recipients array. + */ + apply_filters( + 'antispam_bee_notification_recipients', + [ get_bloginfo( 'admin_email' ) ] + ), + /** + * Filters the subject of the spam notification. + * + * @param string $subject subject line. + */ + apply_filters( + 'antispam_bee_notification_subject', + $subject + ), + $body + ); + } + ] + ); + + return $item; + } + + public static function is_active( $type ) { + } + + public static function get_slug() { + return 'asb-send-email'; + } + + public static function get_supported_types() { + return [ 'comment', 'trackback' ]; + } + + public static function get_label() { + return __( 'Spam-Notification by email', 'antispam-bee' ); + } + + public static function get_description() { + return __( 'Notify admins by e-mail about incoming spam', 'antispam-bee' ); + } + + public static function get_options() { + return null; + } + + public static function marks_as_delete() { + return false; + } +} + diff --git a/inc/PostProcessors/UpdateDailyStats.php b/inc/PostProcessors/UpdateDailyStats.php new file mode 100644 index 00000000..a984a6fd --- /dev/null +++ b/inc/PostProcessors/UpdateDailyStats.php @@ -0,0 +1,53 @@ + self::get_weight(), - 'name' => self::get_name(), 'verifiable' => self::class, ]; } ); diff --git a/inc/Rules/IsActive.php b/inc/Rules/IsActive.php new file mode 100644 index 00000000..db7c0462 --- /dev/null +++ b/inc/Rules/IsActive.php @@ -0,0 +1,11 @@ + wp_json_encode( array( 'body' => $comment_text ) ) ) + array( 'body' => wp_json_encode( [ 'body' => $comment_text ] ) ) ); if ( is_wp_error( $response ) @@ -76,7 +81,7 @@ public static function verify( $data ) { return false; } - return ! in_array( Lang_Code_Helper::map ( $detected_lang->code ), $allowed_lang, true ); + return ! in_array( LangHelper::map ( $detected_lang->code ), $allowed_lang, true ); } public static function get_name() { @@ -119,4 +124,8 @@ public static function get_description() { public static function get_options() { null; } + + public static function get_supported_types() { + return [ 'comment', 'trackback' ]; + } } diff --git a/inc/Rules/RegexpSpam.php b/inc/Rules/RegexpSpam.php index 9dffe85b..31352500 100644 --- a/inc/Rules/RegexpSpam.php +++ b/inc/Rules/RegexpSpam.php @@ -2,27 +2,150 @@ namespace AntispamBee\Rules; -class RegexpSpam implements Verifiable { +use AntispamBee\Interfaces\Controllable; +use AntispamBee\Interfaces\Verifiable; + +class RegexpSpam implements Verifiable, Controllable { use InitRule; + use IsActive; + /** + * Usage of regexp, also custom + */ public static function verify( $data ) { - // TODO: Implement verify() method. + $fields = [ + 'ip', + 'host', + 'body', + 'email', + 'author', + 'useragent', + ]; + + $comment = $data; + + $patterns = [ + [ + 'host' => '^(www\.)?\d+\w+\.com$', + 'body' => '^\w+\s\d+$', + 'email' => '@gmail.com$', + ], + [ + 'body' => '\b[a-z]{30}\b', + 'author' => '\b[a-z]{10}\b', + 'host' => '\b[a-z]{10}\b', + ], + [ + 'body' => '\<\!.+?mfunc.+?\>', + ], + [ + 'author' => 'moncler|north face|vuitton|handbag|burberry|outlet|prada|cialis|viagra|maillot|oakley|ralph lauren|ray ban|iphone|プラダ', + ], + [ + 'host' => '^(www\.)?fkbook\.co\.uk$|^(www\.)?nsru\.net$|^(www\.)?goo\.gl$|^(www\.)?bit\.ly$', + ], + [ + 'body' => 'target[t]?ed (visitors|traffic)|viagra|cialis', + ], + [ + 'body' => 'purchase amazing|buy amazing|luxurybrandsale', + ], + [ + 'body' => 'dating|sex|lotto|pharmacy', + 'email' => '@mail\.ru|@yandex\.', + ], + ]; + + $quoted_author = preg_quote( $comment['author'], '/' ); + if ( $quoted_author ) { + $patterns[] = [ + 'body' => sprintf( + '%s<\/a>$', + $quoted_author + ), + ]; + $patterns[] = [ + 'body' => sprintf( + '%s https?:.+?$', + $quoted_author + ), + ]; + $patterns[] = [ + 'email' => '@gmail.com$', + 'author' => '^[a-z0-9-\.]+\.[a-z]{2,6}$', + 'host' => sprintf( + '^%s$', + $quoted_author + ), + ]; + } + + $patterns = apply_filters( + 'antispam_bee_patterns', + $patterns + ); + + if ( ! $patterns ) { + return false; + } + + foreach ( $patterns as $pattern ) { + $hits = []; + + foreach ( $pattern as $field => $regexp ) { + if ( empty( $field ) || ! in_array( $field, $fields, true ) || empty( $regexp ) ) { + continue; + } + + $comment[ $field ] = ( function_exists( 'iconv' ) ? iconv( 'utf-8', 'utf-8//TRANSLIT', $comment[ $field ] ) : $comment[ $field ] ); + + if ( empty( $comment[ $field ] ) ) { + continue; + } + + if ( preg_match( '/' . $regexp . '/isu', $comment[ $field ] ) ) { + $hits[ $field ] = true; + } + } + + if ( count( $hits ) === count( $pattern ) ) { + return true; + } + } + + return false; } public static function get_name() { - // TODO: Implement get_name() method. + return __( 'Regular Expression', 'antispam-bee' ); } public static function get_weight() { - // TODO: Implement get_weight() method. + return 1; } public static function get_slug() { - // TODO: Implement get_slug() method. + return 'asb-regexp'; } public static function is_final() { - // TODO: Implement is_final() method. + return false; + } + + public static function get_supported_types() { + return [ 'comment', 'trackback' ]; + } + + public static function get_label() { + __( 'Use regular expressions', 'antispam-bee' ); + } + + public static function get_description() { + __( 'Predefined and custom patterns by plugin hook', 'antispam-bee' ); + } + + public static function get_options() { + return null; } -} \ No newline at end of file +} diff --git a/inc/Rules/ShortestTime.php b/inc/Rules/ShortestTime.php index 88d87f0a..87dc4020 100644 --- a/inc/Rules/ShortestTime.php +++ b/inc/Rules/ShortestTime.php @@ -2,9 +2,13 @@ namespace AntispamBee\Rules; +use AntispamBee\Interfaces\Controllable; +use AntispamBee\Interfaces\Verifiable; + class ShortestTime implements Verifiable, Controllable { use InitRule; + use IsActive; public static function verify( $data ) { // phpcs:disable WordPress.Security.NonceVerification.Missing @@ -49,4 +53,8 @@ public static function get_description() { public static function get_options() { return null; } + + public static function get_supported_types() { + return [ 'comment', 'trackback' ]; + } } diff --git a/inc/Rules/TrackbackFromMyself.php b/inc/Rules/TrackbackFromMyself.php new file mode 100644 index 00000000..692cbdd7 --- /dev/null +++ b/inc/Rules/TrackbackFromMyself.php @@ -0,0 +1,67 @@ +post_content ); + $url_to_find = get_permalink( $target_post_id ); + if ( ! $url_to_find ) { + return -1; + } + foreach ( $urls as $url ) { + if ( strpos( $url, $url_to_find ) === 0 ) { + return 1; + } + } + return -1; + } + + public static function get_name() { + return __( 'Trackback from myself', 'antispam-bee' ); + } + + public static function get_weight() { + return 1.0; + } + + public static function get_slug() { + return 'asb-approved-email'; + } + + public static function is_final() { + return false; + } + + public static function get_supported_types() { + return [ 'trackback' ]; + } +} diff --git a/inc/Rules/TrackbackPostTitleIsBlogName.php b/inc/Rules/TrackbackPostTitleIsBlogName.php new file mode 100644 index 00000000..b97be6ca --- /dev/null +++ b/inc/Rules/TrackbackPostTitleIsBlogName.php @@ -0,0 +1,41 @@ +(.*)<\/strong>\\n\\n/', $body, $matches ); + if ( ! isset( $matches[1] ) ) { + return -1; + } + return trim( $matches[1] ) === trim( $blog_name ) ? 1 : -1; + } + + public static function get_name() { + return __( 'Trackback post title is blog name', 'antispam-bee' ); + } + + public static function get_weight() { + return 1.0; + } + + public static function get_slug() { + return 'asb-approved-email'; + } + + public static function is_final() { + return false; + } + + public static function get_supported_types() { + return [ 'trackback' ]; + } +} diff --git a/inc/Rules/ValidGravatar.php b/inc/Rules/ValidGravatar.php index 94d4304f..0dcfa01b 100644 --- a/inc/Rules/ValidGravatar.php +++ b/inc/Rules/ValidGravatar.php @@ -2,19 +2,13 @@ namespace AntispamBee\Rules; +use AntispamBee\Interfaces\Controllable; +use AntispamBee\Interfaces\Verifiable; + class ValidGravatar implements Verifiable, Controllable { use InitRule; - - public static function init() { - add_filter( 'asb_rules', function( $rules ) { - $rules[] = [ - 'weight' => self::get_weight(), - 'name' => self::get_name(), - 'callable' => array( self::class, 'verify' ), - ]; - } ); - } + use IsActive; public static function verify( $data ) { if ( ! isset( $data['email'] ) ) { @@ -78,4 +72,8 @@ public static function get_description() { public static function get_options() { return null; } + + public static function get_supported_types() { + return [ 'comment', 'trackback' ]; + } } diff --git a/inc/Settings.php b/inc/Settings.php index cfc4ee99..830a76f1 100644 --- a/inc/Settings.php +++ b/inc/Settings.php @@ -6,13 +6,67 @@ use AntispamBee\Rules\Verifiable; class Settings { + protected static $defaults; public static function init() { + self::init_options(); add_action( 'admin_menu', - array( + [ __CLASS__, 'add_sidebar_menu', - ) + ] + ); + } + + protected static function init_options() { + self::$defaults = array( + 'options' => array( + 'regexp_check' => 1, + 'spam_ip' => 1, + 'already_commented' => 1, + 'gravatar_check' => 0, + 'time_check' => 0, + 'ignore_pings' => 0, + + 'dashboard_chart' => 0, + 'dashboard_count' => 0, + + 'country_code' => 0, + 'country_denied' => '', + 'country_allowed' => '', + + 'translate_api' => 0, + 'translate_lang' => array(), + + 'bbcode_check' => 1, + + 'flag_spam' => 1, + 'email_notify' => 0, + 'no_notice' => 0, + 'cronjob_enable' => 0, + 'cronjob_interval' => 0, + + 'ignore_filter' => 0, + 'ignore_type' => 0, + + 'reasons_enable' => 0, + 'ignore_reasons' => array(), + + 'delete_data_on_uninstall' => 1, + ), + 'reasons' => array( + 'css' => esc_attr__( 'Honeypot', 'antispam-bee' ), + 'time' => esc_attr__( 'Comment time', 'antispam-bee' ), + 'empty' => esc_attr__( 'Empty Data', 'antispam-bee' ), + 'localdb' => esc_attr__( 'Local DB Spam', 'antispam-bee' ), + 'server' => esc_attr__( 'Fake IP', 'antispam-bee' ), + 'country' => esc_attr__( 'Country Check', 'antispam-bee' ), + 'bbcode' => esc_attr__( 'BBCode', 'antispam-bee' ), + 'lang' => esc_attr__( 'Comment Language', 'antispam-bee' ), + 'regexp' => esc_attr__( 'Regular Expression', 'antispam-bee' ), + 'title_is_name' => esc_attr__( 'Identical Post title and blog title', 'antispam-bee' ), + 'manually' => esc_attr__( 'Manually', 'antispam-bee' ), + ), ); } @@ -22,10 +76,10 @@ public static function add_sidebar_menu() { 'Antispam Bee', 'manage_options', 'antispam_bee', - array( + [ __CLASS__, 'options_page', - ) + ] ); } @@ -43,6 +97,8 @@ public static function options_page() { wp_nonce_field( '_antispam_bee__settings_nonce' ); $rules = apply_filters( 'asb_rules', [] ); foreach ( $rules as $rule ) { + // todo: Check if valid rule, can also have a callable in key (tbd) instead of verifiable (like + // implemented for the post processors). if ( ! isset( $rule['verifiable'] ) ) { continue; } @@ -67,4 +123,91 @@ public static function options_page() { private static function render_option( $verifiable ) { } + + /** + * Get all plugin options + * + * @return array $options Array with option fields. + */ + public static function get_options() { + $options = wp_cache_get( 'antispam_bee' ); + if ( ! $options ) { + wp_cache_set( + 'antispam_bee', + $options = get_option( 'antispam_bee' ) + ); + } + + if ( null === self::$defaults ) { + self::init_options(); + } + + return wp_parse_args( + $options, + self::$defaults['options'] + ); + } + + /** + * Get single option field + * + * @since 0.1 + * @since 2.4.2 + * + * @param string $field Field name. + * @return mixed Field value. + */ + public static function get_option( $field ) { + $options = self::get_options(); + + return self::get_key( $options, $field ); + } + + /** + * Update multiple option fields + * + * @since 0.1 + * @since 2.6.1 + * + * @param array $data Array with plugin option fields. + */ + public static function update_options( $data ) { + $options = get_option( 'antispam_bee' ); + + if ( is_array( $options ) ) { + $options = array_merge( + $options, + $data + ); + } else { + $options = $data; + } + + update_option( + 'antispam_bee', + $options + ); + + wp_cache_set( + 'antispam_bee', + $options + ); + } + + /** + * Update single option field + * + * @since 0.1 + * @since 2.4 + * + * @param string $field Field name. + * @param mixed $value The Field value. + */ + public static function update_option( $field, $value ) { + self::update_options( + array( + $field => $value, + ) + ); + } } diff --git a/lib/Helpers/DataHelper.php b/lib/Helpers/DataHelper.php index 7813d9e0..0c76fb1d 100644 --- a/lib/Helpers/DataHelper.php +++ b/lib/Helpers/DataHelper.php @@ -1,6 +1,6 @@ __( 'Comment', 'antispam-bee' ), + self::TRACKBACK_TYPE => __( 'Trackback', 'antispam-bee' ), + self::PINGBACK_TYPE => __( 'Pingback', 'antispam-bee' ) + ]; + + $type_names = array_merge( apply_filters( 'asb_item_types', [] ), $type_names ); + return isset( $type_names[$item_type] ) ? $type_names[$item_type] : $item_type; + } +} diff --git a/lib/Helpers/LangCodeHelper.php b/lib/Helpers/LangHelper.php similarity index 97% rename from lib/Helpers/LangCodeHelper.php rename to lib/Helpers/LangHelper.php index 36378a76..3193edb3 100644 --- a/lib/Helpers/LangCodeHelper.php +++ b/lib/Helpers/LangHelper.php @@ -1,8 +1,8 @@ 'za', 'zho' => 'zh', 'zul' => 'zu', @@ -200,7 +200,7 @@ public static function map( $franc_code ) { 'aym' => 'ay', 'aze' => 'az', 'nds' => 'de', - ); + ]; if ( array_key_exists( $franc_code, $codes ) ) { return $codes[ $franc_code ]; @@ -209,5 +209,4 @@ public static function map( $franc_code ) { return $franc_code; } - -} \ No newline at end of file +} diff --git a/lib/load.php b/lib/load.php index 5ca5ffc6..4dba1dc6 100644 --- a/lib/load.php +++ b/lib/load.php @@ -8,6 +8,23 @@ namespace AntispamBee; use AntispamBee\Helpers\AssetsLoader; +use AntispamBee\PostProcessors\Delete; +use AntispamBee\PostProcessors\DeleteForReasons; +use AntispamBee\PostProcessors\SaveReason; +use AntispamBee\PostProcessors\SendEmail; +use AntispamBee\PostProcessors\UpdateDailyStats; +use AntispamBee\PostProcessors\UpdateSpamCount; +use AntispamBee\PostProcessors\UpdateSpamLog; +use AntispamBee\Rules\ApprovedEmail; +use AntispamBee\Rules\BBCode; +use AntispamBee\Rules\CountrySpam; +use AntispamBee\Rules\DbSpam; +use AntispamBee\Rules\LangSpam; +use AntispamBee\Rules\RegexpSpam; +use AntispamBee\Rules\ShortestTime; +use AntispamBee\Rules\TrackbackFromMyself; +use AntispamBee\Rules\TrackbackPostTitleIsBlogName; +use AntispamBee\Rules\ValidGravatar; /** * Init function of the plugin @@ -16,6 +33,23 @@ function init() { // Construct all modules to initialize. $modules = [ 'helpers_assets_loader' => new AssetsLoader(), + 'approved_email_rule' => ApprovedEmail::class, + 'bbcode_rule' => BBCode::class, + 'country_spam_rule' => CountrySpam::class, + 'db_spam_rule' => DbSpam::class, + 'lang_spam_rule' => LangSpam::class, + 'regexp_spam_rule' => RegexpSpam::class, + 'shortest_time_rule' => ShortestTime::class, + 'trackback_from_myself_rule' => TrackbackFromMyself::class, + 'trackback_post_title_is_blog_name_rule' => TrackbackPostTitleIsBlogName::class, + 'valid_gravatar_rule' => ValidGravatar::class, + 'delete_post_processor' => Delete::class, + 'delete_for_reasons_post_processor' => DeleteForReasons::class, + 'save_reason_post_processor' => SaveReason::class, + 'send_email_post_processor' => SendEmail::class, + 'update_daily_stats_post_processor' => UpdateDailyStats::class, + 'update_spam_count_post_processor' => UpdateSpamCount::class, + 'update_spam_log_post_processor' => UpdateSpamLog::class ]; // Initialize all modules. From e9d0c0f6d7151914785dd02f11b9abd26e9f1b20 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sun, 20 Mar 2022 18:56:02 +0100 Subject: [PATCH 014/184] adding a todo for CommentsColumns --- lib/Helpers/CommentsColumns.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Helpers/CommentsColumns.php b/lib/Helpers/CommentsColumns.php index 843c121a..52a5c053 100644 --- a/lib/Helpers/CommentsColumns.php +++ b/lib/Helpers/CommentsColumns.php @@ -23,6 +23,7 @@ class CommentsColumns { * Registers the module hooks. */ public function init() { + // @todo: return early, if not on the correct "filter" page on the comments list. add_filter( 'manage_edit-comments_columns', [ $this, 'register_plugin_columns' ] ); add_filter( 'manage_comments_custom_column', [ $this, 'print_plugin_column' ], 10, 2 ); add_filter( 'manage_edit-comments_sortable_columns', [ $this, 'register_sortable_columns' ] ); From 732bd83d0d05ca5ec37040efa57bfd6c77cff7b7 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Mon, 21 Mar 2022 00:35:31 +0100 Subject: [PATCH 015/184] first working version of rules and postprocessors incl. honeypot (generalized) --- inc/Fields/Honeypot.php | 168 +++++++++++++++++++++ inc/Fields/Select.php | 2 +- inc/Handlers/Comment.php | 16 +- inc/Handlers/PostProcessors.php | 3 +- inc/Handlers/Rules.php | 4 +- inc/Interfaces/Verifiable.php | 2 + inc/PostProcessors/DeleteForReasons.php | 3 + inc/PostProcessors/InitPostProcessor.php | 2 + inc/PostProcessors/IsActive.php | 1 + inc/PostProcessors/SendEmail.php | 3 - inc/PostProcessors/UpdateDailyStats.php | 3 - inc/PostProcessors/UpdateSpamCount.php | 3 - inc/PostProcessors/UpdateSpamLog.php | 3 - inc/Rules/ApprovedEmail.php | 4 + inc/Rules/BBCode.php | 4 + inc/Rules/CountrySpam.php | 4 + inc/Rules/DbSpam.php | 4 + inc/Rules/Honeypot.php | 89 +++++++++++ inc/Rules/InitRule.php | 2 + inc/Rules/LangSpam.php | 4 + inc/Rules/RegexpSpam.php | 4 + inc/Rules/ShortestTime.php | 4 + inc/Rules/TrackbackFromMyself.php | 4 + inc/Rules/TrackbackPostTitleIsBlogName.php | 4 + inc/Rules/ValidGravatar.php | 4 + inc/Settings.php | 18 +++ lib/Helpers/DataHelper.php | 18 +++ lib/load.php | 16 +- 28 files changed, 377 insertions(+), 19 deletions(-) create mode 100644 inc/Fields/Honeypot.php create mode 100644 inc/Rules/Honeypot.php diff --git a/inc/Fields/Honeypot.php b/inc/Fields/Honeypot.php new file mode 100644 index 00000000..2ab0ebf1 --- /dev/null +++ b/inc/Fields/Honeypot.php @@ -0,0 +1,168 @@ +loadHTML( $markup, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD ); + $xpath = new DOMXPath( $dom ); + $input = $xpath->query( '//*[@id="' . $options['field_id'] . '"]' )->item( 0 ); + if ( ! $input ) { + return; + } + + $input_type = $input->nodeName; + $honeypot_id = $input->attributes->getNamedItem( 'id' )->textContent; + $honeypot_name = $input->attributes->getNamedItem( 'name' )->textContent; + $attributes_string = sprintf( + 'id="%s" name="%s" aria-hidden="true" aria-label="hp-comment" autocomplete="new-password" tabindex="-1" style="padding:0 !important;clip:rect(1px, 1px, 1px, 1px) !important;position:absolute !important;white-space:nowrap !important;height:1px !important;width:1px !important;overflow:hidden !important;"', + $honeypot_id, + $honeypot_name + ); + switch ( $input_type ) { + case 'textarea': + $item = sprintf( + '', + $attributes_string + ); + + $regex = str_replace( + [ '{{HONEYPOT_ID}}', '{{HONEYPOT_NAME}}' ], + [ $honeypot_id, $honeypot_name ], + '/(?P + '; + + $output .= $id_script; + return $output; + }, $markup ); + break; + case 'input': + $item = sprintf( + '', + $attributes_string + ); + + break; + default: + break; + } + + return $markup; + } + + + /** + * Returns the secret of a post used in the textarea id attribute. + * + * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * + * @param int $post_id The post ID. + * + * @return string + */ + public static function get_secret_id_for_post() { + $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); + return self::ensure_secret_starts_with_letter( $secret ); + } + + /** + * Returns the secret of a post used in the textarea name attribute. + * + * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * + * @param int $post_id The Post ID. + * + * @return string + */ + public static function get_secret_name_for_post() { + $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); + return self::ensure_secret_starts_with_letter( $secret ); + } + + /** + * Ensures that the secret starts with a letter. + * + * @param string $secret The secret. + * + * @return string + */ + public static function ensure_secret_starts_with_letter( $secret ) { + + $first_char = substr( $secret, 0, 1 ); + if ( is_numeric( $first_char ) ) { + return chr( $first_char + 97 ) . substr( $secret, 1 ); + } + + return $secret; + } + + /** + * Testing if we are on an AMP site. + * + * Starting with v2.0, amp_is_request() is the preferred method to check, + * but we fall back to the then deprecated is_amp_endpoint() as needed. + * + * @return bool + */ + private static function _is_amp() { + return ( function_exists( 'amp_is_request' ) && amp_is_request() ) || ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ); + } + + private static function get_salt() { + $salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : ABSPATH; + return substr( sha1( $salt ), 0, 10 ); + } +} diff --git a/inc/Fields/Select.php b/inc/Fields/Select.php index 0188c44c..c7f089bf 100644 --- a/inc/Fields/Select.php +++ b/inc/Fields/Select.php @@ -2,6 +2,6 @@ namespace AntispamBee\Fields; -class Checkbox { +class Select { } diff --git a/inc/Handlers/Comment.php b/inc/Handlers/Comment.php index 0a3c4c49..abc3dd52 100644 --- a/inc/Handlers/Comment.php +++ b/inc/Handlers/Comment.php @@ -4,10 +4,21 @@ use AntispamBee\Helpers\DataHelper; use AntispamBee\Helpers\IpHelper; +use AntispamBee\Rules\Honeypot; class Comment { public static function init() { add_action( + 'init', + function() { + if ( ! Honeypot::is_active() ) { + return; + } + Honeypot::precheck(); + } + ); + + add_filter( 'preprocess_comment', [ __CLASS__, @@ -25,13 +36,13 @@ public static function process( $comment ) { if ( empty( $request_path ) ) { PostProcessors::apply( 'comment', $comment, [ 'empty' ] ); - return; + return $comment; } // phpcs:disable WordPress.Security.NonceVerification.Missing // Everybody can post. if ( strpos( $request_path, 'wp-comments-post.php' ) === false || empty( $_POST ) ) { - return; + return $comment; } // phpcs:enable WordPress.Security.NonceVerification.Missing @@ -42,6 +53,7 @@ public static function process( $comment ) { PostProcessors::apply( 'comment', $comment, $rules->get_spam_reasons() ); } + return $comment; // todo: Maybe store no-spam-reasons } } diff --git a/inc/Handlers/PostProcessors.php b/inc/Handlers/PostProcessors.php index a22a15b8..d04896d6 100644 --- a/inc/Handlers/PostProcessors.php +++ b/inc/Handlers/PostProcessors.php @@ -7,6 +7,7 @@ class PostProcessors { public static function apply( $type, $item, $reasons = [] ) { $post_processors = self::get( $type, true ); + $item['asb_reasons'] = $reasons; $item['asb_item_type'] = $type; for ( $i = 0; $i < count( $post_processors ); $i++ ) { @@ -14,7 +15,7 @@ public static function apply( $type, $item, $reasons = [] ) { $marks_as_delete_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'marks_as_delete' ] : $post_processor['marks_as_delete']; if ( call_user_func( $marks_as_delete_function ) ) { unset( $post_processors[$i] ); - array_unshift( $post_processor ); + array_unshift( $post_processors, $post_processor ); } } diff --git a/inc/Handlers/Rules.php b/inc/Handlers/Rules.php index 5df8bc30..e8fdb1fc 100644 --- a/inc/Handlers/Rules.php +++ b/inc/Handlers/Rules.php @@ -33,11 +33,11 @@ public function apply( $item ) { $no_spam_threshold = (float) apply_filters( 'asb_no_spam_threshold', 0.0 ); $spam_threshold = (float) apply_filters( 'asb_spam_threshold', 0.0 ); - if ( $no_spam_threshold <= 0.0 && $score <= $no_spam_threshold ) { + if ( $no_spam_threshold < 0.0 && $score <= $no_spam_threshold ) { return false; } - if ( $spam_threshold >= 0.0 && $score >= $spam_threshold ) { + if ( $spam_threshold > 0.0 && $score >= $spam_threshold ) { return true; } } diff --git a/inc/Interfaces/Verifiable.php b/inc/Interfaces/Verifiable.php index 0d76a8a6..c8af91f3 100644 --- a/inc/Interfaces/Verifiable.php +++ b/inc/Interfaces/Verifiable.php @@ -14,4 +14,6 @@ public static function get_slug(); public static function get_supported_types(); public static function is_final(); + + public static function is_active(); } diff --git a/inc/PostProcessors/DeleteForReasons.php b/inc/PostProcessors/DeleteForReasons.php index 5868f995..a6b4a48a 100644 --- a/inc/PostProcessors/DeleteForReasons.php +++ b/inc/PostProcessors/DeleteForReasons.php @@ -17,6 +17,9 @@ public static function process( $item ) { } $reasons = Settings::get_option( $item['asb_item_type'] . '_' . self::get_slug() ); + if ( ! $reasons ) { + $reasons = []; + } if ( ! empty( array_intersect( $item['asb_reasons'], $reasons ) ) ) { $item['asb_marked_as_delete'] = true; } diff --git a/inc/PostProcessors/InitPostProcessor.php b/inc/PostProcessors/InitPostProcessor.php index d147c886..dbf28dd2 100644 --- a/inc/PostProcessors/InitPostProcessor.php +++ b/inc/PostProcessors/InitPostProcessor.php @@ -8,6 +8,8 @@ public static function init() { $post_processors[] = [ 'post_processor' => self::class ]; + + return $post_processors; } ); } } diff --git a/inc/PostProcessors/IsActive.php b/inc/PostProcessors/IsActive.php index 40a61f7f..761022f6 100644 --- a/inc/PostProcessors/IsActive.php +++ b/inc/PostProcessors/IsActive.php @@ -6,6 +6,7 @@ trait IsActive { public static function is_active( $type ) { + return true; return Settings::get_option( $type . '_' . self::get_slug() . '_active' ); } } diff --git a/inc/PostProcessors/SendEmail.php b/inc/PostProcessors/SendEmail.php index fc227708..73ee89fa 100644 --- a/inc/PostProcessors/SendEmail.php +++ b/inc/PostProcessors/SendEmail.php @@ -141,9 +141,6 @@ function ( $id ) use ( $item ) { return $item; } - public static function is_active( $type ) { - } - public static function get_slug() { return 'asb-send-email'; } diff --git a/inc/PostProcessors/UpdateDailyStats.php b/inc/PostProcessors/UpdateDailyStats.php index a984a6fd..b8b9ce3f 100644 --- a/inc/PostProcessors/UpdateDailyStats.php +++ b/inc/PostProcessors/UpdateDailyStats.php @@ -35,9 +35,6 @@ public static function process( $item ) { return $item; } - public static function is_active( $type ) { - } - public static function get_slug() { return 'asb-send-email'; } diff --git a/inc/PostProcessors/UpdateSpamCount.php b/inc/PostProcessors/UpdateSpamCount.php index 3bf220cb..363a2ddd 100644 --- a/inc/PostProcessors/UpdateSpamCount.php +++ b/inc/PostProcessors/UpdateSpamCount.php @@ -24,9 +24,6 @@ public static function process( $item ) { return $item; } - public static function is_active( $type ) { - } - public static function get_slug() { return 'asb-send-email'; } diff --git a/inc/PostProcessors/UpdateSpamLog.php b/inc/PostProcessors/UpdateSpamLog.php index ae94a26d..4cf3e48f 100644 --- a/inc/PostProcessors/UpdateSpamLog.php +++ b/inc/PostProcessors/UpdateSpamLog.php @@ -36,9 +36,6 @@ public static function process( $item ) { return $item; } - public static function is_active( $type ) { - } - public static function get_slug() { return 'asb-send-email'; } diff --git a/inc/Rules/ApprovedEmail.php b/inc/Rules/ApprovedEmail.php index 56ae1183..a24affad 100644 --- a/inc/Rules/ApprovedEmail.php +++ b/inc/Rules/ApprovedEmail.php @@ -63,4 +63,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/BBCode.php b/inc/Rules/BBCode.php index 7ceb56ba..8ecbae8b 100644 --- a/inc/Rules/BBCode.php +++ b/inc/Rules/BBCode.php @@ -50,4 +50,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/CountrySpam.php b/inc/Rules/CountrySpam.php index b3f22e71..a6c4444d 100644 --- a/inc/Rules/CountrySpam.php +++ b/inc/Rules/CountrySpam.php @@ -154,4 +154,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/DbSpam.php b/inc/Rules/DbSpam.php index 65e5e180..ab0f9fb7 100644 --- a/inc/Rules/DbSpam.php +++ b/inc/Rules/DbSpam.php @@ -86,4 +86,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/Honeypot.php b/inc/Rules/Honeypot.php new file mode 100644 index 00000000..4a5f14a1 --- /dev/null +++ b/inc/Rules/Honeypot.php @@ -0,0 +1,89 @@ + $value ) { + if ( isset( $fields['plugin_field'] ) ) { + $fields['hidden_field'] = $key; + break; + } + if ( $key === HoneypotField::get_secret_name_for_post() ) { + $fields['plugin_field'] = $key; + } + } + if ( ! empty( $_POST[$fields['hidden_field']] ) ) { + $_POST['ab_spam__hidden_field'] = 1; + } else { + $_POST[$fields['hidden_field']] = $_POST[$fields['plugin_field']]; + unset( $_POST[ HoneypotField::get_secret_name_for_post() ] ); + } + // phpcs:enable WordPress.Security.NonceVerification.Missing + } + + public static function get_name() { + return __( 'Approved Email', 'antispam-bee' ); + } + + public static function get_label() { + return __( '', 'antispam-bee' ); + } + + public static function get_description() { + return __( 'No review of already commented users', 'antispam-bee' ); + } + + public static function get_weight() { + return 1.0; + } + + public static function get_slug() { + return 'asb-honeypot'; + } + + public static function is_final() { + return false; + } + + public static function get_options() { + return null; + } + + public static function get_supported_types() { + return [ 'comment' ]; + } + + public static function is_active() { + return true; + } +} diff --git a/inc/Rules/InitRule.php b/inc/Rules/InitRule.php index e3b90653..eb581352 100644 --- a/inc/Rules/InitRule.php +++ b/inc/Rules/InitRule.php @@ -8,6 +8,8 @@ public static function init() { $rules[] = [ 'verifiable' => self::class, ]; + + return $rules; } ); } } diff --git a/inc/Rules/LangSpam.php b/inc/Rules/LangSpam.php index 6c73031e..a5c4e4c1 100644 --- a/inc/Rules/LangSpam.php +++ b/inc/Rules/LangSpam.php @@ -128,4 +128,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/RegexpSpam.php b/inc/Rules/RegexpSpam.php index 31352500..a037fc7c 100644 --- a/inc/Rules/RegexpSpam.php +++ b/inc/Rules/RegexpSpam.php @@ -148,4 +148,8 @@ public static function get_description() { public static function get_options() { return null; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/ShortestTime.php b/inc/Rules/ShortestTime.php index 87dc4020..221cabee 100644 --- a/inc/Rules/ShortestTime.php +++ b/inc/Rules/ShortestTime.php @@ -57,4 +57,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/TrackbackFromMyself.php b/inc/Rules/TrackbackFromMyself.php index 692cbdd7..7dafe99d 100644 --- a/inc/Rules/TrackbackFromMyself.php +++ b/inc/Rules/TrackbackFromMyself.php @@ -64,4 +64,8 @@ public static function is_final() { public static function get_supported_types() { return [ 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/TrackbackPostTitleIsBlogName.php b/inc/Rules/TrackbackPostTitleIsBlogName.php index b97be6ca..24053ebf 100644 --- a/inc/Rules/TrackbackPostTitleIsBlogName.php +++ b/inc/Rules/TrackbackPostTitleIsBlogName.php @@ -38,4 +38,8 @@ public static function is_final() { public static function get_supported_types() { return [ 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Rules/ValidGravatar.php b/inc/Rules/ValidGravatar.php index 0dcfa01b..bc28aca7 100644 --- a/inc/Rules/ValidGravatar.php +++ b/inc/Rules/ValidGravatar.php @@ -76,4 +76,8 @@ public static function get_options() { public static function get_supported_types() { return [ 'comment', 'trackback' ]; } + + public static function is_active() { + return false; + } } diff --git a/inc/Settings.php b/inc/Settings.php index 830a76f1..d601beae 100644 --- a/inc/Settings.php +++ b/inc/Settings.php @@ -210,4 +210,22 @@ public static function update_option( $field, $value ) { ) ); } + + /** + * Check and return an array key + * + * @since 2.4.2 + * @since 2.10.0 Only return `null` if option does not exist. + * + * @param array $array Array with values. + * @param string $key Name of the key. + * @return mixed Value of the requested key. + */ + public static function get_key( $array, $key ) { + if ( empty( $array ) || empty( $key ) || ! isset( $array[ $key ] ) ) { + return null; + } + + return $array[ $key ]; + } } diff --git a/lib/Helpers/DataHelper.php b/lib/Helpers/DataHelper.php index 0c76fb1d..ac84b5ef 100644 --- a/lib/Helpers/DataHelper.php +++ b/lib/Helpers/DataHelper.php @@ -32,4 +32,22 @@ public static function parse_url( $url, $component = 'host' ) { $parts = wp_parse_url( $url ); return ( is_array( $parts ) && isset( $parts[ $component ] ) ) ? $parts[ $component ] : ''; } + + /** + * Check and return an array key + * + * @since 2.4.2 + * @since 2.10.0 Only return `null` if option does not exist. + * + * @param array $array Array with values. + * @param string $key Name of the key. + * @return mixed Value of the requested key. + */ + public static function get_key( $array, $key ) { + if ( empty( $array ) || empty( $key ) || ! isset( $array[ $key ] ) ) { + return null; + } + + return $array[ $key ]; + } } diff --git a/lib/load.php b/lib/load.php index 4dba1dc6..59513b37 100644 --- a/lib/load.php +++ b/lib/load.php @@ -7,6 +7,10 @@ namespace AntispamBee; +use AntispamBee\Fields\Honeypot as HoneypotField; +use AntispamBee\Rules\Honeypot as HoneypotRule; +use AntispamBee\Handlers\Comment; +use AntispamBee\Handlers\Trackback; use AntispamBee\Helpers\AssetsLoader; use AntispamBee\PostProcessors\Delete; use AntispamBee\PostProcessors\DeleteForReasons; @@ -43,13 +47,16 @@ function init() { 'trackback_from_myself_rule' => TrackbackFromMyself::class, 'trackback_post_title_is_blog_name_rule' => TrackbackPostTitleIsBlogName::class, 'valid_gravatar_rule' => ValidGravatar::class, + 'honeypot_rule' => HoneypotRule::class, 'delete_post_processor' => Delete::class, 'delete_for_reasons_post_processor' => DeleteForReasons::class, 'save_reason_post_processor' => SaveReason::class, 'send_email_post_processor' => SendEmail::class, 'update_daily_stats_post_processor' => UpdateDailyStats::class, 'update_spam_count_post_processor' => UpdateSpamCount::class, - 'update_spam_log_post_processor' => UpdateSpamLog::class + 'update_spam_log_post_processor' => UpdateSpamLog::class, + 'comment_handler' => Comment::class, + 'trackback_handler' => Trackback::class, ]; // Initialize all modules. @@ -58,6 +65,13 @@ function init() { call_user_func( [ $module, 'init' ] ); } } + + add_filter( + 'comment_form_field_comment', + function( $field_markup ) { + return HoneypotField::inject( $field_markup, [ 'field_id' => 'comment' ] ); + } + ); } add_action( 'plugins_loaded', 'AntispamBee\init' ); From d0401f90bd2910f5cf0f83e10cb4355d0c417819 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 10:43:02 +0100 Subject: [PATCH 016/184] implement an OptionsHelper to enable the plugin to work with the Antispam Bee option --- lib/Helpers/CommentsColumns.php | 41 +++------ lib/Helpers/DashboardHelper.php | 71 ++++++++++++++++ lib/Helpers/OptionsHelper.php | 146 ++++++++++++++++++++++++++++++++ lib/load.php | 2 + 4 files changed, 230 insertions(+), 30 deletions(-) create mode 100644 lib/Helpers/DashboardHelper.php create mode 100644 lib/Helpers/OptionsHelper.php diff --git a/lib/Helpers/CommentsColumns.php b/lib/Helpers/CommentsColumns.php index 52a5c053..1241855c 100644 --- a/lib/Helpers/CommentsColumns.php +++ b/lib/Helpers/CommentsColumns.php @@ -12,18 +12,14 @@ */ class CommentsColumns { - /** - * The known spam reasons. - * - * @var array - */ - public static $reasons = []; - /** * Registers the module hooks. */ public function init() { - // @todo: return early, if not on the correct "filter" page on the comments list. + if ( ! DashboardHelper::is_edit_spam_comments_page() && ! OptionsHelper::get_option( 'no_notice' ) ) { + return; + } + add_filter( 'manage_edit-comments_columns', [ $this, 'register_plugin_columns' ] ); add_filter( 'manage_comments_custom_column', [ $this, 'print_plugin_column' ], 10, 2 ); add_filter( 'manage_edit-comments_sortable_columns', [ $this, 'register_sortable_columns' ] ); @@ -31,23 +27,6 @@ public function init() { add_action( 'restrict_manage_comments', [ $this, 'filter_columns' ] ); add_action( 'pre_get_comments', [ $this, 'filter_by_spam_reason' ] ); add_filter( 'admin_print_styles-edit-comments.php', [ $this, 'print_column_styles' ] ); - - // @todo: replace this with the dynamic list of spam reasons from the rules list. - $default_reasons = [ - 'css' => esc_attr__( 'Honeypot', 'antispam-bee' ), - 'time' => esc_attr__( 'Comment time', 'antispam-bee' ), - 'empty' => esc_attr__( 'Empty Data', 'antispam-bee' ), - 'localdb' => esc_attr__( 'Local DB Spam', 'antispam-bee' ), - 'server' => esc_attr__( 'Fake IP', 'antispam-bee' ), - 'country' => esc_attr__( 'Country Check', 'antispam-bee' ), - 'bbcode' => esc_attr__( 'BBCode', 'antispam-bee' ), - 'lang' => esc_attr__( 'Comment Language', 'antispam-bee' ), - 'regexp' => esc_attr__( 'Regular Expression', 'antispam-bee' ), - 'title_is_name' => esc_attr__( 'Identical Post title and blog title', 'antispam-bee' ), - 'manually' => esc_attr__( 'Manually', 'antispam-bee' ), - ]; - - self::$reasons = apply_filters( 'asb_spam_reasons_list', $default_reasons ); } /** @@ -71,7 +50,7 @@ public static function register_plugin_columns( $columns ) { /** * Display plugin column values on comments screen * - * @param string $column Currently selected column. + * @param string $column Currently selected column. * @param integer $comment_id Comment ID. * * @since 2.6.0 @@ -83,7 +62,7 @@ public static function print_plugin_column( $column, $comment_id ) { } $spam_reason = get_comment_meta( $comment_id, $column, true ); - $spam_reasons = self::$reasons; + $spam_reasons = OptionsHelper::get_options( 'reasons' ); if ( empty( $spam_reason ) || empty( $spam_reasons[ $spam_reason ] ) ) { return; @@ -140,20 +119,21 @@ public static function filter_columns() { - + active_section ); ?> tabs[] = new Tab( - 'general', __( 'General', 'antispam-bee' ), - [ - new Section( - 'global_settings', - __('Global Settings', 'antispam-bee' ), - __('Setup global plugin spam settings.', 'antispam-bee' ),// @todo Description? - [ - new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), - new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), - new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), - new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ) - ] - ) - ] - ); - - $this->tabs = apply_filters( 'antispam_bee_tabs', $this->tabs ); - - // Register option setting - foreach( $this->tabs as $tab ) { - foreach ( $tab->get_sections() as $section ) { - add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); - - foreach( $section->get_fields() as $field ) { - add_settings_field( - $field->get_name(), - $field->get_label(), - [ $field, 'render' ], - 'antispam_bee', - $section->get_name() - ); - - register_setting( 'antispam_bee', $field->get_name() ); - } - } - } - } } \ No newline at end of file diff --git a/inc/Admin/Tab.php b/inc/Admin/Tab.php deleted file mode 100644 index b4ce36cc..00000000 --- a/inc/Admin/Tab.php +++ /dev/null @@ -1,68 +0,0 @@ -name = $name; - $this->title = $title; - $this->sections = $sections; - } - - /** - * Get Name. - * - * @return string Name of the field. - */ - public function get_name() { - return $this->name; - } - - /** - * Get title. - * - * @return string Title of the field. - */ - public function get_title() { - return $this->title; - } - - /** - * Get sections. - * - * @return Section[] - */ - public function get_sections() { - return $this->sections; - } -} \ No newline at end of file From e30101ee65d6dd05fc0dcba1c3a12be6aa67c2ec Mon Sep 17 00:00:00 2001 From: Sven Wagener Date: Mon, 21 Mar 2022 11:45:45 +0100 Subject: [PATCH 022/184] Fixed checkbox value --- inc/Admin/Fields/Checkbox.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/Admin/Fields/Checkbox.php b/inc/Admin/Fields/Checkbox.php index 1566910a..6ec862e4 100644 --- a/inc/Admin/Fields/Checkbox.php +++ b/inc/Admin/Fields/Checkbox.php @@ -12,7 +12,7 @@ class Checkbox extends Field implements RenderElement { * Get HTML. */ public function render() { - echo 'get_value(), true ) . ' />'; + echo 'get_value(), false ) . ' />'; $this->maybe_show_description(); } } From d5b45d7dc4f21da8464d9c2a82ab3036464d41fd Mon Sep 17 00:00:00 2001 From: Sven Wagener Date: Mon, 21 Mar 2022 11:45:56 +0100 Subject: [PATCH 023/184] Added textarea --- inc/Admin/Fields/Textarea.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 inc/Admin/Fields/Textarea.php diff --git a/inc/Admin/Fields/Textarea.php b/inc/Admin/Fields/Textarea.php new file mode 100644 index 00000000..05e832ee --- /dev/null +++ b/inc/Admin/Fields/Textarea.php @@ -0,0 +1,20 @@ +get_name() . '">' . $this->get_value() . ''; + $this->maybe_show_description(); + } +} From bce5a3769a458466d3925807321c71377c621c8c Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 11:38:17 +0100 Subject: [PATCH 024/184] add the OptionsPage class for the new UI --- lib/Admin/OptionsPage.php | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 lib/Admin/OptionsPage.php diff --git a/lib/Admin/OptionsPage.php b/lib/Admin/OptionsPage.php new file mode 100644 index 00000000..1c8fcddc --- /dev/null +++ b/lib/Admin/OptionsPage.php @@ -0,0 +1,69 @@ + Date: Mon, 21 Mar 2022 12:09:32 +0100 Subject: [PATCH 025/184] add missing options function --- lib/Helpers/OptionsHelper.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/Helpers/OptionsHelper.php b/lib/Helpers/OptionsHelper.php index fd21f3bb..92bcf9f2 100644 --- a/lib/Helpers/OptionsHelper.php +++ b/lib/Helpers/OptionsHelper.php @@ -110,6 +110,24 @@ public static function get_option( $field ) { return self::get_key( $options, $field ); } + /** + * Update single option field + * + * @param string $field Field name. + * @param mixed $value The Field value. + * + * @since 0.1 + * @since 2.4 + * + */ + public static function update_option( $field, $value ) { + self::update_options( + [ + $field => $value, + ] + ); + } + /** * Update multiple option fields * From c9a3492447e56fd9f881f2957060cba35d039ae9 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 15:54:57 +0100 Subject: [PATCH 026/184] code style fixes (mostly whitespaces) --- inc/Admin/Fields/Checkbox.php | 14 +- inc/Admin/Fields/Field.php | 142 +++++++-------- inc/Admin/Fields/Text.php | 18 +- inc/Admin/Fields/Textarea.php | 18 +- inc/Admin/RenderElement.php | 14 +- inc/Admin/Section.php | 148 +++++++-------- inc/Admin/SettingsPage.php | 198 ++++++++++----------- inc/Fields/Honeypot.php | 31 ++-- inc/Handlers/Comment.php | 5 +- inc/Handlers/PostProcessors.php | 16 +- inc/Handlers/Rules.php | 12 +- inc/Interfaces/Controllable.php | 19 +- inc/PostProcessors/InitPostProcessor.php | 2 +- inc/PostProcessors/SaveReason.php | 3 +- inc/PostProcessors/SendEmail.php | 108 +++++------ inc/PostProcessors/UpdateDailyStats.php | 1 - inc/PostProcessors/UpdateSpamCount.php | 1 - inc/PostProcessors/UpdateSpamLog.php | 1 - inc/Rules/ApprovedEmail.php | 6 +- inc/Rules/BBCode.php | 1 + inc/Rules/Controllable.php | 19 +- inc/Rules/CountrySpam.php | 15 +- inc/Rules/DbSpam.php | 2 +- inc/Rules/Honeypot.php | 7 +- inc/Rules/InitRule.php | 2 +- inc/Rules/IsActive.php | 2 +- inc/Rules/LangSpam.php | 11 +- inc/Rules/RegexpSpam.php | 4 +- inc/Rules/TrackbackFromMyself.php | 15 +- inc/Rules/TrackbackPostTitleIsBlogName.php | 7 +- inc/Settings.php | 74 ++++---- lib/Admin/DashboardWidgets.php | 113 ++++++++++++ lib/Admin/OptionsPage.php | 6 +- lib/Helpers/AssetsLoader.php | 41 +++++ lib/Helpers/StatsHelpers.php | 85 +++++++++ lib/load.php | 52 +++--- package.json | 3 + src/legacy/dashboard.js | 112 ++++++++++++ src/legacy/raphael.helper.js | 140 +++++++++++++++ src/legacy/raphael.min.js | 3 + 40 files changed, 993 insertions(+), 478 deletions(-) create mode 100644 lib/Admin/DashboardWidgets.php create mode 100644 lib/Helpers/StatsHelpers.php create mode 100644 src/legacy/dashboard.js create mode 100644 src/legacy/raphael.helper.js create mode 100644 src/legacy/raphael.min.js diff --git a/inc/Admin/Fields/Checkbox.php b/inc/Admin/Fields/Checkbox.php index 6ec862e4..058822f0 100644 --- a/inc/Admin/Fields/Checkbox.php +++ b/inc/Admin/Fields/Checkbox.php @@ -8,11 +8,11 @@ * Checkbox field. */ class Checkbox extends Field implements RenderElement { - /** - * Get HTML. - */ - public function render() { - echo 'get_value(), false ) . ' />'; - $this->maybe_show_description(); - } + /** + * Get HTML. + */ + public function render() { + echo 'get_value(), false ) . ' />'; + $this->maybe_show_description(); + } } diff --git a/inc/Admin/Fields/Field.php b/inc/Admin/Fields/Field.php index 7924b6c6..7953aa13 100644 --- a/inc/Admin/Fields/Field.php +++ b/inc/Admin/Fields/Field.php @@ -6,82 +6,82 @@ * Abstract class for field. */ abstract class Field { - /** - * Field Name. - * - * @param string - */ - private $name; + /** + * Field Name. + * + * @param string + */ + private $name; - /** - * Field Description. - * - * @param string - */ - private $description; + /** + * Field Description. + * + * @param string + */ + private $description; - /** - * Initializing field - * - * @param string $name Name of the field. - * @param string $label Label of the field. - * @param string $description Description of the field. - */ - public function __construct( $name, $label, $description = '' ) { - $this->name = $name; - $this->label = $label; - $this->description = $description; - } + /** + * Initializing field + * + * @param string $name Name of the field. + * @param string $label Label of the field. + * @param string $description Description of the field. + */ + public function __construct( $name, $label, $description = '' ) { + $this->name = $name; + $this->label = $label; + $this->description = $description; + } - /** - * Get Name. - * - * @return string Name of the field. - */ - public function get_name() { - return $this->name; - } + /** + * Get Name. + * + * @return string Name of the field. + */ + public function get_name() { + return $this->name; + } - /** - * Get label. - * - * @return string Label of the field. - */ - public function get_label() { - return $this->label; - } + /** + * Get label. + * + * @return string Label of the field. + */ + public function get_label() { + return $this->label; + } - /** - * Get Description. - * - * @return string Description of the field. - */ - public function get_description() { - return $this->description; - } + /** + * Get Description. + * + * @return string Description of the field. + */ + public function get_description() { + return $this->description; + } - /** - * Get Value. - * - * @return mixed Value stored in database. - */ - protected function get_value() { - return get_option( $this->name ); - } + /** + * Get Value. + * + * @return mixed Value stored in database. + */ + protected function get_value() { + return get_option( $this->name ); + } - /** - * Show description if not empty. - */ - protected function maybe_show_description() { - if ( ! empty( $this->get_description() ) ) { - echo '' . $this->get_description() . ''; - } - } + /** + * Show description if not empty. + */ + protected function maybe_show_description() { + if ( ! empty( $this->get_description() ) ) { + echo '' . $this->get_description() . ''; + } + } - /** - * Get HTML for field. - * - * @return string Elment HTML. - */ - abstract public function render(); -} \ No newline at end of file + /** + * Get HTML for field. + * + * @return string Elment HTML. + */ + abstract public function render(); +} diff --git a/inc/Admin/Fields/Text.php b/inc/Admin/Fields/Text.php index a6f30ac3..a5ffa6a8 100644 --- a/inc/Admin/Fields/Text.php +++ b/inc/Admin/Fields/Text.php @@ -8,13 +8,13 @@ * Text field. */ class Text extends Field implements RenderElement { - /** - * Get HTML. - * - * @return string Elment HTML. - */ - public function render() { - echo ''; - $this->maybe_show_description(); - } + /** + * Get HTML. + * + * @return string Elment HTML. + */ + public function render() { + echo ''; + $this->maybe_show_description(); + } } diff --git a/inc/Admin/Fields/Textarea.php b/inc/Admin/Fields/Textarea.php index 05e832ee..646f77e6 100644 --- a/inc/Admin/Fields/Textarea.php +++ b/inc/Admin/Fields/Textarea.php @@ -8,13 +8,13 @@ * Text field. */ class Textarea extends Field implements RenderElement { - /** - * Get HTML. - * - * @return string Elment HTML. - */ - public function render() { - echo ''; - $this->maybe_show_description(); - } + /** + * Get HTML. + * + * @return string Elment HTML. + */ + public function render() { + echo ''; + $this->maybe_show_description(); + } } diff --git a/inc/Admin/RenderElement.php b/inc/Admin/RenderElement.php index ff20c3fb..c6f6385f 100644 --- a/inc/Admin/RenderElement.php +++ b/inc/Admin/RenderElement.php @@ -6,10 +6,10 @@ * Render Element. */ interface RenderElement { - /** - * Render function. - * - * @return string Rendered Element. - */ - public function render(); -} \ No newline at end of file + /** + * Render function. + * + * @return string Rendered Element. + */ + public function render(); +} diff --git a/inc/Admin/Section.php b/inc/Admin/Section.php index a9c3938b..52447e11 100644 --- a/inc/Admin/Section.php +++ b/inc/Admin/Section.php @@ -6,86 +6,86 @@ * Sections for admin. */ class Section { - /** - * Name. - * - * @var string - */ - private $name; + /** + * Name. + * + * @var string + */ + private $name; - /** - * Title. - * - * @var string - */ - private $title; + /** + * Title. + * + * @var string + */ + private $title; - /** - * Description. - * - * @var string - */ - private $description; + /** + * Description. + * + * @var string + */ + private $description; - /** - * Fields. - * - * @var Field[] - */ - private $fields; + /** + * Fields. + * + * @var Field[] + */ + private $fields; - /** - * Initializung Tab. - * - * @param string $label Title for tab - * @param Section[] $sections Sections object array. - */ - public function __construct( $name, $title, $description = '', $fields ) { - $this->name = $name; - $this->title = $title; - $this->fields = $fields; - $this->description = $description; - } + /** + * Initializung Tab. + * + * @param string $label Title for tab + * @param Section[] $sections Sections object array. + */ + public function __construct( $name, $title, $description = '', $fields ) { + $this->name = $name; + $this->title = $title; + $this->fields = $fields; + $this->description = $description; + } - /** - * Get Name. - * - * @return string Name of the field. - */ - public function get_name() { - return $this->name; - } + /** + * Get Name. + * + * @return string Name of the field. + */ + public function get_name() { + return $this->name; + } - /** - * Get title. - * - * @return string Title of the field. - */ - public function get_title() { - return $this->title; - } + /** + * Get title. + * + * @return string Title of the field. + */ + public function get_title() { + return $this->title; + } - /** - * Get description. - * - * @return string Title of the field. - */ - public function get_description() { - return $this->description; - } + /** + * Get description. + * + * @return string Title of the field. + */ + public function get_description() { + return $this->description; + } - /** - * Get fields. - * - * @return Field[] - */ - public function get_fields() { - return $this->fields; - } + /** + * Get fields. + * + * @return Field[] + */ + public function get_fields() { + return $this->fields; + } - public function get_callback() { - if ( ! empty( $this->description ) ) { - echo '

' . $this->get_description() . '

'; - } - } -} \ No newline at end of file + public function get_callback() { + if ( ! empty( $this->description ) ) { + echo '

' . $this->get_description() . '

'; + } + } +} diff --git a/inc/Admin/SettingsPage.php b/inc/Admin/SettingsPage.php index 9bf12da7..496e41bb 100644 --- a/inc/Admin/SettingsPage.php +++ b/inc/Admin/SettingsPage.php @@ -8,110 +8,110 @@ * Antispam Bee Settings Page */ class SettingsPage { - /** - * Active section - * - * @var string - */ - private $active_section = []; - - /** - * Tabs - * - * @var Section[] - */ - private $sections = []; - - /** - * Add Hooks. - */ - public function init() { - add_action( 'admin_menu', [ $this, 'add_menu' ] ); - add_action( 'admin_init', [ $this, 'setup_settings' ] ); - - $this->active_section = isset( $_GET['section'] ) ? $_GET['section']: 'general'; - } - - /** - * Add settings page. - */ - public function add_menu() { - add_options_page( - __('Antispam Bee', 'antispam-bee' ), - __('Antispam Bee', 'antispam-bee' ), - 'manage_options', - 'antispam_bee', - [ $this, 'options_page' ] - ); - } - - /** - * Setup tabs content. - */ - public function setup_settings() { - // General - $sections[] = new Section( - 'general', - __('General', 'antispam-bee' ), - __('Setup global plugin spam settings.', 'antispam-bee' ), - [ - new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), - new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), - new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), - new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ) - ] - ); - - $this->sections = apply_filters( 'antispam_bee_sections', $sections ); - - // Register option setting - foreach ( $this->sections as $section ) { - if ( $section->get_name() !== $this->active_section ) { - continue; - } - - add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); - - foreach( $section->get_fields() as $field ) { - add_settings_field( - $field->get_name(), - $field->get_label(), - [ $field, 'render' ], - 'antispam_bee', - $section->get_name() - ); - - register_setting( 'antispam_bee', $field->get_name() ); - } - } - } - - /** - * Settings page content. - */ - public function options_page() { - ?> -
+ /** + * Active section + * + * @var string + */ + private $active_section = []; + + /** + * Tabs + * + * @var Section[] + */ + private $sections = []; + + /** + * Add Hooks. + */ + public function init() { + add_action( 'admin_menu', [ $this, 'add_menu' ] ); + add_action( 'admin_init', [ $this, 'setup_settings' ] ); + + $this->active_section = isset( $_GET['section'] ) ? $_GET['section'] : 'general'; + } + + /** + * Add settings page. + */ + public function add_menu() { + add_options_page( + __( 'Antispam Bee', 'antispam-bee' ), + __( 'Antispam Bee', 'antispam-bee' ), + 'manage_options', + 'antispam_bee', + [ $this, 'options_page' ] + ); + } + + /** + * Setup tabs content. + */ + public function setup_settings() { + // General + $sections[] = new Section( + 'general', + __( 'General', 'antispam-bee' ), + __( 'Setup global plugin spam settings.', 'antispam-bee' ), + [ + new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), + new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), + new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), + new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ) + ] + ); + + $this->sections = apply_filters( 'antispam_bee_sections', $sections ); + + // Register option setting + foreach ( $this->sections as $section ) { + if ( $section->get_name() !== $this->active_section ) { + continue; + } + + add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); + + foreach ( $section->get_fields() as $field ) { + add_settings_field( + $field->get_name(), + $field->get_label(), + [ $field, 'render' ], + 'antispam_bee', + $section->get_name() + ); + + register_setting( 'antispam_bee', $field->get_name() ); + } + } + } + + /** + * Settings page content. + */ + public function options_page() { + ?> +

- +
- + - active_section ); ?> - + active_section ); ?> +
- nodeName; - $honeypot_id = $input->attributes->getNamedItem( 'id' )->textContent; - $honeypot_name = $input->attributes->getNamedItem( 'name' )->textContent; + $input_type = $input->nodeName; + $honeypot_id = $input->attributes->getNamedItem( 'id' )->textContent; + $honeypot_name = $input->attributes->getNamedItem( 'name' )->textContent; $attributes_string = sprintf( 'id="%s" name="%s" aria-hidden="true" aria-label="hp-comment" autocomplete="new-password" tabindex="-1" style="padding:0 !important;clip:rect(1px, 1px, 1px, 1px) !important;position:absolute !important;white-space:nowrap !important;height:1px !important;width:1px !important;overflow:hidden !important;"', $honeypot_id, @@ -37,7 +38,7 @@ public static function inject( $markup, $options ) { switch ( $input_type ) { case 'textarea': $item = sprintf( - '', + '', $attributes_string ); @@ -68,7 +69,7 @@ public static function inject( $markup, $options ) { )/x' ); - $markup = preg_replace_callback( $regex, function( $matches ) use ( $honeypot_id, $honeypot_name, $attributes_string ) { + $markup = preg_replace_callback( $regex, function ( $matches ) use ( $honeypot_id, $honeypot_name, $attributes_string ) { $output = ''; $output .= $id_script; + return $output; }, $markup ); break; @@ -107,28 +109,30 @@ public static function inject( $markup, $options ) { /** * Returns the secret of a post used in the textarea id attribute. * - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists - * * @param int $post_id The post ID. * * @return string + * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * */ public static function get_secret_id_for_post() { $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); + return self::ensure_secret_starts_with_letter( $secret ); } /** * Returns the secret of a post used in the textarea name attribute. * - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists - * * @param int $post_id The Post ID. * * @return string + * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * */ public static function get_secret_name_for_post() { $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); + return self::ensure_secret_starts_with_letter( $secret ); } @@ -163,6 +167,7 @@ private static function _is_amp() { private static function get_salt() { $salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : ABSPATH; + return substr( sha1( $salt ), 0, 10 ); } } diff --git a/inc/Handlers/Comment.php b/inc/Handlers/Comment.php index 332c2437..33720088 100644 --- a/inc/Handlers/Comment.php +++ b/inc/Handlers/Comment.php @@ -11,7 +11,7 @@ class Comment { public static function init() { add_action( 'init', - function() { + function () { if ( ! Honeypot::is_active( ItemTypeHelper::COMMENT_TYPE ) ) { return; } @@ -37,6 +37,7 @@ public static function process( $comment ) { if ( empty( $request_path ) ) { PostProcessors::apply( 'comment', $comment, [ 'empty' ] ); + return $comment; } @@ -55,7 +56,7 @@ public static function process( $comment ) { if ( ! isset( $item['asb_marked_as_delete'] ) ) { add_filter( 'pre_comment_approved', - function() { + function () { return 'spam'; } ); diff --git a/inc/Handlers/PostProcessors.php b/inc/Handlers/PostProcessors.php index ec8991fa..0ab10345 100644 --- a/inc/Handlers/PostProcessors.php +++ b/inc/Handlers/PostProcessors.php @@ -8,20 +8,20 @@ class PostProcessors { public static function apply( $type, $item, $reasons = [] ) { $post_processors = self::get( $type, true ); - $item['asb_reasons'] = $reasons; + $item['asb_reasons'] = $reasons; $item['asb_item_type'] = $type; - for ( $i = 0; $i < count( $post_processors ); $i++ ) { - $post_processor = $post_processors[$i]; + for ( $i = 0; $i < count( $post_processors ); $i ++ ) { + $post_processor = $post_processors[ $i ]; $marks_as_delete_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'marks_as_delete' ] : $post_processor['marks_as_delete']; if ( call_user_func( $marks_as_delete_function ) ) { - unset( $post_processors[$i] ); + unset( $post_processors[ $i ] ); array_unshift( $post_processors, $post_processor ); } } foreach ( $post_processors as $post_processor ) { $process_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'process' ] : $post_processor['process']; - $item = call_user_func( $process_function, $item ); + $item = call_user_func( $process_function, $item ); } return $item; @@ -29,14 +29,14 @@ public static function apply( $type, $item, $reasons = [] ) { public static function get( $type = null, $only_active = false ) { $all_post_processors = apply_filters( 'asb_post_processors', [] ); - $post_processors = []; + $post_processors = []; foreach ( $all_post_processors as $key => $post_processor ) { if ( ! self::is_valid_post_processor( $post_processor ) ) { continue; } $supported_types_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'get_supported_types' ] : $post_processor['get_supported_types']; - $supported_types = (array) call_user_func( $supported_types_function, $type ); + $supported_types = (array) call_user_func( $supported_types_function, $type ); if ( ! in_array( $type, $supported_types ) ) { continue; } @@ -47,7 +47,7 @@ public static function get( $type = null, $only_active = false ) { } $is_active_function = isset( $post_processor['post_processor'] ) ? [ $post_processor['post_processor'], 'is_active' ] : $post_processor['is_active']; - $is_active = call_user_func( $is_active_function, $type ); + $is_active = call_user_func( $is_active_function, $type ); if ( ! $is_active ) { continue; diff --git a/inc/Handlers/Rules.php b/inc/Handlers/Rules.php index 72c624b9..cea86b6b 100644 --- a/inc/Handlers/Rules.php +++ b/inc/Handlers/Rules.php @@ -15,13 +15,13 @@ public function __construct( $type ) { public function apply( $item ) { $item['asb_item_type'] = $this->type; - $rules = self::get( $this->type, true ); + $rules = self::get( $this->type, true ); $score = 0.0; foreach ( $rules as $rule ) { - $verify_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'verify' ] : $rule['verify']; + $verify_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'verify' ] : $rule['verify']; $get_weight_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_weight' ] : $rule['get_weight']; - $get_slug_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_slug' ] : $rule['get_slug']; + $get_slug_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_slug' ] : $rule['get_slug']; $rule_score = call_user_func( $verify_function, $item ) * call_user_func( $get_weight_function ); if ( $rule_score > 0.0 ) { @@ -33,7 +33,7 @@ public function apply( $item ) { $score += $rule_score; $no_spam_threshold = (float) apply_filters( 'asb_no_spam_threshold', 0.0 ); - $spam_threshold = (float) apply_filters( 'asb_spam_threshold', 0.0 ); + $spam_threshold = (float) apply_filters( 'asb_spam_threshold', 0.0 ); if ( $no_spam_threshold < 0.0 && $score <= $no_spam_threshold ) { return false; } @@ -54,7 +54,7 @@ public static function get( $type = null, $only_active = false ) { if ( self::is_valid_rule( $rule ) ) { $get_supported_types_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_supported_types' ] : $rule['get_supported_types']; - $supported_types = call_user_func( $get_supported_types_function ); + $supported_types = call_user_func( $get_supported_types_function ); if ( ! in_array( $type, $supported_types ) ) { continue; @@ -66,7 +66,7 @@ public static function get( $type = null, $only_active = false ) { } $is_active_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'is_active' ] : $rule['is_active']; - $is_active = call_user_func( $is_active_function, $type ); + $is_active = call_user_func( $is_active_function, $type ); if ( ! $is_active ) { continue; diff --git a/inc/Interfaces/Controllable.php b/inc/Interfaces/Controllable.php index b45b0f14..f15b18bf 100644 --- a/inc/Interfaces/Controllable.php +++ b/inc/Interfaces/Controllable.php @@ -4,6 +4,7 @@ interface Controllable { public static function get_label(); + public static function get_description(); /** @@ -13,15 +14,15 @@ public static function get_description(); * [ * [ * 'type' => 'textarea|radio|checkbox|input|select|callable', - * 'input_type' => 'email|password|number...', - * 'option_name' => 'asb_deny_langcodes', - * 'options' => [ 'Option A', 'Option B' ], - * 'multiple' => true, - * 'placeholder' => 'My placeholder text', - * 'default' => 'Default value', - * 'sanitize' => callable, - * 'persist' => callable, - * 'load' => callable, + * 'input_type' => 'email|password|number...', + * 'option_name' => 'asb_deny_langcodes', + * 'options' => [ 'Option A', 'Option B' ], + * 'multiple' => true, + * 'placeholder' => 'My placeholder text', + * 'default' => 'Default value', + * 'sanitize' => callable, + * 'persist' => callable, + * 'load' => callable, * ] * ] * @return mixed diff --git a/inc/PostProcessors/InitPostProcessor.php b/inc/PostProcessors/InitPostProcessor.php index dbf28dd2..0ea0c1fc 100644 --- a/inc/PostProcessors/InitPostProcessor.php +++ b/inc/PostProcessors/InitPostProcessor.php @@ -4,7 +4,7 @@ trait InitPostProcessor { public static function init() { - add_filter( 'asb_post_processors', function( $post_processors ) { + add_filter( 'asb_post_processors', function ( $post_processors ) { $post_processors[] = [ 'post_processor' => self::class ]; diff --git a/inc/PostProcessors/SaveReason.php b/inc/PostProcessors/SaveReason.php index ae87d422..96e7dd70 100644 --- a/inc/PostProcessors/SaveReason.php +++ b/inc/PostProcessors/SaveReason.php @@ -22,7 +22,7 @@ public static function process( $item ) { add_action( 'comment_post', - function( $comment_id ) use ( $item ) { + function ( $comment_id ) use ( $item ) { add_comment_meta( $comment_id, 'antispam_bee_reason', @@ -30,6 +30,7 @@ function( $comment_id ) use ( $item ) { ); } ); + return $item; } diff --git a/inc/PostProcessors/SendEmail.php b/inc/PostProcessors/SendEmail.php index a19611c0..d816f3f3 100644 --- a/inc/PostProcessors/SendEmail.php +++ b/inc/PostProcessors/SendEmail.php @@ -58,64 +58,64 @@ function ( $id ) use ( $item ) { // Body. $body = sprintf( - "%s \"%s\"\r\n\r\n", - esc_html__( 'New spam comment on your post', 'antispam-bee' ), - strip_tags( $post->post_title ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Author', 'antispam-bee' ), - ( empty( $comment['comment_author'] ) ? '' : strip_tags( $comment['comment_author'] ) ) - ) . sprintf( - "URL: %s\r\n", - // empty check exists. - esc_url( $comment['comment_author_url'] ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Type', 'antispam-bee' ), - esc_html( $comment_name ) - ) . sprintf( - "Whois: http://whois.arin.net/rest/ip/%s\r\n", - $comment['comment_author_IP'] - ) . sprintf( - "%s: %s\r\n\r\n", - esc_html__( 'Spam Reason', 'antispam-bee' ), - esc_html( implode( ',', $item[ 'asb_reasons' ] ) ) - ) . sprintf( - "%s\r\n\r\n\r\n", - $content - ) . ( - EMPTY_TRASH_DAYS ? ( - sprintf( - "%s: %s\r\n", - esc_html__( 'Trash it', 'antispam-bee' ), - admin_url( 'comment.php?action=trash&c=' . $id ) - ) - ) : ( - sprintf( - "%s: %s\r\n", - esc_html__( 'Delete it', 'antispam-bee' ), - admin_url( 'comment.php?action=delete&c=' . $id ) - ) - ) - ) . sprintf( - "%s: %s\r\n", - esc_html__( 'Approve it', 'antispam-bee' ), - admin_url( 'comment.php?action=approve&c=' . $id ) - ) . sprintf( - "%s: %s\r\n\r\n", - esc_html__( 'Spam list', 'antispam-bee' ), - admin_url( 'edit-comments.php?comment_status=spam' ) - ) . sprintf( - "%s\r\n%s\r\n", - esc_html__( 'Notify message by Antispam Bee', 'antispam-bee' ), - esc_html__( 'https://antispambee.pluginkollektiv.org/', 'antispam-bee' ) - ); + "%s \"%s\"\r\n\r\n", + esc_html__( 'New spam comment on your post', 'antispam-bee' ), + strip_tags( $post->post_title ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Author', 'antispam-bee' ), + ( empty( $comment['comment_author'] ) ? '' : strip_tags( $comment['comment_author'] ) ) + ) . sprintf( + "URL: %s\r\n", + // empty check exists. + esc_url( $comment['comment_author_url'] ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Type', 'antispam-bee' ), + esc_html( $comment_name ) + ) . sprintf( + "Whois: http://whois.arin.net/rest/ip/%s\r\n", + $comment['comment_author_IP'] + ) . sprintf( + "%s: %s\r\n\r\n", + esc_html__( 'Spam Reason', 'antispam-bee' ), + esc_html( implode( ',', $item['asb_reasons'] ) ) + ) . sprintf( + "%s\r\n\r\n\r\n", + $content + ) . ( + EMPTY_TRASH_DAYS ? ( + sprintf( + "%s: %s\r\n", + esc_html__( 'Trash it', 'antispam-bee' ), + admin_url( 'comment.php?action=trash&c=' . $id ) + ) + ) : ( + sprintf( + "%s: %s\r\n", + esc_html__( 'Delete it', 'antispam-bee' ), + admin_url( 'comment.php?action=delete&c=' . $id ) + ) + ) + ) . sprintf( + "%s: %s\r\n", + esc_html__( 'Approve it', 'antispam-bee' ), + admin_url( 'comment.php?action=approve&c=' . $id ) + ) . sprintf( + "%s: %s\r\n\r\n", + esc_html__( 'Spam list', 'antispam-bee' ), + admin_url( 'edit-comments.php?comment_status=spam' ) + ) . sprintf( + "%s\r\n%s\r\n", + esc_html__( 'Notify message by Antispam Bee', 'antispam-bee' ), + esc_html__( 'https://antispambee.pluginkollektiv.org/', 'antispam-bee' ) + ); wp_mail( /** * Filters the recipients of the spam notification. * - * @param array The recipients array. + * @param array The recipients array. */ apply_filters( 'antispam_bee_notification_recipients', @@ -124,7 +124,7 @@ function ( $id ) use ( $item ) { /** * Filters the subject of the spam notification. * - * @param string $subject subject line. + * @param string $subject subject line. */ apply_filters( 'antispam_bee_notification_subject', diff --git a/inc/PostProcessors/UpdateDailyStats.php b/inc/PostProcessors/UpdateDailyStats.php index 98e5f51e..9e31dab1 100644 --- a/inc/PostProcessors/UpdateDailyStats.php +++ b/inc/PostProcessors/UpdateDailyStats.php @@ -3,7 +3,6 @@ namespace AntispamBee\PostProcessors; use AntispamBee\Helpers\ItemTypeHelper; -use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\PostProcessor; use AntispamBee\Settings; diff --git a/inc/PostProcessors/UpdateSpamCount.php b/inc/PostProcessors/UpdateSpamCount.php index d6dca1a1..d942d9ba 100644 --- a/inc/PostProcessors/UpdateSpamCount.php +++ b/inc/PostProcessors/UpdateSpamCount.php @@ -3,7 +3,6 @@ namespace AntispamBee\PostProcessors; use AntispamBee\Helpers\ItemTypeHelper; -use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\PostProcessor; use AntispamBee\Settings; diff --git a/inc/PostProcessors/UpdateSpamLog.php b/inc/PostProcessors/UpdateSpamLog.php index 1c57d5b8..c241571b 100644 --- a/inc/PostProcessors/UpdateSpamLog.php +++ b/inc/PostProcessors/UpdateSpamLog.php @@ -3,7 +3,6 @@ namespace AntispamBee\PostProcessors; use AntispamBee\Helpers\ItemTypeHelper; -use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\PostProcessor; class UpdateSpamLog implements PostProcessor { diff --git a/inc/Rules/ApprovedEmail.php b/inc/Rules/ApprovedEmail.php index 8cd89193..e2cbc008 100644 --- a/inc/Rules/ApprovedEmail.php +++ b/inc/Rules/ApprovedEmail.php @@ -21,8 +21,8 @@ public static function verify( $data ) { $email = array_shift( $email ); $approved_comments_count = get_comments( [ - 'status' => 'approve', - 'count' => true, + 'status' => 'approve', + 'count' => true, 'author_email' => $email, ] ); @@ -30,7 +30,7 @@ public static function verify( $data ) { return 0; } - return -1; + return - 1; } public static function get_name() { diff --git a/inc/Rules/BBCode.php b/inc/Rules/BBCode.php index d2dfcab5..6f7a92bc 100644 --- a/inc/Rules/BBCode.php +++ b/inc/Rules/BBCode.php @@ -17,6 +17,7 @@ public static function verify( $data ) { return 1; } } + return 0; } diff --git a/inc/Rules/Controllable.php b/inc/Rules/Controllable.php index 1fb56769..8cabf8a8 100644 --- a/inc/Rules/Controllable.php +++ b/inc/Rules/Controllable.php @@ -4,6 +4,7 @@ interface Controllable { public static function get_label(); + public static function get_description(); /** @@ -13,15 +14,15 @@ public static function get_description(); * [ * [ * 'type' => 'textarea|radio|checkbox|input|select|callable', - * 'input_type' => 'email|password|number...', - * 'option_name' => 'asb_deny_langcodes', - * 'options' => [ 'Option A', 'Option B' ], - * 'multiple' => true, - * 'placeholder' => 'My placeholder text', - * 'default' => 'Default value', - * 'sanitize' => callable, - * 'persist' => callable, - * 'load' => callable, + * 'input_type' => 'email|password|number...', + * 'option_name' => 'asb_deny_langcodes', + * 'options' => [ 'Option A', 'Option B' ], + * 'multiple' => true, + * 'placeholder' => 'My placeholder text', + * 'default' => 'Default value', + * 'sanitize' => callable, + * 'persist' => callable, + * 'load' => callable, * ] * ] * @return mixed diff --git a/inc/Rules/CountrySpam.php b/inc/Rules/CountrySpam.php index 8ea2bf8c..23658435 100644 --- a/inc/Rules/CountrySpam.php +++ b/inc/Rules/CountrySpam.php @@ -22,13 +22,13 @@ public static function verify( $data ) { $allowed = preg_split( '/[\s,;]+/', $options['country_allowed'], - -1, + - 1, PREG_SPLIT_NO_EMPTY ); - $denied = preg_split( + $denied = preg_split( '/[\s,;]+/', $options['country_denied'], - -1, + - 1, PREG_SPLIT_NO_EMPTY ); @@ -39,14 +39,14 @@ public static function verify( $data ) { /** * Filter to hook into the `Country_Spam::verify` functionality, to implement for example a custom IP check. * - * @since 2.10.0 - * * @param null $is_country_spam The `is_country_spam` result. * @param string $ip The IP address. * @param array $allowed The list of allowed country codes. * @param array $denied The list of denied country codes. * * @return null|boolean The `is_country_spam` result or null. + * @since 2.10.0 + * */ $is_country_spam = apply_filters( 'antispam_bee_is_country_spam', null, $ip, $allowed, $denied ); @@ -57,11 +57,11 @@ public static function verify( $data ) { /** * Filters the IPLocate API key. With this filter, you can add your own IPLocate API key. * - * @since 2.10.0 - * * @param string The current IPLocate API key. Default is `null`. * * @return string The changed IPLocate API key or null. + * @since 2.10.0 + * */ $apikey = apply_filters( 'antispam_bee_country_spam_apikey', '' ); @@ -127,6 +127,7 @@ public static function get_description() { 'https' ) ); + return sprintf( /* translators: 1: opening tag with link to documentation. 2: closing tag. */ esc_html__( 'Filtering the requests depending on country. Please note the %1$sprivacy notice%2$s for this option.', diff --git a/inc/Rules/DbSpam.php b/inc/Rules/DbSpam.php index fdcf6825..ec6bd374 100644 --- a/inc/Rules/DbSpam.php +++ b/inc/Rules/DbSpam.php @@ -15,7 +15,7 @@ class DbSpam implements Verifiable, Controllable { public static function verify( $data ) { $params = []; $filter = []; - $url = DataHelper::get_values_where_key_contains( [ 'url' ], $data ); + $url = DataHelper::get_values_where_key_contains( [ 'url' ], $data ); if ( ! empty( $url ) ) { $filter[] = '`comment_author_url` = %s'; diff --git a/inc/Rules/Honeypot.php b/inc/Rules/Honeypot.php index 6ff955b1..d5284581 100644 --- a/inc/Rules/Honeypot.php +++ b/inc/Rules/Honeypot.php @@ -18,7 +18,8 @@ public static function verify( $data ) { if ( isset( $_POST['ab_spam__hidden_field'] ) && $_POST['ab_spam__hidden_field'] == 1 ) { return 1; } - return -1; + + return - 1; } public static function precheck() { @@ -43,10 +44,10 @@ public static function precheck() { $fields['plugin_field'] = $key; } } - if ( ! empty( $_POST[$fields['hidden_field']] ) ) { + if ( ! empty( $_POST[ $fields['hidden_field'] ] ) ) { $_POST['ab_spam__hidden_field'] = 1; } else { - $_POST[$fields['hidden_field']] = $_POST[$fields['plugin_field']]; + $_POST[ $fields['hidden_field'] ] = $_POST[ $fields['plugin_field'] ]; unset( $_POST[ HoneypotField::get_secret_name_for_post() ] ); } // phpcs:enable WordPress.Security.NonceVerification.Missing diff --git a/inc/Rules/InitRule.php b/inc/Rules/InitRule.php index eb581352..0c639a07 100644 --- a/inc/Rules/InitRule.php +++ b/inc/Rules/InitRule.php @@ -4,7 +4,7 @@ trait InitRule { public static function init() { - add_filter( 'asb_rules', function( $rules ) { + add_filter( 'asb_rules', function ( $rules ) { $rules[] = [ 'verifiable' => self::class, ]; diff --git a/inc/Rules/IsActive.php b/inc/Rules/IsActive.php index 3e23328c..62bbce1e 100644 --- a/inc/Rules/IsActive.php +++ b/inc/Rules/IsActive.php @@ -7,7 +7,7 @@ trait IsActive { public static function is_active( $type ) { return true; - + return Settings::get_option( $type . '_' . self::get_slug() . '_active' ); } } diff --git a/inc/Rules/LangSpam.php b/inc/Rules/LangSpam.php index 800dcc44..aa539b9b 100644 --- a/inc/Rules/LangSpam.php +++ b/inc/Rules/LangSpam.php @@ -7,7 +7,6 @@ use AntispamBee\Helpers\LangHelper; use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\Verifiable; -use AntispamBee\Settings; class LangSpam implements Verifiable, Controllable { @@ -20,7 +19,7 @@ public static function verify( $data ) { return 0; } $comment_content = array_shift( $comment_content ); - $comment_text = wp_strip_all_tags( $comment_content ); + $comment_text = wp_strip_all_tags( $comment_content ); if ( empty( $allowed_lang ) || empty( $comment_text ) ) { return 0; @@ -29,8 +28,8 @@ public static function verify( $data ) { /** * Filters the detected language. With this filter, other detection methods can skip in and detect the language. * - * @param null $detected_lang The detected language. - * @param string $comment_text The text, to detect the language. + * @param null $detected_lang The detected language. + * @param string $comment_text The text, to detect the language. * * @return null|string The detected language or null. * @since 2.8.2 @@ -71,7 +70,7 @@ public static function verify( $data ) { ); if ( is_wp_error( $response ) - || wp_remote_retrieve_response_code( $response ) !== 200 ) { + || wp_remote_retrieve_response_code( $response ) !== 200 ) { return 0; } @@ -85,7 +84,7 @@ public static function verify( $data ) { return 0; } - return (int) ! in_array( LangHelper::map ( $detected_lang->code ), $allowed_lang, true ); + return (int) ! in_array( LangHelper::map( $detected_lang->code ), $allowed_lang, true ); } public static function get_name() { diff --git a/inc/Rules/RegexpSpam.php b/inc/Rules/RegexpSpam.php index f912d114..06e081c1 100644 --- a/inc/Rules/RegexpSpam.php +++ b/inc/Rules/RegexpSpam.php @@ -34,7 +34,7 @@ public static function verify( $data ) { $email = $data['comment_author_email']; $author = $data['comment_author']; $useragent = $data['comment_agent']; - $item = array( + $item = array( 'ip' => $ip, 'rawurl' => $url, 'host' => DataHelper::parse_url( $url, 'host' ), @@ -52,7 +52,7 @@ public static function verify( $data ) { $post_id = $data['comment_post_ID']; $type = $data['comment_type']; $blog_name = $data['comment_author']; - $item = [ + $item = [ 'ip' => $ip, 'rawurl' => $url, 'host' => DataHelper::parse_url( $url, 'host' ), diff --git a/inc/Rules/TrackbackFromMyself.php b/inc/Rules/TrackbackFromMyself.php index 661e3ebd..072add3d 100644 --- a/inc/Rules/TrackbackFromMyself.php +++ b/inc/Rules/TrackbackFromMyself.php @@ -11,39 +11,40 @@ class TrackbackFromMyself implements Verifiable { use IsActive; public static function verify( $data ) { - $url = isset( $data['comment_author_url'] ) ? $data['comment_author_url'] : null; + $url = isset( $data['comment_author_url'] ) ? $data['comment_author_url'] : null; $target_post_id = isset( $data['comment_post_ID'] ) ? $data['comment_post_ID'] : null; if ( empty( $url ) || empty( $target_post_id ) ) { return 0; } - $url = $url[0]; + $url = $url[0]; $target_post_id = $target_post_id[0]; if ( 0 !== strpos( $url, home_url() ) ) { - return -1; + return - 1; } $original_post_id = (int) url_to_postid( $url ); if ( ! $original_post_id ) { - return -1; + return - 1; } $post = get_post( $original_post_id ); if ( ! $post ) { - return -1; + return - 1; } $urls = wp_extract_urls( $post->post_content ); $url_to_find = get_permalink( $target_post_id ); if ( ! $url_to_find ) { - return -1; + return - 1; } foreach ( $urls as $url ) { if ( strpos( $url, $url_to_find ) === 0 ) { return 1; } } - return -1; + + return - 1; } public static function get_name() { diff --git a/inc/Rules/TrackbackPostTitleIsBlogName.php b/inc/Rules/TrackbackPostTitleIsBlogName.php index e03bfc6b..122b4e97 100644 --- a/inc/Rules/TrackbackPostTitleIsBlogName.php +++ b/inc/Rules/TrackbackPostTitleIsBlogName.php @@ -11,13 +11,14 @@ class TrackbackPostTitleIsBlogName implements Verifiable { use IsActive; public static function verify( $data ) { - $body = isset( $data['comment_content'] ) ? $data['comment_content'] : null; + $body = isset( $data['comment_content'] ) ? $data['comment_content'] : null; $blog_name = isset( $data['comment_author'] ) ? $data['comment_author'] : null; preg_match( '/(.*)<\/strong>\\n\\n/', $body, $matches ); if ( ! isset( $matches[1] ) ) { - return -1; + return - 1; } - return trim( $matches[1] ) === trim( $blog_name ) ? 1 : -1; + + return trim( $matches[1] ) === trim( $blog_name ) ? 1 : - 1; } public static function get_name() { diff --git a/inc/Settings.php b/inc/Settings.php index d601beae..aec056e6 100644 --- a/inc/Settings.php +++ b/inc/Settings.php @@ -3,10 +3,10 @@ namespace AntispamBee; use AntispamBee\Rules\Controllable; -use AntispamBee\Rules\Verifiable; class Settings { protected static $defaults; + public static function init() { self::init_options(); add_action( @@ -21,36 +21,36 @@ public static function init() { protected static function init_options() { self::$defaults = array( 'options' => array( - 'regexp_check' => 1, - 'spam_ip' => 1, - 'already_commented' => 1, - 'gravatar_check' => 0, - 'time_check' => 0, - 'ignore_pings' => 0, + 'regexp_check' => 1, + 'spam_ip' => 1, + 'already_commented' => 1, + 'gravatar_check' => 0, + 'time_check' => 0, + 'ignore_pings' => 0, - 'dashboard_chart' => 0, - 'dashboard_count' => 0, + 'dashboard_chart' => 0, + 'dashboard_count' => 0, - 'country_code' => 0, - 'country_denied' => '', - 'country_allowed' => '', + 'country_code' => 0, + 'country_denied' => '', + 'country_allowed' => '', - 'translate_api' => 0, - 'translate_lang' => array(), + 'translate_api' => 0, + 'translate_lang' => array(), - 'bbcode_check' => 1, + 'bbcode_check' => 1, - 'flag_spam' => 1, - 'email_notify' => 0, - 'no_notice' => 0, - 'cronjob_enable' => 0, - 'cronjob_interval' => 0, + 'flag_spam' => 1, + 'email_notify' => 0, + 'no_notice' => 0, + 'cronjob_enable' => 0, + 'cronjob_interval' => 0, - 'ignore_filter' => 0, - 'ignore_type' => 0, + 'ignore_filter' => 0, + 'ignore_type' => 0, - 'reasons_enable' => 0, - 'ignore_reasons' => array(), + 'reasons_enable' => 0, + 'ignore_reasons' => array(), 'delete_data_on_uninstall' => 1, ), @@ -91,7 +91,7 @@ public static function options_page() {
- + #dashboard_right_now .ab-count:before {content: "\f117"}'; + + $items[] = '' . esc_html( + sprintf( + // translators: The number of spam comments Antispam Bee blocked so far. + __( '%s Blocked', 'antispam-bee' ), + StatsHelpers::get_spam_count() + ) + ) . ''; + + return $items; + } + + /** + * Initialize the dashboard chart + * + * @since 1.9 + * @since 2.5.6 + */ + public function add_dashboard_chart() { + if ( ! current_user_can( 'publish_posts' ) || ! OptionsHelper::get_option( 'dashboard_chart' ) ) { + return; + } + + wp_add_dashboard_widget( + 'ab_widget', + 'Antispam Bee', + [ $this, 'show_spam_chart' ] + ); + } + + /** + * Print dashboard html + * + * @since 1.9.0 + * @since 2.5.8 + */ + public function show_spam_chart() { + $items = (array) OptionsHelper::get_option( 'daily_stats' ); + + if ( empty( $items ) ) { + echo sprintf( + '

%s

', + esc_html__( 'No data available.', 'antispam-bee' ) + ); + + return; + } + + ksort( $items, SORT_NUMERIC ); + + $html = "\n"; + + $html .= "\n"; + foreach ( $items as $date => $count ) { + $html .= '\n"; + } + $html .= "\n"; + + $html .= "\n"; + foreach ( $items as $date => $count ) { + $html .= '\n"; + } + $html .= "\n"; + + $html .= "
' . date_i18n( 'j. F Y', $date ) . "
' . (int) $count . "
\n"; + + echo wp_kses_post( '
' . $html . '
' ); + } +} diff --git a/lib/Admin/OptionsPage.php b/lib/Admin/OptionsPage.php index 1c8fcddc..971c4cbd 100644 --- a/lib/Admin/OptionsPage.php +++ b/lib/Admin/OptionsPage.php @@ -44,7 +44,7 @@ public function add_sidebar_menu() { * @since 1.6 * @since 2.4 */ - public static function add_options_script() { + public function add_options_script() { // @todo: maybe load some more scripts. } @@ -55,7 +55,7 @@ public static function add_options_script() { * @since 1.6 * @since 2.4 */ - public static function add_options_style() { + public function add_options_style() { // @todo: maybe load some more styles. } @@ -63,7 +63,7 @@ public static function add_options_style() { /** * Display the GUI. */ - public static function options_page() { + public function options_page() { // @todo: use new options UI. } } diff --git a/lib/Helpers/AssetsLoader.php b/lib/Helpers/AssetsLoader.php index d1727754..0fcffe28 100644 --- a/lib/Helpers/AssetsLoader.php +++ b/lib/Helpers/AssetsLoader.php @@ -71,6 +71,47 @@ public function register_assets() { public function admin_enqueue_scripts() { wp_enqueue_script( 'antispam-bee-backend' ); wp_enqueue_style( 'antispam-bee-backend' ); + + // Adding legacy scripts. + $this->add_dashboard_script(); + } + + /** + * Print dashboard scripts + * + * @since 1.9.0 + * @since 2.5.8 + */ + public function add_dashboard_script() { + if ( ! OptionsHelper::get_option( 'daily_stats' ) ) { + return; + } + + $plugin = get_plugin_data( ANTISPAM_BEE_FILE ); + + wp_enqueue_script( + 'raphael', + plugins_url( 'src/legacy/raphael.min.js', ANTISPAM_BEE_FILE ), + [], + '2.1.0', + true + ); + + wp_enqueue_script( + 'ab-raphael', + plugins_url( 'src/legacy/raphael.helper.js', ANTISPAM_BEE_FILE ), + [ 'raphael' ], + $plugin['Version'], + true + ); + + wp_enqueue_script( + 'ab_chart_js', + plugins_url( 'src/legacy/dashboard.js', ANTISPAM_BEE_FILE ), + array( 'jquery', 'ab-raphael' ), + $plugin['Version'], + true + ); } /** diff --git a/lib/Helpers/StatsHelpers.php b/lib/Helpers/StatsHelpers.php new file mode 100644 index 00000000..0f5e1922 --- /dev/null +++ b/lib/Helpers/StatsHelpers.php @@ -0,0 +1,85 @@ +get_spam_count() ); + } + + /** + * Update the number of spam comments + * + * @since 0.1 + * @since 2.6.1 + */ + public function update_spam_count() { + if ( ! OptionsHelper::get_option( 'dashboard_count' ) ) { + return; + } + + OptionsHelper::update_option( + 'spam_count', + intval( OptionsHelper::get_option( 'spam_count' ) + 1 ) + ); + } + + /** + * Update statistics + * + * @since 1.9 + * @since 2.6.1 + */ + public function update_daily_stats() { + if ( ! OptionsHelper::get_option( 'dashboard_chart' ) ) { + return; + } + + $stats = (array) OptionsHelper::get_option( 'daily_stats' ); + $today = (int) strtotime( 'today' ); + + if ( array_key_exists( $today, $stats ) ) { + $stats[ $today ] ++; + } else { + $stats[ $today ] = 1; + } + + krsort( $stats, SORT_NUMERIC ); + + OptionsHelper::update_option( + 'daily_stats', + array_slice( $stats, 0, 31, true ) + ); + } +} diff --git a/lib/load.php b/lib/load.php index 31b968af..4211593c 100644 --- a/lib/load.php +++ b/lib/load.php @@ -7,6 +7,7 @@ namespace AntispamBee; +use AntispamBee\Admin\DashboardWidgets; use AntispamBee\Admin\SettingsPage; use AntispamBee\Fields\Honeypot as HoneypotField; use AntispamBee\Rules\Honeypot as HoneypotRule; @@ -33,6 +34,7 @@ use AntispamBee\Helpers\CommentsColumns; use AntispamBee\Helpers\Installer; use AntispamBee\Helpers\OptionsHelper; +use AntispamBee\Helpers\StatsHelpers; /** * Init function of the plugin @@ -40,30 +42,32 @@ function init() { // Construct all modules to initialize. $modules = [ - 'helpers_assets_loader' => new AssetsLoader(), - 'settings_page' => new SettingsPage(), - 'helpers_comments_columns' => new CommentsColumns(), - 'approved_email_rule' => ApprovedEmail::class, - 'bbcode_rule' => BBCode::class, - 'country_spam_rule' => CountrySpam::class, - 'db_spam_rule' => DbSpam::class, - 'lang_spam_rule' => LangSpam::class, - 'regexp_spam_rule' => RegexpSpam::class, - 'shortest_time_rule' => ShortestTime::class, - 'trackback_from_myself_rule' => TrackbackFromMyself::class, + 'helpers_assets_loader' => new AssetsLoader(), + 'settings_page' => new SettingsPage(), + 'helpers_comments_columns' => new CommentsColumns(), + 'approved_email_rule' => ApprovedEmail::class, + 'bbcode_rule' => BBCode::class, + 'country_spam_rule' => CountrySpam::class, + 'db_spam_rule' => DbSpam::class, + 'lang_spam_rule' => LangSpam::class, + 'regexp_spam_rule' => RegexpSpam::class, + 'shortest_time_rule' => ShortestTime::class, + 'trackback_from_myself_rule' => TrackbackFromMyself::class, 'trackback_post_title_is_blog_name_rule' => TrackbackPostTitleIsBlogName::class, - 'valid_gravatar_rule' => ValidGravatar::class, - 'honeypot_rule' => HoneypotRule::class, - 'delete_post_processor' => Delete::class, - 'delete_for_reasons_post_processor' => DeleteForReasons::class, - 'save_reason_post_processor' => SaveReason::class, - 'send_email_post_processor' => SendEmail::class, - 'update_daily_stats_post_processor' => UpdateDailyStats::class, - 'update_spam_count_post_processor' => UpdateSpamCount::class, - 'update_spam_log_post_processor' => UpdateSpamLog::class, - 'comment_handler' => Comment::class, - 'trackback_handler' => Trackback::class, - 'helpers_options_helper' => new OptionsHelper(), + 'valid_gravatar_rule' => ValidGravatar::class, + 'honeypot_rule' => HoneypotRule::class, + 'delete_post_processor' => Delete::class, + 'delete_for_reasons_post_processor' => DeleteForReasons::class, + 'save_reason_post_processor' => SaveReason::class, + 'send_email_post_processor' => SendEmail::class, + 'update_daily_stats_post_processor' => UpdateDailyStats::class, + 'update_spam_count_post_processor' => UpdateSpamCount::class, + 'update_spam_log_post_processor' => UpdateSpamLog::class, + 'comment_handler' => Comment::class, + 'trackback_handler' => Trackback::class, + 'helpers_options_helper' => new OptionsHelper(), + 'helpers_dashboard_helper' => new DashboardWidgets(), + 'helpers_stats_helpers' => new StatsHelpers(), ]; // Initialize all modules. @@ -75,7 +79,7 @@ function init() { add_filter( 'comment_form_field_comment', - function( $field_markup ) { + function ( $field_markup ) { return HoneypotField::inject( $field_markup, [ 'field_id' => 'comment' ] ); } ); diff --git a/package.json b/package.json index afb14d77..d44971cd 100644 --- a/package.json +++ b/package.json @@ -29,5 +29,8 @@ "classnames": "^2.3.1", "svg-spritemap-webpack-plugin": "^4.3.3", "url-loader": "^4.1.1" + }, + "dependencies": { + "raphael": "^2.3.0" } } diff --git a/src/legacy/dashboard.js b/src/legacy/dashboard.js new file mode 100644 index 00000000..94d1783e --- /dev/null +++ b/src/legacy/dashboard.js @@ -0,0 +1,112 @@ +( function() { + // Grab the data + var labels = [], + data = []; + jQuery( '#ab_chart_data tfoot th' ).each( function() { + labels.push( jQuery( this ).text() ); + } ); + jQuery( '#ab_chart_data tbody td' ).each( function() { + data.push( jQuery( this ).text() ); + } ); + + // Draw + var width = jQuery( '#ab_chart' ).parent().width() + 8, + height = 140, + leftgutter = 0, + bottomgutter = 22, + topgutter = 22, + color = '#135e96', + r = Raphael( 'ab_chart', width, height ), + txt = { font: 'bold 12px "Open Sans", sans-serif', fill: '#1d2327' }, + X = ( width - leftgutter * 2 ) / labels.length, + max = Math.max.apply( Math, data ), + Y = ( height - bottomgutter - topgutter ) / max; + + // Max value + r + .text( 16, 16, max ) + .attr( + { + font: 'normal 10px "Open Sans", sans-serif', + fill: '#a7aaad', + } + ); + + var path = r.path().attr( { stroke: color, 'stroke-width': 2, 'stroke-linejoin': 'round' } ), + bgp = r.path().attr( { stroke: 'none', opacity: .3, fill: color } ), + label = r.set(), + lx = 0, + ly = 0, + is_label_visible = false, + leave_timer, + blanket = r.set(); + label.push( r.text( 60, 12, '' ).attr( txt ) ); + label.push( r.text( 60, 27, '' ).attr( txt ).attr( { fill: color } ) ); + label.hide(); + var frame = r.popup( 100, 100, label, 'right' ).attr( { fill: '#fff', stroke: '#444', 'stroke-width': 1 } ).hide(); + + var p, bgpp; + for ( var i = 0, ii = labels.length; i < ii; i++ ) { + var y = Math.round( height - bottomgutter - Y * data[i] ), + x = Math.round( leftgutter + X * ( i + .5 ) ); + if ( ! i ) { + p = [ 'M', x, y, 'C', x, y ]; + bgpp = [ 'M', leftgutter + X * .5, height - bottomgutter, 'L', x, y, 'C', x, y ]; + } + if ( i && i < ii - 1 ) { + var Y0 = Math.round( height - bottomgutter - Y * data[i - 1] ), + X0 = Math.round( leftgutter + X * ( i - .5 ) ), + Y2 = Math.round( height - bottomgutter - Y * data[i + 1] ), + X2 = Math.round( leftgutter + X * ( i + 1.5 ) ); + var a = getAnchors( X0, Y0, x, y, X2, Y2 ); + p = p.concat( [ a.x1, a.y1, x, y, a.x2, a.y2 ] ); + bgpp = bgpp.concat( [ a.x1, a.y1, x, y, a.x2, a.y2 ] ); + } + var dot = r.circle( x, y, 4 ).attr( { fill: '#fff', stroke: color, 'stroke-width': 1 } ); + blanket.push( r.rect( leftgutter + X * i, 0, X, height - bottomgutter ).attr( { stroke: 'none', fill: '#fff', opacity: .2 } ) ); + var rect = blanket[blanket.length - 1]; + ( function( x, y, data, date, dot ) { + var timer, + i = 0; + rect.hover( function() { + clearTimeout( leave_timer ); + var side = 'right'; + if ( x + frame.getBBox().width > width ) { + side = 'left'; + } + // set label content to determine correct dimensions + label[0].attr( { text: date } ); + label[1].attr( { text: data + '× Spam' } ); + var ppp = r.popup( x, y, label, side, 1 ), + anim = Raphael.animation( { + path: ppp.path, + transform: [ 't', ppp.dx, ppp.dy ], + }, 200 * is_label_visible ); + lx = label[0].transform()[0][1] + ppp.dx; + ly = label[0].transform()[0][2] + ppp.dy; + frame.show().stop().animate( anim ); + + label[0].show().stop().animateWith( frame, anim, { transform: [ 't', lx, ly ] }, 200 * is_label_visible ); + label[1].show().stop().animateWith( frame, anim, { transform: [ 't', lx, ly ] }, 200 * is_label_visible ); + dot.attr( 'r', 6 ); + is_label_visible = true; + }, function() { + dot.attr( 'r', 4 ); + leave_timer = setTimeout( function() { + frame.hide(); + label[0].hide(); + label[1].hide(); + is_label_visible = false; + }, 1 ); + } ); + }( x, y, data[i], labels[i], dot ) ); + } + p = p.concat( [ x, y, x, y ] ); + bgpp = bgpp.concat( [ x, y, x, y, 'L', x, height - bottomgutter, 'z' ] ); + path.attr( { path: p } ); + bgp.attr( { path: bgpp } ); + frame.toFront(); + label[0].toFront(); + label[1].toFront(); + blanket.toFront(); +}() ); diff --git a/src/legacy/raphael.helper.js b/src/legacy/raphael.helper.js new file mode 100644 index 00000000..b7a066d3 --- /dev/null +++ b/src/legacy/raphael.helper.js @@ -0,0 +1,140 @@ +var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, + replacer = function( all, key, obj ) { + var res = obj; + key.replace( objNotationRegex, function( all, name, quote, quotedName, isFunc ) { + name = name || quotedName; + if ( res ) { + if ( name in res ) { + res = res[name]; + } + typeof res === 'function' && isFunc && ( res = res() ); + } + } ); + res = ( res == null || res == obj ? all : res ) + ''; + return res; + }, + fill = function( str, obj ) { + return String( str ).replace( tokenRegex, function( all, key ) { + return replacer( all, key, obj ); + } ); + }; + +Raphael.fn.popup = function( X, Y, set, pos, ret ) { + pos = String( pos || 'top-middle' ).split( '-' ); + pos[1] = pos[1] || 'middle'; + var r = 5, + bb = set.getBBox(), + w = Math.round( bb.width ), + h = Math.round( bb.height ), + x = Math.round( bb.x ) - r, + y = Math.round( bb.y ) - r, + gap = Math.min( h / 2, w / 2, 10 ), + shapes = { + top: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}l-{right},0-{gap},{gap}-{gap}-{gap}-{left},0a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', + bottom: 'M{x},{y}l{left},0,{gap}-{gap},{gap},{gap},{right},0a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', + right: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}l0-{bottom}-{gap}-{gap},{gap}-{gap},0-{top}a{r},{r},0,0,1,{r}-{r}z', + left: 'M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}l0,{top},{gap},{gap}-{gap},{gap},0,{bottom}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z', + }, + offset = { + hx0: X - ( x + r + w - gap * 2 ), + hx1: X - ( x + r + w / 2 - gap ), + hx2: X - ( x + r + gap ), + vhy: Y - ( y + r + h + r + gap ), + '^hy': Y - ( y - gap ), + + }, + mask = [ { + x: x + r, + y: y, + w: w, + w4: w / 4, + h4: h / 4, + right: 0, + left: w - gap * 2, + bottom: 0, + top: h - gap * 2, + r: r, + h: h, + gap: gap, + }, { + x: x + r, + y: y, + w: w, + w4: w / 4, + h4: h / 4, + left: w / 2 - gap, + right: w / 2 - gap, + top: h / 2 - gap, + bottom: h / 2 - gap, + r: r, + h: h, + gap: gap, + }, { + x: x + r, + y: y, + w: w, + w4: w / 4, + h4: h / 4, + left: 0, + right: w - gap * 2, + top: 0, + bottom: h - gap * 2, + r: r, + h: h, + gap: gap, + } ][pos[1] == 'middle' ? 1 : ( pos[1] == 'top' || pos[1] == 'left' ) * 2]; + var dx = 0, + dy = 0, + out = this.path( fill( shapes[pos[0]], mask ) ).insertBefore( set ); + switch ( pos[0] ) { + case 'top': + dx = X - ( x + r + mask.left + gap ); + dy = Y - ( y + r + h + r + gap ); + break; + case 'bottom': + dx = X - ( x + r + mask.left + gap ); + dy = Y - ( y - gap ); + break; + case 'left': + dx = X - ( x + r + w + r + gap ); + dy = Y - ( y + r + mask.top + gap ); + break; + case 'right': + dx = X - ( x - gap ); + dy = Y - ( y + r + mask.top + gap ); + break; + } + out.translate( dx, dy ); + if ( ret ) { + ret = out.attr( 'path' ); + out.remove(); + return { + path: ret, + dx: dx, + dy: dy, + }; + } + set.translate( dx, dy ); + return out; +}; + +function getAnchors( p1x, p1y, p2x, p2y, p3x, p3y ) { + var l1 = ( p2x - p1x ) / 2, + l2 = ( p3x - p2x ) / 2, + a = Math.atan( ( p2x - p1x ) / Math.abs( p2y - p1y ) ), + b = Math.atan( ( p3x - p2x ) / Math.abs( p2y - p3y ) ); + a = p1y < p2y ? Math.PI - a : a; + b = p3y < p2y ? Math.PI - b : b; + var alpha = Math.PI / 2 - ( ( a + b ) % ( Math.PI * 2 ) ) / 2, + dx1 = l1 * Math.sin( alpha + a ), + dy1 = l1 * Math.cos( alpha + a ), + dx2 = l2 * Math.sin( alpha + b ), + dy2 = l2 * Math.cos( alpha + b ); + return { + x1: p2x - dx1, + y1: p2y + dy1, + x2: p2x + dx2, + y2: p2y + dy2, + }; +} diff --git a/src/legacy/raphael.min.js b/src/legacy/raphael.min.js new file mode 100644 index 00000000..a1f879b4 --- /dev/null +++ b/src/legacy/raphael.min.js @@ -0,0 +1,3 @@ +!function t(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r():"function"==typeof define&&define.amd?define([],r):"object"==typeof exports?exports.Raphael=r():e.Raphael=r()}(this,function(){return function(t){function e(i){if(r[i])return r[i].exports;var n=r[i]={exports:{},id:i,loaded:!1};return t[i].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){var i,n;i=[r(1),r(3),r(4)],n=function(t){return t}.apply(e,i),!(void 0!==n&&(t.exports=n))},function(t,e,r){var i,n;i=[r(2)],n=function(t){function e(r){if(e.is(r,"function"))return w?r():t.on("raphael.DOMload",r);if(e.is(r,Q))return e._engine.create[z](e,r.splice(0,3+e.is(r[0],$))).add(r);var i=Array.prototype.slice.call(arguments,0);if(e.is(i[i.length-1],"function")){var n=i.pop();return w?n.call(e._engine.create[z](e,i)):t.on("raphael.DOMload",function(){n.call(e._engine.create[z](e,i))})}return e._engine.create[z](e,arguments)}function r(t){if("function"==typeof t||Object(t)!==t)return t;var e=new t.constructor;for(var i in t)t[A](i)&&(e[i]=r(t[i]));return e}function i(t,e){for(var r=0,i=t.length;r=1e3&&delete o[l.shift()],l.push(s),o[s]=t[z](e,a),r?r(o[s]):o[s])}return n}function a(){return this.hex}function s(t,e){for(var r=[],i=0,n=t.length;n-2*!e>i;i+=2){var a=[{x:+t[i-2],y:+t[i-1]},{x:+t[i],y:+t[i+1]},{x:+t[i+2],y:+t[i+3]},{x:+t[i+4],y:+t[i+5]}];e?i?n-4==i?a[3]={x:+t[0],y:+t[1]}:n-2==i&&(a[2]={x:+t[0],y:+t[1]},a[3]={x:+t[2],y:+t[3]}):a[0]={x:+t[n-2],y:+t[n-1]}:n-4==i?a[3]=a[2]:i||(a[0]={x:+t[i],y:+t[i+1]}),r.push(["C",(-a[0].x+6*a[1].x+a[2].x)/6,(-a[0].y+6*a[1].y+a[2].y)/6,(a[1].x+6*a[2].x-a[3].x)/6,(a[1].y+6*a[2].y-a[3].y)/6,a[2].x,a[2].y])}return r}function o(t,e,r,i,n){var a=-3*e+9*r-9*i+3*n,s=t*a+6*e-12*r+6*i;return t*s-3*e+3*r}function l(t,e,r,i,n,a,s,l,h){null==h&&(h=1),h=h>1?1:h<0?0:h;for(var u=h/2,c=12,f=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],p=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],d=0,g=0;gd;)c/=2,f+=(pW(n,s)||W(e,i)W(a,o))){var l=(t*i-e*r)*(n-s)-(t-r)*(n*o-a*s),h=(t*i-e*r)*(a-o)-(e-i)*(n*o-a*s),u=(t-r)*(a-o)-(e-i)*(n-s);if(u){var c=l/u,f=h/u,p=+c.toFixed(2),d=+f.toFixed(2);if(!(p<+G(t,r).toFixed(2)||p>+W(t,r).toFixed(2)||p<+G(n,s).toFixed(2)||p>+W(n,s).toFixed(2)||d<+G(e,i).toFixed(2)||d>+W(e,i).toFixed(2)||d<+G(a,o).toFixed(2)||d>+W(a,o).toFixed(2)))return{x:c,y:f}}}}function c(t,e){return p(t,e)}function f(t,e){return p(t,e,1)}function p(t,r,i){var n=e.bezierBBox(t),a=e.bezierBBox(r);if(!e.isBBoxIntersect(n,a))return i?0:[];for(var s=l.apply(0,t),o=l.apply(0,r),h=W(~~(s/5),1),c=W(~~(o/5),1),f=[],p=[],d={},g=i?0:[],v=0;v=0&&S<=1.001&&A>=0&&A<=1.001&&(i?g++:g.push({x:C.x,y:C.y,t1:G(S,1),t2:G(A,1)}))}}return g}function d(t,r,i){t=e._path2curve(t),r=e._path2curve(r);for(var n,a,s,o,l,h,u,c,f,d,g=i?0:[],v=0,x=t.length;vi)return i;for(;ra?r=n:i=n,n=(i-r)/2+r}return n}var h=3*e,u=3*(i-e)-h,c=1-h-u,f=3*r,p=3*(n-r)-f,d=1-f-p;return o(t,1/(200*a))}function m(t,e){var r=[],i={};if(this.ms=e,this.times=1,t){for(var n in t)t[A](n)&&(i[ht(n)]=t[n],r.push(ht(n)));r.sort(Bt)}this.anim=i,this.top=r[r.length-1],this.percents=r}function b(r,i,n,a,s,o){n=ht(n);var l,h,u,c=[],f,p,d,v=r.ms,x={},m={},b={};if(a)for(w=0,B=Ee.length;wa*r.top){n=r.percents[w],p=r.percents[w-1]||0,v=v/r.top*(n-p),f=r.percents[w+1],l=r.anim[n];break}a&&i.attr(r.anim[r.percents[w]])}if(l){if(h)h.initstatus=a,h.start=new Date-h.ms*a;else{for(var C in l)if(l[A](C)&&(pt[A](C)||i.paper.customAttributes[A](C)))switch(x[C]=i.attr(C),null==x[C]&&(x[C]=ft[C]),m[C]=l[C],pt[C]){case $:b[C]=(m[C]-x[C])/v;break;case"colour":x[C]=e.getRGB(x[C]);var S=e.getRGB(m[C]);b[C]={r:(S.r-x[C].r)/v,g:(S.g-x[C].g)/v,b:(S.b-x[C].b)/v};break;case"path":var T=Qt(x[C],m[C]),E=T[1];for(x[C]=T[0],b[C]=[],w=0,B=x[C].length;w',Lt=Nt.firstChild,Lt.style.behavior="url(#default#VML)",!Lt||"object"!=typeof Lt.adj)return e.type=R;Nt=null}e.svg=!(e.vml="VML"==e.type),e._Paper=M,e.fn=N=M.prototype=e.prototype,e._id=0,e.is=function(t,e){return e=O.call(e),"finite"==e?!at[A](+t):"array"==e?t instanceof Array:"null"==e&&null===t||e==typeof t&&null!==t||"object"==e&&t===Object(t)||"array"==e&&Array.isArray&&Array.isArray(t)||tt.call(t).slice(8,-1).toLowerCase()==e},e.angle=function(t,r,i,n,a,s){if(null==a){var o=t-i,l=r-n;return o||l?(180+180*Y.atan2(-l,-o)/U+360)%360:0}return e.angle(t,r,a,s)-e.angle(i,n,a,s)},e.rad=function(t){return t%360*U/180},e.deg=function(t){return Math.round(180*t/U%360*1e3)/1e3},e.snapTo=function(t,r,i){if(i=e.is(i,"finite")?i:10,e.is(t,Q)){for(var n=t.length;n--;)if(H(t[n]-r)<=i)return t[n]}else{t=+t;var a=r%t;if(at-i)return r-a+t}return r};var zt=e.createUUID=function(t,e){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(t,e).toUpperCase()}}(/[xy]/g,function(t){var e=16*Y.random()|0,r="x"==t?e:3&e|8;return r.toString(16)});e.setWindow=function(r){t("raphael.setWindow",e,T.win,r),T.win=r,T.doc=T.win.document,e._engine.initWin&&e._engine.initWin(T.win)};var Pt=function(t){if(e.vml){var r=/^\s+|\s+$/g,i;try{var a=new ActiveXObject("htmlfile");a.write(""),a.close(),i=a.body}catch(s){i=createPopup().document.body}var o=i.createTextRange();Pt=n(function(t){try{i.style.color=I(t).replace(r,R);var e=o.queryCommandValue("ForeColor");return e=(255&e)<<16|65280&e|(16711680&e)>>>16,"#"+("000000"+e.toString(16)).slice(-6)}catch(n){return"none"}})}else{var l=T.doc.createElement("i");l.title="Raphaël Colour Picker",l.style.display="none",T.doc.body.appendChild(l),Pt=n(function(t){return l.style.color=t,T.doc.defaultView.getComputedStyle(l,R).getPropertyValue("color")})}return Pt(t)},Ft=function(){return"hsb("+[this.h,this.s,this.b]+")"},Rt=function(){return"hsl("+[this.h,this.s,this.l]+")"},jt=function(){return this.hex},It=function(t,r,i){if(null==r&&e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t&&(i=t.b,r=t.g,t=t.r),null==r&&e.is(t,Z)){var n=e.getRGB(t);t=n.r,r=n.g,i=n.b}return(t>1||r>1||i>1)&&(t/=255,r/=255,i/=255),[t,r,i]},qt=function(t,r,i,n){t*=255,r*=255,i*=255;var a={r:t,g:r,b:i,hex:e.rgb(t,r,i),toString:jt};return e.is(n,"finite")&&(a.opacity=n),a};e.color=function(t){var r;return e.is(t,"object")&&"h"in t&&"s"in t&&"b"in t?(r=e.hsb2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):e.is(t,"object")&&"h"in t&&"s"in t&&"l"in t?(r=e.hsl2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):(e.is(t,"string")&&(t=e.getRGB(t)),e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t?(r=e.rgb2hsl(t),t.h=r.h,t.s=r.s,t.l=r.l,r=e.rgb2hsb(t),t.v=r.b):(t={hex:"none"},t.r=t.g=t.b=t.h=t.s=t.v=t.l=-1)),t.toString=jt,t},e.hsb2rgb=function(t,e,r,i){this.is(t,"object")&&"h"in t&&"s"in t&&"b"in t&&(r=t.b,e=t.s,i=t.o,t=t.h),t*=360;var n,a,s,o,l;return t=t%360/60,l=r*e,o=l*(1-H(t%2-1)),n=a=s=r-l,t=~~t,n+=[l,o,0,0,o,l][t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],qt(n,a,s,i)},e.hsl2rgb=function(t,e,r,i){this.is(t,"object")&&"h"in t&&"s"in t&&"l"in t&&(r=t.l,e=t.s,t=t.h),(t>1||e>1||r>1)&&(t/=360,e/=100,r/=100),t*=360;var n,a,s,o,l;return t=t%360/60,l=2*e*(r<.5?r:1-r),o=l*(1-H(t%2-1)),n=a=s=r-l/2,t=~~t,n+=[l,o,0,0,o,l][t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],qt(n,a,s,i)},e.rgb2hsb=function(t,e,r){r=It(t,e,r),t=r[0],e=r[1],r=r[2];var i,n,a,s;return a=W(t,e,r),s=a-G(t,e,r),i=0==s?null:a==t?(e-r)/s:a==e?(r-t)/s+2:(t-e)/s+4,i=(i+360)%6*60/360,n=0==s?0:s/a,{h:i,s:n,b:a,toString:Ft}},e.rgb2hsl=function(t,e,r){r=It(t,e,r),t=r[0],e=r[1],r=r[2];var i,n,a,s,o,l;return s=W(t,e,r),o=G(t,e,r),l=s-o,i=0==l?null:s==t?(e-r)/l:s==e?(r-t)/l+2:(t-e)/l+4,i=(i+360)%6*60/360,a=(s+o)/2,n=0==l?0:a<.5?l/(2*a):l/(2-2*a),{h:i,s:n,l:a,toString:Rt}},e._path2string=function(){return this.join(",").replace(xt,"$1")};var Dt=e._preload=function(t,e){var r=T.doc.createElement("img");r.style.cssText="position:absolute;left:-9999em;top:-9999em",r.onload=function(){e.call(this),this.onload=null,T.doc.body.removeChild(this)},r.onerror=function(){T.doc.body.removeChild(this)},T.doc.body.appendChild(r),r.src=t};e.getRGB=n(function(t){if(!t||(t=I(t)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:a};if("none"==t)return{r:-1,g:-1,b:-1,hex:"none",toString:a};!(vt[A](t.toLowerCase().substring(0,2))||"#"==t.charAt())&&(t=Pt(t));var r,i,n,s,o,l,h,u=t.match(nt);return u?(u[2]&&(s=ut(u[2].substring(5),16),n=ut(u[2].substring(3,5),16),i=ut(u[2].substring(1,3),16)),u[3]&&(s=ut((l=u[3].charAt(3))+l,16),n=ut((l=u[3].charAt(2))+l,16),i=ut((l=u[3].charAt(1))+l,16)),u[4]&&(h=u[4][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),"rgba"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100)),u[5]?(h=u[5][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),("deg"==h[0].slice(-3)||"°"==h[0].slice(-1))&&(i/=360),"hsba"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100),e.hsb2rgb(i,n,s,o)):u[6]?(h=u[6][q](gt),i=ht(h[0]),"%"==h[0].slice(-1)&&(i*=2.55),n=ht(h[1]),"%"==h[1].slice(-1)&&(n*=2.55),s=ht(h[2]),"%"==h[2].slice(-1)&&(s*=2.55),("deg"==h[0].slice(-3)||"°"==h[0].slice(-1))&&(i/=360),"hsla"==u[1].toLowerCase().slice(0,4)&&(o=ht(h[3])),h[3]&&"%"==h[3].slice(-1)&&(o/=100),e.hsl2rgb(i,n,s,o)):(u={r:i,g:n,b:s,toString:a},u.hex="#"+(16777216|s|n<<8|i<<16).toString(16).slice(1),e.is(o,"finite")&&(u.opacity=o),u)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:a}},e),e.hsb=n(function(t,r,i){return e.hsb2rgb(t,r,i).hex}),e.hsl=n(function(t,r,i){return e.hsl2rgb(t,r,i).hex}),e.rgb=n(function(t,e,r){function i(t){return t+.5|0}return"#"+(16777216|i(r)|i(e)<<8|i(t)<<16).toString(16).slice(1)}),e.getColor=function(t){var e=this.getColor.start=this.getColor.start||{h:0,s:1,b:t||.75},r=this.hsb2rgb(e.h,e.s,e.b);return e.h+=.075,e.h>1&&(e.h=0,e.s-=.2,e.s<=0&&(this.getColor.start={h:0,s:1,b:e.b})),r.hex},e.getColor.reset=function(){delete this.start},e.parsePathString=function(t){if(!t)return null;var r=Vt(t);if(r.arr)return Yt(r.arr);var i={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},n=[];return e.is(t,Q)&&e.is(t[0],Q)&&(n=Yt(t)),n.length||I(t).replace(yt,function(t,e,r){var a=[],s=e.toLowerCase();if(r.replace(bt,function(t,e){e&&a.push(+e)}),"m"==s&&a.length>2&&(n.push([e][P](a.splice(0,2))),s="l",e="m"==e?"l":"L"),"r"==s)n.push([e][P](a));else for(;a.length>=i[s]&&(n.push([e][P](a.splice(0,i[s]))),i[s]););}),n.toString=e._path2string,r.arr=Yt(n),n},e.parseTransformString=n(function(t){if(!t)return null;var r={r:3,s:4,t:2,m:6},i=[];return e.is(t,Q)&&e.is(t[0],Q)&&(i=Yt(t)),i.length||I(t).replace(mt,function(t,e,r){var n=[],a=O.call(e);r.replace(bt,function(t,e){e&&n.push(+e)}),i.push([e][P](n))}),i.toString=e._path2string,i});var Vt=function(t){var e=Vt.ps=Vt.ps||{};return e[t]?e[t].sleep=100:e[t]={sleep:100},setTimeout(function(){for(var r in e)e[A](r)&&r!=t&&(e[r].sleep--,!e[r].sleep&&delete e[r])}),e[t]};e.findDotsAtSegment=function(t,e,r,i,n,a,s,o,l){var h=1-l,u=X(h,3),c=X(h,2),f=l*l,p=f*l,d=u*t+3*c*l*r+3*h*l*l*n+p*s,g=u*e+3*c*l*i+3*h*l*l*a+p*o,v=t+2*l*(r-t)+f*(n-2*r+t),x=e+2*l*(i-e)+f*(a-2*i+e),y=r+2*l*(n-r)+f*(s-2*n+r),m=i+2*l*(a-i)+f*(o-2*a+i),b=h*t+l*r,_=h*e+l*i,w=h*n+l*s,k=h*a+l*o,B=90-180*Y.atan2(v-y,x-m)/U;return(v>y||x=t.x&&e<=t.x2&&r>=t.y&&r<=t.y2},e.isBBoxIntersect=function(t,r){var i=e.isPointInsideBBox;return i(r,t.x,t.y)||i(r,t.x2,t.y)||i(r,t.x,t.y2)||i(r,t.x2,t.y2)||i(t,r.x,r.y)||i(t,r.x2,r.y)||i(t,r.x,r.y2)||i(t,r.x2,r.y2)||(t.xr.x||r.xt.x)&&(t.yr.y||r.yt.y)},e.pathIntersection=function(t,e){return d(t,e)},e.pathIntersectionNumber=function(t,e){return d(t,e,1)},e.isPointInsidePath=function(t,r,i){var n=e.pathBBox(t);return e.isPointInsideBBox(n,r,i)&&d(t,[["M",r,i],["H",n.x2+10]],1)%2==1},e._removedFactory=function(e){return function(){t("raphael.log",null,"Raphaël: you are calling to method “"+e+"” of removed object",e)}};var Ot=e.pathBBox=function(t){var e=Vt(t);if(e.bbox)return r(e.bbox);if(!t)return{x:0,y:0,width:0,height:0,x2:0,y2:0};t=Qt(t);for(var i=0,n=0,a=[],s=[],o,l=0,h=t.length;l1&&(b=Y.sqrt(b),r=b*r,i=b*i);var _=r*r,w=i*i,k=(s==o?-1:1)*Y.sqrt(H((_*w-_*m*m-w*y*y)/(_*m*m+w*y*y))),B=k*r*m/i+(t+l)/2,C=k*-i*y/r+(e+h)/2,S=Y.asin(((e-C)/i).toFixed(9)),A=Y.asin(((h-C)/i).toFixed(9));S=tA&&(S-=2*U),!o&&A>S&&(A-=2*U)}var T=A-S;if(H(T)>c){var E=A,M=l,N=h;A=S+c*(o&&A>S?1:-1),l=B+r*Y.cos(A),h=C+i*Y.sin(A),p=Ut(l,h,r,i,a,0,o,M,N,[A,E,B,C])}T=A-S;var L=Y.cos(S),z=Y.sin(S),F=Y.cos(A),R=Y.sin(A),j=Y.tan(T/4),I=4/3*r*j,D=4/3*i*j,V=[t,e],O=[t+I*z,e-D*L],W=[l+I*R,h-D*F],G=[l,h];if(O[0]=2*V[0]-O[0],O[1]=2*V[1]-O[1],u)return[O,W,G][P](p);p=[O,W,G][P](p).join()[q](",");for(var X=[],$=0,Z=p.length;$"1e12"&&(c=.5),H(f)>"1e12"&&(f=.5),c>0&&c<1&&(g=$t(t,e,r,i,n,a,s,o,c),d.push(g.x),p.push(g.y)),f>0&&f<1&&(g=$t(t,e,r,i,n,a,s,o,f),d.push(g.x),p.push(g.y)),l=a-2*i+e-(o-2*a+i),h=2*(i-e)-2*(a-i),u=e-i,c=(-h+Y.sqrt(h*h-4*l*u))/2/l,f=(-h-Y.sqrt(h*h-4*l*u))/2/l,H(c)>"1e12"&&(c=.5),H(f)>"1e12"&&(f=.5),c>0&&c<1&&(g=$t(t,e,r,i,n,a,s,o,c),d.push(g.x),p.push(g.y)),f>0&&f<1&&(g=$t(t,e,r,i,n,a,s,o,f),d.push(g.x),p.push(g.y)),{min:{x:G[z](0,d),y:G[z](0,p)},max:{x:W[z](0,d),y:W[z](0,p)}}}),Qt=e._path2curve=n(function(t,e){var r=!e&&Vt(t);if(!e&&r.curve)return Yt(r.curve);for(var i=Gt(t),n=e&&Gt(e),a={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},s={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},o=(function(t,e,r){var i,n,a={T:1,Q:1};if(!t)return["C",e.x,e.y,e.x,e.y,e.x,e.y];switch(!(t[0]in a)&&(e.qx=e.qy=null),t[0]){case"M":e.X=t[1],e.Y=t[2];break;case"A":t=["C"][P](Ut[z](0,[e.x,e.y][P](t.slice(1))));break;case"S":"C"==r||"S"==r?(i=2*e.x-e.bx,n=2*e.y-e.by):(i=e.x,n=e.y),t=["C",i,n][P](t.slice(1));break;case"T":"Q"==r||"T"==r?(e.qx=2*e.x-e.qx,e.qy=2*e.y-e.qy):(e.qx=e.x,e.qy=e.y),t=["C"][P](Xt(e.x,e.y,e.qx,e.qy,t[1],t[2]));break;case"Q":e.qx=t[1],e.qy=t[2],t=["C"][P](Xt(e.x,e.y,t[1],t[2],t[3],t[4]));break;case"L":t=["C"][P](Ht(e.x,e.y,t[1],t[2]));break;case"H":t=["C"][P](Ht(e.x,e.y,t[1],e.y));break;case"V":t=["C"][P](Ht(e.x,e.y,e.x,t[1]));break;case"Z":t=["C"][P](Ht(e.x,e.y,e.X,e.Y))}return t}),l=function(t,e){if(t[e].length>7){t[e].shift();for(var r=t[e];r.length;)u[e]="A",n&&(c[e]="A"),t.splice(e++,0,["C"][P](r.splice(0,6)));t.splice(e,1),g=W(i.length,n&&n.length||0)}},h=function(t,e,r,a,s){t&&e&&"M"==t[s][0]&&"M"!=e[s][0]&&(e.splice(s,0,["M",a.x,a.y]),r.bx=0,r.by=0,r.x=t[s][1],r.y=t[s][2],g=W(i.length,n&&n.length||0))},u=[],c=[],f="",p="",d=0,g=W(i.length,n&&n.length||0);dn){if(r&&!c.start){if(f=ke(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p),u+=["C"+f.start.x,f.start.y,f.m.x,f.m.y,f.x,f.y],a)return u;c.start=u,u=["M"+f.x,f.y+"C"+f.n.x,f.n.y,f.end.x,f.end.y,l[5],l[6]].join(),p+=h,s=+l[5],o=+l[6];continue}if(!t&&!r)return f=ke(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p),{x:f.x,y:f.y,alpha:f.alpha}}p+=h,s=+l[5],o=+l[6]}u+=l.shift()+l}return c.end=u,f=t?p:r?c:e.findDotsAtSegment(s,o,l[0],l[1],l[2],l[3],l[4],l[5],1),f.alpha&&(f={x:f.x,y:f.y,alpha:f.alpha}),f}},Ce=Be(1),Se=Be(),Ae=Be(0,1);e.getTotalLength=Ce,e.getPointAtLength=Se,e.getSubpath=function(t,e,r){if(this.getTotalLength(t)-r<1e-6)return Ae(t,e).end;var i=Ae(t,r,1);return e?Ae(i,e).end:i},ye.getTotalLength=function(){var t=this.getPath();if(t)return this.node.getTotalLength?this.node.getTotalLength():Ce(t)},ye.getPointAtLength=function(t){var e=this.getPath();if(e)return Se(e,t)},ye.getPath=function(){var t,r=e._getPath[this.type];if("text"!=this.type&&"set"!=this.type)return r&&(t=r(this)),t},ye.getSubpath=function(t,r){var i=this.getPath();if(i)return e.getSubpath(i,t,r)};var Te=e.easing_formulas={linear:function(t){return t},"<":function(t){return X(t,1.7)},">":function(t){return X(t,.48)},"<>":function(t){var e=.48-t/1.04,r=Y.sqrt(.1734+e*e),i=r-e,n=X(H(i),1/3)*(i<0?-1:1),a=-r-e,s=X(H(a),1/3)*(a<0?-1:1),o=n+s+.5;return 3*(1-o)*o*o+o*o*o},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){t-=1;var e=1.70158;return t*t*((e+1)*t+e)+1},elastic:function(t){return t==!!t?t:X(2,-10*t)*Y.sin((t-.075)*(2*U)/.3)+1},bounce:function(t){var e=7.5625,r=2.75,i;return t<1/r?i=e*t*t:t<2/r?(t-=1.5/r,i=e*t*t+.75):t<2.5/r?(t-=2.25/r,i=e*t*t+.9375):(t-=2.625/r,i=e*t*t+.984375),i}};Te.easeIn=Te["ease-in"]=Te["<"],Te.easeOut=Te["ease-out"]=Te[">"],Te.easeInOut=Te["ease-in-out"]=Te["<>"],Te["back-in"]=Te.backIn,Te["back-out"]=Te.backOut;var Ee=[],Me=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){setTimeout(t,16)},Ne=function(){for(var r=+new Date,i=0;i1&&!n.next){for(v in u)u[A](v)&&(g[v]=n.totalOrigin[v]);n.el.attr(g),b(n.anim,n.el,n.anim.percents[0],null,n.totalOrigin,n.repeat-1)}n.next&&!n.stop&&b(n.anim,n.el,n.next,null,n.totalOrigin,n.repeat)}}}Ee.length&&Me(Ne)},Le=function(t){return t>255?255:t<0?0:t};ye.animateWith=function(t,r,i,n,a,s){var o=this;if(o.removed)return s&&s.call(o),o;var l=i instanceof m?i:e.animation(i,n,a,s),h,u;b(l,o,l.percents[0],null,o.attr());for(var c=0,f=Ee.length;cl&&(l=u)}l+="%",!t[l].callback&&(t[l].callback=n)}return new m(t,r)},ye.animate=function(t,r,i,n){var a=this;if(a.removed)return n&&n.call(a),a;var s=t instanceof m?t:e.animation(t,r,i,n);return b(s,a,s.percents[0],null,a.attr()),a},ye.setTime=function(t,e){return t&&null!=e&&this.status(t,G(e,t.ms)/t.ms),this},ye.status=function(t,e){var r=[],i=0,n,a;if(null!=e)return b(t,this,-1,G(e,1)),this;for(n=Ee.length;i1)for(var i=0,n=r.length;i.5)-1;l(f-.5,2)+l(p-.5,2)>.25&&(p=a.sqrt(.25-l(f-.5,2))*n+.5)&&.5!=p&&(p=p.toFixed(5)-1e-5*n)}return c}),n=n.split(/\s*\-\s*/),"linear"==h){var b=n.shift();if(b=-i(b),isNaN(b))return null;var _=[0,0,a.cos(t.rad(b)),a.sin(t.rad(b))],w=1/(s(o(_[2]),o(_[3]))||1);_[2]*=w,_[3]*=w,_[2]<0&&(_[0]=-_[2],_[2]=0),_[3]<0&&(_[1]=-_[3],_[3]=0)}var k=t._parseDots(n);if(!k)return null;if(u=u.replace(/[\(\)\s,\xb0#]/g,"_"),e.gradient&&u!=e.gradient.id&&(g.defs.removeChild(e.gradient),delete e.gradient),!e.gradient){y=v(h+"Gradient",{id:u}),e.gradient=y,v(y,"radial"==h?{fx:f,fy:p}:{x1:_[0],y1:_[1],x2:_[2],y2:_[3],gradientTransform:e.matrix.invert()}),g.defs.appendChild(y);for(var B=0,C=k.length;B1?z.opacity/100:z.opacity});case"stroke":z=t.getRGB(g),l.setAttribute(d,z.hex),"stroke"==d&&z[e]("opacity")&&v(l,{"stroke-opacity":z.opacity>1?z.opacity/100:z.opacity}),"stroke"==d&&i._.arrows&&("startString"in i._.arrows&&_(i,i._.arrows.startString),"endString"in i._.arrows&&_(i,i._.arrows.endString,1));break;case"gradient":("circle"==i.type||"ellipse"==i.type||"r"!=r(g).charAt())&&x(i,g);break;case"opacity":u.gradient&&!u[e]("stroke-opacity")&&v(l,{"stroke-opacity":g>1?g/100:g});case"fill-opacity":if(u.gradient){P=t._g.doc.getElementById(l.getAttribute("fill").replace(/^url\(#|\)$/g,c)),P&&(F=P.getElementsByTagName("stop"),v(F[F.length-1],{"stop-opacity":g}));break}default:"font-size"==d&&(g=n(g,10)+"px");var R=d.replace(/(\-.)/g,function(t){return t.substring(1).toUpperCase()});l.style[R]=g,i._.dirty=1,l.setAttribute(d,g)}}S(i,a),l.style.visibility=f},C=1.2,S=function(i,a){if("text"==i.type&&(a[e]("text")||a[e]("font")||a[e]("font-size")||a[e]("x")||a[e]("y"))){var s=i.attrs,o=i.node,l=o.firstChild?n(t._g.doc.defaultView.getComputedStyle(o.firstChild,c).getPropertyValue("font-size"),10):10;if(a[e]("text")){for(s.text=a.text;o.firstChild;)o.removeChild(o.firstChild);for(var h=r(a.text).split("\n"),u=[],f,p=0,d=h.length;p"));var Z=X.getBoundingClientRect();m.W=f.w=(Z.right-Z.left)/U,m.H=f.h=(Z.bottom-Z.top)/U,m.X=f.x,m.Y=f.y+m.H/2,("x"in l||"y"in l)&&(m.path.v=t.format("m{0},{1}l{2},{1}",a(f.x*b),a(f.y*b),a(f.x*b)+1));for(var Q=["x","y","text","font","font-family","font-weight","font-style","font-size"],J=0,K=Q.length;J.25&&(r=n.sqrt(.25-l(e-.5,2))*(2*(r>.5)-1)+.5),f=e+p+r),d}),a=a.split(/\s*\-\s*/),"linear"==c){var g=a.shift();if(g=-i(g),isNaN(g))return null}var v=t._parseDots(a);if(!v)return null;if(e=e.shape||e.node,v.length){e.removeChild(s),s.on=!0,s.method="none",s.color=v[0].color,s.color2=v[v.length-1].color;for(var x=[],y=0,m=v.length;y')}}catch(r){N=function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},t._engine.initWin(t._g.win),t._engine.create=function(){var e=t._getContainer.apply(0,arguments),r=e.container,i=e.height,n,a=e.width,s=e.x,o=e.y;if(!r)throw new Error("VML container not found.");var l=new t._Paper,h=l.canvas=t._g.doc.createElement("div"),u=h.style;return s=s||0,o=o||0,a=a||512,i=i||342,l.width=a,l.height=i,a==+a&&(a+="px"),i==+i&&(i+="px"),l.coordsize=1e3*b+p+1e3*b,l.coordorigin="0 0",l.span=t._g.doc.createElement("span"),l.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",h.appendChild(l.span),u.cssText=t.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",a,i),1==r?(t._g.doc.body.appendChild(h),u.left=s+"px",u.top=o+"px",u.position="absolute"):r.firstChild?r.insertBefore(h,r.firstChild):r.appendChild(h),l.renderfix=function(){},l},t.prototype.clear=function(){t.eve("raphael.clear",this),this.canvas.innerHTML=d,this.span=t._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},t.prototype.remove=function(){t.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var e in this)this[e]="function"==typeof this[e]?t._removedFactory(e):null;return!0};var L=t.st;for(var z in M)M[e](z)&&!L[e](z)&&(L[z]=function(t){return function(){var e=arguments;return this.forEach(function(r){r[t].apply(r,e)})}}(z))}}.apply(e,i),!(void 0!==n&&(t.exports=n))}])}); From cce02a03b01775b7e0aad50698149f221e0b003f Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 15:57:38 +0100 Subject: [PATCH 027/184] move all files from inc of lib folder --- {inc => lib}/Admin/Fields/Checkbox.php | 0 {inc => lib}/Admin/Fields/Field.php | 0 {inc => lib}/Admin/Fields/Text.php | 0 {inc => lib}/Admin/Fields/Textarea.php | 0 {inc => lib}/Admin/RenderElement.php | 0 {inc => lib}/Admin/Section.php | 0 {inc => lib}/Admin/SettingsPage.php | 0 {inc => lib}/Fields/Honeypot.php | 0 {inc => lib}/Fields/Select.php | 0 {inc => lib}/Handlers/Comment.php | 0 {inc => lib}/Handlers/PostProcessors.php | 0 {inc => lib}/Handlers/Rules.php | 0 {inc => lib}/Handlers/Trackback.php | 0 {inc => lib}/Interfaces/Controllable.php | 0 {inc => lib}/Interfaces/PostProcessor.php | 0 {inc => lib}/Interfaces/Verifiable.php | 0 {inc => lib}/PostProcessors/Delete.php | 0 {inc => lib}/PostProcessors/DeleteForReasons.php | 0 {inc => lib}/PostProcessors/InitPostProcessor.php | 0 {inc => lib}/PostProcessors/IsActive.php | 0 {inc => lib}/PostProcessors/SaveReason.php | 0 {inc => lib}/PostProcessors/SendEmail.php | 0 {inc => lib}/PostProcessors/UpdateDailyStats.php | 0 {inc => lib}/PostProcessors/UpdateSpamCount.php | 0 {inc => lib}/PostProcessors/UpdateSpamLog.php | 0 {inc => lib}/Rules/ApprovedEmail.php | 0 {inc => lib}/Rules/BBCode.php | 0 {inc => lib}/Rules/Controllable.php | 0 {inc => lib}/Rules/CountrySpam.php | 0 {inc => lib}/Rules/DbSpam.php | 0 {inc => lib}/Rules/Honeypot.php | 0 {inc => lib}/Rules/InitRule.php | 0 {inc => lib}/Rules/IsActive.php | 0 {inc => lib}/Rules/LangSpam.php | 0 {inc => lib}/Rules/RegexpSpam.php | 0 {inc => lib}/Rules/ShortestTime.php | 0 {inc => lib}/Rules/TrackbackFromMyself.php | 0 {inc => lib}/Rules/TrackbackPostTitleIsBlogName.php | 0 {inc => lib}/Rules/ValidGravatar.php | 0 {inc => lib}/Rules/Verifiable.php | 0 {inc => lib}/Settings.php | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename {inc => lib}/Admin/Fields/Checkbox.php (100%) rename {inc => lib}/Admin/Fields/Field.php (100%) rename {inc => lib}/Admin/Fields/Text.php (100%) rename {inc => lib}/Admin/Fields/Textarea.php (100%) rename {inc => lib}/Admin/RenderElement.php (100%) rename {inc => lib}/Admin/Section.php (100%) rename {inc => lib}/Admin/SettingsPage.php (100%) rename {inc => lib}/Fields/Honeypot.php (100%) rename {inc => lib}/Fields/Select.php (100%) rename {inc => lib}/Handlers/Comment.php (100%) rename {inc => lib}/Handlers/PostProcessors.php (100%) rename {inc => lib}/Handlers/Rules.php (100%) rename {inc => lib}/Handlers/Trackback.php (100%) rename {inc => lib}/Interfaces/Controllable.php (100%) rename {inc => lib}/Interfaces/PostProcessor.php (100%) rename {inc => lib}/Interfaces/Verifiable.php (100%) rename {inc => lib}/PostProcessors/Delete.php (100%) rename {inc => lib}/PostProcessors/DeleteForReasons.php (100%) rename {inc => lib}/PostProcessors/InitPostProcessor.php (100%) rename {inc => lib}/PostProcessors/IsActive.php (100%) rename {inc => lib}/PostProcessors/SaveReason.php (100%) rename {inc => lib}/PostProcessors/SendEmail.php (100%) rename {inc => lib}/PostProcessors/UpdateDailyStats.php (100%) rename {inc => lib}/PostProcessors/UpdateSpamCount.php (100%) rename {inc => lib}/PostProcessors/UpdateSpamLog.php (100%) rename {inc => lib}/Rules/ApprovedEmail.php (100%) rename {inc => lib}/Rules/BBCode.php (100%) rename {inc => lib}/Rules/Controllable.php (100%) rename {inc => lib}/Rules/CountrySpam.php (100%) rename {inc => lib}/Rules/DbSpam.php (100%) rename {inc => lib}/Rules/Honeypot.php (100%) rename {inc => lib}/Rules/InitRule.php (100%) rename {inc => lib}/Rules/IsActive.php (100%) rename {inc => lib}/Rules/LangSpam.php (100%) rename {inc => lib}/Rules/RegexpSpam.php (100%) rename {inc => lib}/Rules/ShortestTime.php (100%) rename {inc => lib}/Rules/TrackbackFromMyself.php (100%) rename {inc => lib}/Rules/TrackbackPostTitleIsBlogName.php (100%) rename {inc => lib}/Rules/ValidGravatar.php (100%) rename {inc => lib}/Rules/Verifiable.php (100%) rename {inc => lib}/Settings.php (100%) diff --git a/inc/Admin/Fields/Checkbox.php b/lib/Admin/Fields/Checkbox.php similarity index 100% rename from inc/Admin/Fields/Checkbox.php rename to lib/Admin/Fields/Checkbox.php diff --git a/inc/Admin/Fields/Field.php b/lib/Admin/Fields/Field.php similarity index 100% rename from inc/Admin/Fields/Field.php rename to lib/Admin/Fields/Field.php diff --git a/inc/Admin/Fields/Text.php b/lib/Admin/Fields/Text.php similarity index 100% rename from inc/Admin/Fields/Text.php rename to lib/Admin/Fields/Text.php diff --git a/inc/Admin/Fields/Textarea.php b/lib/Admin/Fields/Textarea.php similarity index 100% rename from inc/Admin/Fields/Textarea.php rename to lib/Admin/Fields/Textarea.php diff --git a/inc/Admin/RenderElement.php b/lib/Admin/RenderElement.php similarity index 100% rename from inc/Admin/RenderElement.php rename to lib/Admin/RenderElement.php diff --git a/inc/Admin/Section.php b/lib/Admin/Section.php similarity index 100% rename from inc/Admin/Section.php rename to lib/Admin/Section.php diff --git a/inc/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php similarity index 100% rename from inc/Admin/SettingsPage.php rename to lib/Admin/SettingsPage.php diff --git a/inc/Fields/Honeypot.php b/lib/Fields/Honeypot.php similarity index 100% rename from inc/Fields/Honeypot.php rename to lib/Fields/Honeypot.php diff --git a/inc/Fields/Select.php b/lib/Fields/Select.php similarity index 100% rename from inc/Fields/Select.php rename to lib/Fields/Select.php diff --git a/inc/Handlers/Comment.php b/lib/Handlers/Comment.php similarity index 100% rename from inc/Handlers/Comment.php rename to lib/Handlers/Comment.php diff --git a/inc/Handlers/PostProcessors.php b/lib/Handlers/PostProcessors.php similarity index 100% rename from inc/Handlers/PostProcessors.php rename to lib/Handlers/PostProcessors.php diff --git a/inc/Handlers/Rules.php b/lib/Handlers/Rules.php similarity index 100% rename from inc/Handlers/Rules.php rename to lib/Handlers/Rules.php diff --git a/inc/Handlers/Trackback.php b/lib/Handlers/Trackback.php similarity index 100% rename from inc/Handlers/Trackback.php rename to lib/Handlers/Trackback.php diff --git a/inc/Interfaces/Controllable.php b/lib/Interfaces/Controllable.php similarity index 100% rename from inc/Interfaces/Controllable.php rename to lib/Interfaces/Controllable.php diff --git a/inc/Interfaces/PostProcessor.php b/lib/Interfaces/PostProcessor.php similarity index 100% rename from inc/Interfaces/PostProcessor.php rename to lib/Interfaces/PostProcessor.php diff --git a/inc/Interfaces/Verifiable.php b/lib/Interfaces/Verifiable.php similarity index 100% rename from inc/Interfaces/Verifiable.php rename to lib/Interfaces/Verifiable.php diff --git a/inc/PostProcessors/Delete.php b/lib/PostProcessors/Delete.php similarity index 100% rename from inc/PostProcessors/Delete.php rename to lib/PostProcessors/Delete.php diff --git a/inc/PostProcessors/DeleteForReasons.php b/lib/PostProcessors/DeleteForReasons.php similarity index 100% rename from inc/PostProcessors/DeleteForReasons.php rename to lib/PostProcessors/DeleteForReasons.php diff --git a/inc/PostProcessors/InitPostProcessor.php b/lib/PostProcessors/InitPostProcessor.php similarity index 100% rename from inc/PostProcessors/InitPostProcessor.php rename to lib/PostProcessors/InitPostProcessor.php diff --git a/inc/PostProcessors/IsActive.php b/lib/PostProcessors/IsActive.php similarity index 100% rename from inc/PostProcessors/IsActive.php rename to lib/PostProcessors/IsActive.php diff --git a/inc/PostProcessors/SaveReason.php b/lib/PostProcessors/SaveReason.php similarity index 100% rename from inc/PostProcessors/SaveReason.php rename to lib/PostProcessors/SaveReason.php diff --git a/inc/PostProcessors/SendEmail.php b/lib/PostProcessors/SendEmail.php similarity index 100% rename from inc/PostProcessors/SendEmail.php rename to lib/PostProcessors/SendEmail.php diff --git a/inc/PostProcessors/UpdateDailyStats.php b/lib/PostProcessors/UpdateDailyStats.php similarity index 100% rename from inc/PostProcessors/UpdateDailyStats.php rename to lib/PostProcessors/UpdateDailyStats.php diff --git a/inc/PostProcessors/UpdateSpamCount.php b/lib/PostProcessors/UpdateSpamCount.php similarity index 100% rename from inc/PostProcessors/UpdateSpamCount.php rename to lib/PostProcessors/UpdateSpamCount.php diff --git a/inc/PostProcessors/UpdateSpamLog.php b/lib/PostProcessors/UpdateSpamLog.php similarity index 100% rename from inc/PostProcessors/UpdateSpamLog.php rename to lib/PostProcessors/UpdateSpamLog.php diff --git a/inc/Rules/ApprovedEmail.php b/lib/Rules/ApprovedEmail.php similarity index 100% rename from inc/Rules/ApprovedEmail.php rename to lib/Rules/ApprovedEmail.php diff --git a/inc/Rules/BBCode.php b/lib/Rules/BBCode.php similarity index 100% rename from inc/Rules/BBCode.php rename to lib/Rules/BBCode.php diff --git a/inc/Rules/Controllable.php b/lib/Rules/Controllable.php similarity index 100% rename from inc/Rules/Controllable.php rename to lib/Rules/Controllable.php diff --git a/inc/Rules/CountrySpam.php b/lib/Rules/CountrySpam.php similarity index 100% rename from inc/Rules/CountrySpam.php rename to lib/Rules/CountrySpam.php diff --git a/inc/Rules/DbSpam.php b/lib/Rules/DbSpam.php similarity index 100% rename from inc/Rules/DbSpam.php rename to lib/Rules/DbSpam.php diff --git a/inc/Rules/Honeypot.php b/lib/Rules/Honeypot.php similarity index 100% rename from inc/Rules/Honeypot.php rename to lib/Rules/Honeypot.php diff --git a/inc/Rules/InitRule.php b/lib/Rules/InitRule.php similarity index 100% rename from inc/Rules/InitRule.php rename to lib/Rules/InitRule.php diff --git a/inc/Rules/IsActive.php b/lib/Rules/IsActive.php similarity index 100% rename from inc/Rules/IsActive.php rename to lib/Rules/IsActive.php diff --git a/inc/Rules/LangSpam.php b/lib/Rules/LangSpam.php similarity index 100% rename from inc/Rules/LangSpam.php rename to lib/Rules/LangSpam.php diff --git a/inc/Rules/RegexpSpam.php b/lib/Rules/RegexpSpam.php similarity index 100% rename from inc/Rules/RegexpSpam.php rename to lib/Rules/RegexpSpam.php diff --git a/inc/Rules/ShortestTime.php b/lib/Rules/ShortestTime.php similarity index 100% rename from inc/Rules/ShortestTime.php rename to lib/Rules/ShortestTime.php diff --git a/inc/Rules/TrackbackFromMyself.php b/lib/Rules/TrackbackFromMyself.php similarity index 100% rename from inc/Rules/TrackbackFromMyself.php rename to lib/Rules/TrackbackFromMyself.php diff --git a/inc/Rules/TrackbackPostTitleIsBlogName.php b/lib/Rules/TrackbackPostTitleIsBlogName.php similarity index 100% rename from inc/Rules/TrackbackPostTitleIsBlogName.php rename to lib/Rules/TrackbackPostTitleIsBlogName.php diff --git a/inc/Rules/ValidGravatar.php b/lib/Rules/ValidGravatar.php similarity index 100% rename from inc/Rules/ValidGravatar.php rename to lib/Rules/ValidGravatar.php diff --git a/inc/Rules/Verifiable.php b/lib/Rules/Verifiable.php similarity index 100% rename from inc/Rules/Verifiable.php rename to lib/Rules/Verifiable.php diff --git a/inc/Settings.php b/lib/Settings.php similarity index 100% rename from inc/Settings.php rename to lib/Settings.php From 323a1849374c97d0c6337a1f83be0118c8e29d86 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 16:03:50 +0100 Subject: [PATCH 028/184] initialize all modules using their constructors, as they might be used in some of them --- lib/load.php | 62 ++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/load.php b/lib/load.php index 4211593c..8aec8df8 100644 --- a/lib/load.php +++ b/lib/load.php @@ -10,10 +10,13 @@ use AntispamBee\Admin\DashboardWidgets; use AntispamBee\Admin\SettingsPage; use AntispamBee\Fields\Honeypot as HoneypotField; -use AntispamBee\Rules\Honeypot as HoneypotRule; use AntispamBee\Handlers\Comment; use AntispamBee\Handlers\Trackback; use AntispamBee\Helpers\AssetsLoader; +use AntispamBee\Helpers\CommentsColumns; +use AntispamBee\Helpers\Installer; +use AntispamBee\Helpers\OptionsHelper; +use AntispamBee\Helpers\StatsHelpers; use AntispamBee\PostProcessors\Delete; use AntispamBee\PostProcessors\DeleteForReasons; use AntispamBee\PostProcessors\SaveReason; @@ -25,16 +28,13 @@ use AntispamBee\Rules\BBCode; use AntispamBee\Rules\CountrySpam; use AntispamBee\Rules\DbSpam; +use AntispamBee\Rules\Honeypot as HoneypotRule; use AntispamBee\Rules\LangSpam; use AntispamBee\Rules\RegexpSpam; use AntispamBee\Rules\ShortestTime; use AntispamBee\Rules\TrackbackFromMyself; use AntispamBee\Rules\TrackbackPostTitleIsBlogName; use AntispamBee\Rules\ValidGravatar; -use AntispamBee\Helpers\CommentsColumns; -use AntispamBee\Helpers\Installer; -use AntispamBee\Helpers\OptionsHelper; -use AntispamBee\Helpers\StatsHelpers; /** * Init function of the plugin @@ -42,32 +42,32 @@ function init() { // Construct all modules to initialize. $modules = [ - 'helpers_assets_loader' => new AssetsLoader(), - 'settings_page' => new SettingsPage(), - 'helpers_comments_columns' => new CommentsColumns(), - 'approved_email_rule' => ApprovedEmail::class, - 'bbcode_rule' => BBCode::class, - 'country_spam_rule' => CountrySpam::class, - 'db_spam_rule' => DbSpam::class, - 'lang_spam_rule' => LangSpam::class, - 'regexp_spam_rule' => RegexpSpam::class, - 'shortest_time_rule' => ShortestTime::class, - 'trackback_from_myself_rule' => TrackbackFromMyself::class, - 'trackback_post_title_is_blog_name_rule' => TrackbackPostTitleIsBlogName::class, - 'valid_gravatar_rule' => ValidGravatar::class, - 'honeypot_rule' => HoneypotRule::class, - 'delete_post_processor' => Delete::class, - 'delete_for_reasons_post_processor' => DeleteForReasons::class, - 'save_reason_post_processor' => SaveReason::class, - 'send_email_post_processor' => SendEmail::class, - 'update_daily_stats_post_processor' => UpdateDailyStats::class, - 'update_spam_count_post_processor' => UpdateSpamCount::class, - 'update_spam_log_post_processor' => UpdateSpamLog::class, - 'comment_handler' => Comment::class, - 'trackback_handler' => Trackback::class, - 'helpers_options_helper' => new OptionsHelper(), - 'helpers_dashboard_helper' => new DashboardWidgets(), - 'helpers_stats_helpers' => new StatsHelpers(), + 'admin_dashboard_helper' => new DashboardWidgets(), + 'admin_settings_page' => new SettingsPage(), + 'handlers_comment_handler' => new Comment(), + 'handlers_trackback_handler' => new Trackback(), + 'helpers_assets_loader' => new AssetsLoader(), + 'helpers_comments_columns' => new CommentsColumns(), + 'helpers_options_helper' => new OptionsHelper(), + 'helpers_stats_helpers' => new StatsHelpers(), + 'post_processor_delete' => new Delete(), + 'post_processor_delete_for_reasons' => new DeleteForReasons(), + 'post_processor_save_reason' => new SaveReason(), + 'post_processor_send_email' => new SendEmail(), + 'post_processor_update_daily_stats' => new UpdateDailyStats(), + 'post_processor_update_spam_count' => new UpdateSpamCount(), + 'post_processor_update_spam_log' => new UpdateSpamLog(), + 'rules_approved_email' => new ApprovedEmail(), + 'rules_bbcode' => new BBCode(), + 'rules_country_spam' => new CountrySpam(), + 'rules_db_spam' => new DbSpam(), + 'rules_honeypot' => new HoneypotRule(), + 'rules_lang_spam' => new LangSpam(), + 'rules_regexp_spam' => new RegexpSpam(), + 'rules_shortest_time' => new ShortestTime(), + 'rules_trackback_from_myself' => new TrackbackFromMyself(), + 'rules_trackback_post_title_is_blog_name' => new TrackbackPostTitleIsBlogName(), + 'rules_valid_gravatar' => new ValidGravatar(), ]; // Initialize all modules. From 9a5c2828910bc74edea44d7efbd875d430be91c8 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Mon, 21 Mar 2022 16:04:14 +0100 Subject: [PATCH 029/184] remove duplicate OptionsPage file (duplicate of SettingsPage) --- lib/Admin/OptionsPage.php | 69 --------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 lib/Admin/OptionsPage.php diff --git a/lib/Admin/OptionsPage.php b/lib/Admin/OptionsPage.php deleted file mode 100644 index 971c4cbd..00000000 --- a/lib/Admin/OptionsPage.php +++ /dev/null @@ -1,69 +0,0 @@ - Date: Mon, 21 Mar 2022 16:12:47 +0100 Subject: [PATCH 030/184] automated code style fixes (mostly whitespaces) --- lib/Admin/SettingsPage.php | 8 ++-- lib/Fields/Honeypot.php | 41 +++++++++---------- lib/Handlers/Rules.php | 3 +- lib/Helpers/AssetsLoader.php | 2 +- lib/Helpers/IpHelper.php | 1 - lib/Helpers/ItemTypeHelper.php | 10 ++--- lib/Helpers/LangCodeHelper.php | 2 +- lib/Helpers/OptionsHelper.php | 1 - lib/Interfaces/Controllable.php | 1 + lib/PostProcessors/InitPostProcessor.php | 15 ++++--- lib/PostProcessors/SendEmail.php | 50 ++++++++++++------------ lib/Rules/ApprovedEmail.php | 12 +++--- lib/Rules/Controllable.php | 1 + lib/Rules/CountrySpam.php | 14 ++++--- lib/Rules/InitRule.php | 15 ++++--- lib/Rules/LangSpam.php | 11 ++++-- lib/Settings.php | 49 +++++++++++------------ 17 files changed, 123 insertions(+), 113 deletions(-) diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 496e41bb..4703bd89 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -58,7 +58,7 @@ public function setup_settings() { new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), - new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ) + new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), ] ); @@ -95,10 +95,10 @@ public function options_page() {

- Date: Wed, 30 Mar 2022 18:31:45 +0200 Subject: [PATCH 037/184] work on tabs/sections/settings ... --- lib/Admin/Fields/CheckboxGroup.php | 18 +++++ lib/Admin/Fields/Select.php | 36 +++++++++ lib/Admin/Fields/Text.php | 11 ++- lib/Admin/Fields/Textarea.php | 4 +- lib/Admin/Section.php | 58 ++++++++++--- lib/Admin/SettingsPage.php | 126 ++++++++++++++++++++--------- lib/Admin/Tab.php | 73 +++++++++++++++++ lib/Fields/Honeypot.php | 5 -- lib/Handlers/PostProcessors.php | 20 +---- lib/Handlers/Rules.php | 104 ++++++++++++------------ lib/Helpers/InterfaceHelper.php | 95 ++++++++++++++++++++++ lib/Interfaces/Controllable.php | 3 +- lib/Rules/BBCode.php | 31 ++++++- lib/Rules/CountrySpam.php | 27 ++++++- lib/Rules/InitRule.php | 12 ++- 15 files changed, 494 insertions(+), 129 deletions(-) create mode 100644 lib/Admin/Fields/CheckboxGroup.php create mode 100644 lib/Admin/Fields/Select.php create mode 100644 lib/Admin/Tab.php create mode 100644 lib/Helpers/InterfaceHelper.php diff --git a/lib/Admin/Fields/CheckboxGroup.php b/lib/Admin/Fields/CheckboxGroup.php new file mode 100644 index 00000000..2254205a --- /dev/null +++ b/lib/Admin/Fields/CheckboxGroup.php @@ -0,0 +1,18 @@ +get_name() . '" value="1" ' . checked( 1, $this->get_value(), false ) . ' />'; + $this->maybe_show_description(); + } +} diff --git a/lib/Admin/Fields/Select.php b/lib/Admin/Fields/Select.php new file mode 100644 index 00000000..16f5b88a --- /dev/null +++ b/lib/Admin/Fields/Select.php @@ -0,0 +1,36 @@ +options = $options; + $this->multiple = $multiple; + } + + /** + * Get HTML. + * + * @return string Elment HTML. + */ + public function render() { + echo ''; + $this->maybe_show_description(); + } +} diff --git a/lib/Admin/Fields/Text.php b/lib/Admin/Fields/Text.php index a5ffa6a8..413f1b73 100644 --- a/lib/Admin/Fields/Text.php +++ b/lib/Admin/Fields/Text.php @@ -8,13 +8,22 @@ * Text field. */ class Text extends Field implements RenderElement { + + protected $placeholder; + + public function __construct( $name, $label, $description = '', $placeholder = '' ) { + parent::__construct( $name, $label, $description ); + + $this->placeholder = $placeholder; + } + /** * Get HTML. * * @return string Elment HTML. */ public function render() { - echo ''; + echo ''; $this->maybe_show_description(); } } diff --git a/lib/Admin/Fields/Textarea.php b/lib/Admin/Fields/Textarea.php index 646f77e6..7f110ae9 100644 --- a/lib/Admin/Fields/Textarea.php +++ b/lib/Admin/Fields/Textarea.php @@ -11,10 +11,10 @@ class Textarea extends Field implements RenderElement { /** * Get HTML. * - * @return string Elment HTML. + * @return string Element HTML. */ public function render() { - echo ''; + echo '
'; $this->maybe_show_description(); } } diff --git a/lib/Admin/Section.php b/lib/Admin/Section.php index 52447e11..032e03a1 100644 --- a/lib/Admin/Section.php +++ b/lib/Admin/Section.php @@ -2,6 +2,11 @@ namespace AntispamBee\Admin; +use AntispamBee\Admin\Fields\Select; +use AntispamBee\Admin\Fields\Text; +use AntispamBee\Admin\Fields\Textarea; +use AntispamBee\Helpers\InterfaceHelper; + /** * Sections for admin. */ @@ -32,19 +37,54 @@ class Section { * * @var Field[] */ - private $fields; + private $fields = []; - /** - * Initializung Tab. - * - * @param string $label Title for tab - * @param Section[] $sections Sections object array. - */ - public function __construct( $name, $title, $description = '', $fields ) { + private $type; + + public function __construct( $name, $title, $description = '', $type = null ) { $this->name = $name; $this->title = $title; - $this->fields = $fields; $this->description = $description; + $this->type = $type; + } + + public function add_fields( $fields ) { + $this->fields = array_merge( $this->fields, $fields ); + } + + public function add_controllables( $controllables ) { + $this->generate_fields( $controllables ); + } + + private function generate_fields( $controllables ) { + $fields = []; + foreach ( $controllables as $controllable ) { + // Todo: Generate checkbox to activate/deactivate rule + + $options = InterfaceHelper::call( $controllable, 'controllable', 'get_options' ); + if ( empty( $options ) ) { + continue; + } + + foreach ( $options as $option ) { + $fields[] = $this->generate_field( $option ); + } + } + + $this->fields = array_merge( $this->fields, $fields ); + } + + private function generate_field( $option ) { + switch ( $option['type'] ) { + case 'input': + return new Text( $this->type . '_' . $option['option_name'], $option['label'], '' ); + case 'select': + return new Select( $this->type . '_' . $option['option_name'], $option['label'], + 'Hold CTRL to select multiple entries', $option['options'], false ); + case 'textarea': + return new Textarea( $this->type . '_' . $option['option_name'], $option['label'], + $option['label'] ); + } } /** diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 4703bd89..295608af 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -3,11 +3,27 @@ namespace AntispamBee\Admin; use AntispamBee\Admin\Fields\Checkbox; +use AntispamBee\Admin\Fields\Text; +use AntispamBee\Admin\Fields\Select; +use AntispamBee\Admin\Fields\Textarea; +use AntispamBee\Handlers\Rules; +use AntispamBee\Handlers\Trackback; +use AntispamBee\Helpers\InterfaceHelper; +use AntispamBee\Helpers\ItemTypeHelper; +use AntispamBee\Interfaces\Controllable; +use AntispamBee\Interfaces\Verifiable; /** * Antispam Bee Settings Page */ class SettingsPage { + /** + * Active tab + * + * @var string + */ + private $active_tab = []; + /** * Active section * @@ -18,9 +34,9 @@ class SettingsPage { /** * Tabs * - * @var Section[] + * @var Tab[] */ - private $sections = []; + private $tabs = []; /** * Add Hooks. @@ -29,7 +45,7 @@ public function init() { add_action( 'admin_menu', [ $this, 'add_menu' ] ); add_action( 'admin_init', [ $this, 'setup_settings' ] ); - $this->active_section = isset( $_GET['section'] ) ? $_GET['section'] : 'general'; + $this->active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general'; } /** @@ -49,39 +65,76 @@ public function add_menu() { * Setup tabs content. */ public function setup_settings() { - // General - $sections[] = new Section( + $general_section = new Section( 'general', __( 'General', 'antispam-bee' ), - __( 'Setup global plugin spam settings.', 'antispam-bee' ), + __( 'Setup global plugin spam settings.', 'antispam-bee' ) ); + $general_section->add_fields( [ + new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), + new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), + new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), + new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), + ] ); + $general_tab = new Tab( + 'general', + __( 'General','antispam-bee' ), [ - new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), - new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), - new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), - new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), + $general_section ] ); - $this->sections = apply_filters( 'antispam_bee_sections', $sections ); + $rules = Rules::filter( Rules::get(), [ + 'is_controllable' => true, + 'only_active' => true, + ] ); + $types = []; + foreach ( $rules as $rule ) { + $types = array_merge( $types, InterfaceHelper::call( $rule, 'controllable', 'get_supported_types' ) ); + } + $types = array_unique( $types ); + + $tabs = []; + $tabs['general'] = $general_tab; + foreach ( $types as $type ) { + $section = new Section( + 'rules', + __( 'Rules', 'antispam-bee' ), + __( 'Setup rules.', 'antispam-bee' ), + $type + ); + $section->add_controllables( Rules::filter( $rules, [ + 'type' => $type, + ] ) ); + $tabs[$type] = new Tab( + $type . '_tab', + ItemTypeHelper::get_type_name( $type ), + [ + 'rules' => $section + ] + ); + } + $this->tabs = $tabs; // Register option setting - foreach ( $this->sections as $section ) { - if ( $section->get_name() !== $this->active_section ) { - continue; - } - - add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); - - foreach ( $section->get_fields() as $field ) { - add_settings_field( - $field->get_name(), - $field->get_label(), - [ $field, 'render' ], - 'antispam_bee', - $section->get_name() - ); - - register_setting( 'antispam_bee', $field->get_name() ); + foreach ( $this->tabs as $tab ) { + foreach ( $tab->get_sections() as $section ) { + if ( $tab->get_slug() !== $this->active_tab ) { + continue; + } + + add_settings_section( $section->get_name(), '' . $section->get_title() . '', [ $section, 'get_callback' ], 'antispam_bee' ); + + foreach ( $section->get_fields() as $field ) { + add_settings_field( + $field->get_name(), + $field->get_label(), + [ $field, 'render' ], + 'antispam_bee', + $section->get_name() + ); + + register_setting( 'antispam_bee', $field->get_name() ); + } } } } @@ -95,20 +148,21 @@ public function options_page() {

-
+ - active_section ); ?> + active_tab ); ?> +
diff --git a/lib/Admin/Tab.php b/lib/Admin/Tab.php new file mode 100644 index 00000000..82176beb --- /dev/null +++ b/lib/Admin/Tab.php @@ -0,0 +1,73 @@ +slug = $slug; + $this->title = $title; + $this->sections = $sections; + } + + /** + * Get slug. + * + * @return string Name of the field. + */ + public function get_slug() { + return $this->slug; + } + + /** + * Get title. + * + * @return string Title of the field. + */ + public function get_title() { + return $this->title; + } + + /** + * Get sections. + * + * @return Section[] + */ + public function get_sections() { + return $this->sections; + } + + public function add_section( Section $section ) { + $this->sections[] = $section; + } +} diff --git a/lib/Fields/Honeypot.php b/lib/Fields/Honeypot.php index 235f3231..3a125e2c 100644 --- a/lib/Fields/Honeypot.php +++ b/lib/Fields/Honeypot.php @@ -37,11 +37,6 @@ public static function inject( $markup, $options ) { ); switch ( $input_type ) { case 'textarea': - $item = sprintf( - '', - $attributes_string - ); - $regex = str_replace( [ '{{HONEYPOT_ID}}', '{{HONEYPOT_NAME}}' ], [ $honeypot_id, $honeypot_name ], diff --git a/lib/Handlers/PostProcessors.php b/lib/Handlers/PostProcessors.php index 0ab10345..9e8fea21 100644 --- a/lib/Handlers/PostProcessors.php +++ b/lib/Handlers/PostProcessors.php @@ -2,6 +2,7 @@ namespace AntispamBee\Handlers; +use AntispamBee\Helpers\InterfaceHelper; use AntispamBee\Interfaces\PostProcessor; class PostProcessors { @@ -61,16 +62,7 @@ public static function get( $type = null, $only_active = false ) { private static function is_valid_post_processor( $post_processor ) { if ( isset( $post_processor['post_processor'] ) ) { - $interfaces = class_implements( $post_processor['post_processor'] ); - if ( false === $interfaces || empty( $interfaces ) ) { - return false; - } - - if ( ! in_array( PostProcessor::class, $interfaces, true ) ) { - return false; - } - - return true; + return InterfaceHelper::class_implements_interface( $post_processor['post_processor'], PostProcessor::class ); } $post_processor_callables = [ @@ -80,12 +72,6 @@ private static function is_valid_post_processor( $post_processor ) { 'get_supported_types', ]; - foreach ( $post_processor_callables as $key ) { - if ( ! isset( $post_processor[ $key ] ) || ! is_callable( $post_processor[ $key ] ) ) { - return false; - } - } - - return true; + return InterfaceHelper::array_has_callables( $post_processor, $post_processor_callables ); } } diff --git a/lib/Handlers/Rules.php b/lib/Handlers/Rules.php index c7d5414c..5e500b4c 100644 --- a/lib/Handlers/Rules.php +++ b/lib/Handlers/Rules.php @@ -2,7 +2,11 @@ namespace AntispamBee\Handlers; +use AntispamBee\Helpers\InterfaceHelper; +use AntispamBee\Helpers\IpHelper; +use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\Verifiable; +use AntispamBee\Rules\ApprovedEmail; class Rules { protected $type; @@ -47,65 +51,18 @@ public function apply( $item ) { } public static function get( $type = null, $only_active = false ) { - $all_rules = apply_filters( 'asb_rules', [] ); - - $rules = []; - foreach ( $all_rules as $rule ) { - if ( self::is_valid_rule( $rule ) ) { - $get_supported_types_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_supported_types' ] : $rule['get_supported_types']; - $supported_types = call_user_func( $get_supported_types_function ); - - if ( ! in_array( $type, $supported_types ) ) { - continue; - } - - if ( ! $only_active ) { - $rules[] = $rule; - continue; - } - - $is_active_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'is_active' ] : $rule['is_active']; - $is_active = call_user_func( $is_active_function, $type ); - - if ( ! $is_active ) { - continue; - } - - $rules[] = $rule; - } - } - - return $rules; + return self::filter( apply_filters( 'asb_rules', [] ), [ + 'type' => $type, + 'only_active' => $only_active, + ] ); } private static function is_valid_rule( $rule ) { if ( isset( $rule['verifiable'] ) ) { - $interfaces = class_implements( $rule['verifiable'] ); - if ( false === $interfaces || empty( $interfaces ) ) { - return false; - } - - if ( ! in_array( Verifiable::class, $interfaces, true ) ) { - return false; - } - - return true; - } - - $rule_callables = [ - 'is_active', - 'verify', - 'get_slug', - 'get_supported_types', - ]; - - foreach ( $rule_callables as $key ) { - if ( ! isset( $rule[ $key ] ) || ! is_callable( $rule[ $key ] ) ) { - return false; - } + return InterfaceHelper::conforms_to_interface( $rule['verifiable'], Verifiable::class ); } - return true; + return false; } public function get_spam_reasons() { @@ -115,4 +72,45 @@ public function get_spam_reasons() { public function get_no_spam_reasons() { return $this->no_spam_reasons; } + + /** + * @param $options + * $options = array( + * 'type' => 'comment', + * 'only_active' => true, + * 'is_controllable' => false, + * ); + */ + public static function filter( $rules, $options ) { + $type = isset( $options['type'] ) ? $options['type'] : null; + $only_active = isset( $options['only_active'] ) ? $options['only_active'] : false; + $is_controllable = isset( $options['is_controllable'] ) ? $options['is_controllable'] : false; + + $filtered_rules = []; + foreach ( $rules as $rule ) { + if ( self::is_valid_rule( $rule ) ) { + $supported_types = InterfaceHelper::call( $rule, 'verifiable', 'get_supported_types' ); + if ( ! is_null( $type ) && ! in_array( $type, $supported_types ) ) { + continue; + } + + if ( $is_controllable ) { + if ( ! isset( $rule['controllable'] ) + || ! InterfaceHelper::conforms_to_interface( $rule['controllable'], Controllable::class ) ) { + continue; + } + } + + if ( $only_active ) { + if ( ! InterfaceHelper::call( $rule, 'verifiable', 'is_active', $type ) ) { + continue; + } + } + + $filtered_rules[] = $rule; + } + } + + return $filtered_rules; + } } diff --git a/lib/Helpers/InterfaceHelper.php b/lib/Helpers/InterfaceHelper.php new file mode 100644 index 00000000..ed7fb9c6 --- /dev/null +++ b/lib/Helpers/InterfaceHelper.php @@ -0,0 +1,95 @@ +getInterfaces(); + if ( false === $interfaces || empty( $interfaces ) ) { + return false; + } + + if ( ! array_key_exists( $interface, $interfaces ) ) { + return false; + } + + return true; + } + + public static function array_conforms_to_interface( $array, $interface ) { + if ( ! is_array( $array ) ) { + return false; + } + + $refClass = new \ReflectionClass( $interface ); + + $callables = []; + foreach ( $refClass->getMethods() as $method ) { + $callables[] = $method->name; + } + + return self::array_has_callables( $array, $callables ); + } + + public static function conforms_to_interface( $array_or_object, $interface ) { + return self::array_conforms_to_interface( $array_or_object, $interface ) || + self::class_implements_interface( $array_or_object, $interface ) || + self::object_implements_interface( $array_or_object, $interface ); + } + + public static function array_has_callables( $array, $callable_names ) { + foreach ( $callable_names as $callable_name ) { + if ( ! ( isset( $array[ $callable_name ] ) && is_callable( $array[ $callable_name ] ) ) ) { + return false; + } + } + + return true; + } + + public static function object_to_callable_array( $object ) { + $ref_class = new \ReflectionClass( $object ); + + $callable_array = []; + foreach ( $ref_class->getMethods() as $method ) { + $callable_array[ $method->name ] = [ $object, $method->name ]; + } + + return $callable_array; + } +} diff --git a/lib/Interfaces/Controllable.php b/lib/Interfaces/Controllable.php index dc35de17..dca53dc8 100644 --- a/lib/Interfaces/Controllable.php +++ b/lib/Interfaces/Controllable.php @@ -15,8 +15,9 @@ public static function get_description(); * [ * 'type' => 'textarea|radio|checkbox|input|select|callable', * 'input_type' => 'email|password|number...', + * * 'label' => 'asb_deny_langcodes', * 'option_name' => 'asb_deny_langcodes', - * 'options' => [ 'Option A', 'Option B' ], + * 'options' => [ [ 'value' => 1, 'label' => 'Option 1' ], [ 'value' => 2, 'label' => 'Option 2' ] ], * 'multiple' => true, * 'placeholder' => 'My placeholder text', * 'default' => 'Default value', diff --git a/lib/Rules/BBCode.php b/lib/Rules/BBCode.php index 6f7a92bc..b3dc9232 100644 --- a/lib/Rules/BBCode.php +++ b/lib/Rules/BBCode.php @@ -46,7 +46,36 @@ public static function is_final() { } public static function get_options() { - return null; + return [ + [ + 'type' => 'input', + 'input_type' => 'email|password|number...', + 'label' => __( 'BBCodes to allow', 'antispam-bee' ), + 'option_name' => 'asb_deny_langcodes', + 'options' => [ 'Option A', 'Option B' ], + 'multiple' => true, + 'placeholder' => 'My placeholder text', + 'default' => 'Default value' + ], + [ + 'type' => 'select', + 'label' => __( 'BBCodes to allow', 'antispam-bee' ), + 'option_name' => 'asb_deny_langcodes', + 'options' => [ + [ + 'value' => 1, + 'label' => 'Option A' + ], + [ + 'value' => 2, + 'label' => 'Option B' + ], + ], + 'multiple' => false, + 'placeholder' => 'My placeholder text', + 'default' => 'Default value' + ] + ]; } public static function get_supported_types() { diff --git a/lib/Rules/CountrySpam.php b/lib/Rules/CountrySpam.php index e6198d1a..dd8d87d4 100644 --- a/lib/Rules/CountrySpam.php +++ b/lib/Rules/CountrySpam.php @@ -152,7 +152,26 @@ public static function is_final() { } public static function get_options() { - return null; + return [ + [ + 'type' => 'textarea', + 'label' => __( 'Denied ISO country codes for this option.', 'antispam-bee' ), + 'placeholder' => __( 'e.g. BF, SG, YE', 'antispam-bee' ), + 'option_name' => 'ab_country_denied', + 'sanitize' => function( $value ) { + return self::sanitize_input( $value ); + } + ], + [ + 'type' => 'textarea', + 'label' => __( 'Allowed ISO country codes for this option.', 'antispam-bee' ), + 'placeholder' => __( 'e.g. BF, SG, YE', 'antispam-bee' ), + 'option_name' => 'ab_country_allowed', + 'sanitize' => function( $value ) { + return self::sanitize_input( $value ); + } + ] + ]; } public static function get_supported_types() { @@ -160,6 +179,12 @@ public static function get_supported_types() { } public static function is_active( $type ) { + return true; + } + + private static function sanitize_input( $value ) { return false; } + + } diff --git a/lib/Rules/InitRule.php b/lib/Rules/InitRule.php index ab37448d..ecfcbae7 100644 --- a/lib/Rules/InitRule.php +++ b/lib/Rules/InitRule.php @@ -2,15 +2,21 @@ namespace AntispamBee\Rules; +use AntispamBee\Helpers\InterfaceHelper; +use AntispamBee\Interfaces\Controllable; + trait InitRule { public static function init() { add_filter( 'asb_rules', function ( $rules ) { - $rules[] = [ - 'verifiable' => self::class, - ]; + $rule = []; + $rule['verifiable'] = self::class; + if ( InterfaceHelper::class_implements_interface( self::class, Controllable::class ) ) { + $rule['controllable'] = self::class; + } + $rules[] = $rule; return $rules; } ); From 4a1281c88f8544eb02cddb073ed157194622223d Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sat, 2 Apr 2022 13:51:33 +0200 Subject: [PATCH 038/184] add back honeypot regex comments --- lib/Fields/Honeypot.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/Fields/Honeypot.php b/lib/Fields/Honeypot.php index 235f3231..045fff2d 100644 --- a/lib/Fields/Honeypot.php +++ b/lib/Fields/Honeypot.php @@ -45,27 +45,27 @@ public static function inject( $markup, $options ) { $regex = str_replace( [ '{{HONEYPOT_ID}}', '{{HONEYPOT_NAME}}' ], [ $honeypot_id, $honeypot_name ], - '/(?P - '; + printf( + '', + esc_attr( $this->get_name() ), + esc_html( $this->get_value() ) + ); $this->maybe_show_description(); } } diff --git a/lib/Admin/Section.php b/lib/Admin/Section.php index 52447e11..efa92ffc 100644 --- a/lib/Admin/Section.php +++ b/lib/Admin/Section.php @@ -37,7 +37,7 @@ class Section { /** * Initializung Tab. * - * @param string $label Title for tab + * @param string $label Title for tab * @param Section[] $sections Sections object array. */ public function __construct( $name, $title, $description = '', $fields ) { @@ -85,7 +85,10 @@ public function get_fields() { public function get_callback() { if ( ! empty( $this->description ) ) { - echo '

' . $this->get_description() . '

'; + printf( + '

%s

', + wp_kses_post( $this->get_description() ) + ); } } } diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 4703bd89..5b998ba7 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -29,7 +29,8 @@ public function init() { add_action( 'admin_menu', [ $this, 'add_menu' ] ); add_action( 'admin_init', [ $this, 'setup_settings' ] ); - $this->active_section = isset( $_GET['section'] ) ? $_GET['section'] : 'general'; + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $this->active_section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : 'general'; } /** @@ -97,9 +98,9 @@ public function options_page() { diff --git a/lib/Handlers/Comment.php b/lib/Handlers/Comment.php index 33720088..0a4eec22 100644 --- a/lib/Handlers/Comment.php +++ b/lib/Handlers/Comment.php @@ -32,7 +32,7 @@ function () { public static function process( $comment ) { $comment['comment_author_IP'] = IpHelper::get_client_ip(); - $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : null; + $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : null; $request_path = DataHelper::parse_url( $request_uri, 'path' ); if ( empty( $request_path ) ) { diff --git a/lib/Rules/Honeypot.php b/lib/Rules/Honeypot.php index 9f101c7c..e4a61473 100644 --- a/lib/Rules/Honeypot.php +++ b/lib/Rules/Honeypot.php @@ -15,7 +15,8 @@ class Honeypot implements Verifiable, Controllable { use InitRule; public static function verify( $data ) { - if ( isset( $_POST['ab_spam__hidden_field'] ) && $_POST['ab_spam__hidden_field'] == 1 ) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing + if ( isset( $_POST['ab_spam__hidden_field'] ) && 1 === $_POST['ab_spam__hidden_field'] ) { return 1; } @@ -47,6 +48,7 @@ public static function precheck() { if ( ! empty( $_POST[ $fields['hidden_field'] ] ) ) { $_POST['ab_spam__hidden_field'] = 1; } else { + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $_POST[ $fields['hidden_field'] ] = $_POST[ $fields['plugin_field'] ]; unset( $_POST[ HoneypotField::get_secret_name_for_post() ] ); } @@ -58,7 +60,7 @@ public static function get_name() { } public static function get_label() { - return __( '', 'antispam-bee' ); + return ''; } public static function get_description() { diff --git a/lib/Rules/LangSpam.php b/lib/Rules/LangSpam.php index d4c3104b..7a80c32e 100644 --- a/lib/Rules/LangSpam.php +++ b/lib/Rules/LangSpam.php @@ -48,6 +48,7 @@ public static function verify( $data ) { * Do not translate into your own language. */ if ( strpos( + // phpcs:ignore WordPress.WP.I18n.MissingArgDomain _x( 'words', 'Word count type. Do not translate!' ), 'characters' ) === 0 && preg_match( diff --git a/lib/Rules/ShortestTime.php b/lib/Rules/ShortestTime.php index 27d7dd06..10c1d40c 100644 --- a/lib/Rules/ShortestTime.php +++ b/lib/Rules/ShortestTime.php @@ -23,6 +23,8 @@ public static function verify( $data ) { return 0; } + // @todo: maybe rename this filter to start with `abs` and add a deprecation message. + // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound if ( time() - $init_time < apply_filters( 'ab_action_time_limit', 5 ) ) { return 1; } From a6e477c757cec8cdf634b4b5406562f3201b31aa Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sat, 2 Apr 2022 18:51:24 +0200 Subject: [PATCH 043/184] use sprintf for honeypot script markup - remove type attribute as in a44bca14a2ba1f660ccf2b3c9a9a8cc0bc7f0fe4 --- lib/Fields/Honeypot.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Fields/Honeypot.php b/lib/Fields/Honeypot.php index 045fff2d..c0476797 100644 --- a/lib/Fields/Honeypot.php +++ b/lib/Fields/Honeypot.php @@ -78,7 +78,12 @@ function ( $matches ) use ( $honeypot_id, $honeypot_name, $attributes_string ) { if ( ! empty( $matches['id1'] ) || ! empty( $matches['id2'] ) ) { $output .= 'id="' . self::get_secret_id_for_post() . '" '; if ( ! self::_is_amp() ) { - $id_script = ''; + $id_script = sprintf( + '', + $honeypot_id, + esc_js( substr( md5( time() ), 0, 31 ) ), + esc_js( self::get_secret_id_for_post() ) + ); } } From c64aa832cd7763abbb300e6e582918492f99c90a Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sat, 2 Apr 2022 19:20:08 +0200 Subject: [PATCH 044/184] PHPCS fixing issues in lib/Admin --- lib/Admin/Fields/Checkbox.php | 5 +++++ lib/Admin/Fields/Field.php | 13 ++++++++---- lib/Admin/Fields/Text.php | 7 +++++-- lib/Admin/Fields/Textarea.php | 7 +++++-- lib/Admin/RenderElement.php | 5 +++++ lib/Admin/Section.php | 18 ++++++++++++++--- lib/Admin/SettingsPage.php | 37 +++++++++++++++++++++++++++++------ lib/Helpers/AssetsLoader.php | 2 +- 8 files changed, 76 insertions(+), 18 deletions(-) diff --git a/lib/Admin/Fields/Checkbox.php b/lib/Admin/Fields/Checkbox.php index 03a088b7..07fafec0 100644 --- a/lib/Admin/Fields/Checkbox.php +++ b/lib/Admin/Fields/Checkbox.php @@ -1,4 +1,9 @@ name = $name; $this->title = $title; $this->fields = $fields; @@ -83,6 +92,9 @@ public function get_fields() { return $this->fields; } + /** + * Print the UI element. + */ public function get_callback() { if ( ! empty( $this->description ) ) { printf( diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 5b998ba7..24776a7c 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -1,4 +1,9 @@ comment_form_field_comment' ) ), + new Checkbox( + 'ab_dashboard_chart', + esc_html__( 'Generate statistics as a dashboard widget', 'antispam-bee' ), + esc_html__( 'Daily updates of spam detection rate', 'antispam-bee' ) + ), + new Checkbox( + 'ab_dashboard_count', + esc_html__( 'Spam counter on the dashboard', 'antispam-bee' ), + esc_html__( 'Amount of identified spam comments', 'antispam-bee' ) + ), + new Checkbox( + 'ab_ignore_pings', + esc_html__( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), + esc_html__( 'No spam check for link notifications', 'antispam-bee' ) + ), + new Checkbox( + 'ab_use_output_buffer', + esc_html__( 'Check complete site markup for comment forms', 'antispam-bee' ), + sprintf( + /* translators: %s: filter name */ + esc_html__( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), + 'comment_form_field_comment' + ) + ), ] ); $this->sections = apply_filters( 'antispam_bee_sections', $sections ); - // Register option setting + // Register option setting. foreach ( $this->sections as $section ) { if ( $section->get_name() !== $this->active_section ) { continue; diff --git a/lib/Helpers/AssetsLoader.php b/lib/Helpers/AssetsLoader.php index f67cdbd7..e4801979 100644 --- a/lib/Helpers/AssetsLoader.php +++ b/lib/Helpers/AssetsLoader.php @@ -8,7 +8,7 @@ namespace AntispamBee\Helpers; /** - * Class AssetsLoader + * AssetsLoader helper. */ class AssetsLoader { /** From 0d3912405131d496fc6d46a0ffeabb2555acb20b Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Sat, 2 Apr 2022 19:35:39 +0200 Subject: [PATCH 045/184] PHPCS fixing issues in lib/Fields --- lib/Fields/Honeypot.php | 60 ++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/lib/Fields/Honeypot.php b/lib/Fields/Honeypot.php index c0476797..335b670a 100644 --- a/lib/Fields/Honeypot.php +++ b/lib/Fields/Honeypot.php @@ -1,22 +1,41 @@ query( '//*[@id="' . $options['field_id'] . '"]' )->item( 0 ); if ( ! $input ) { - return; + return ''; } - $input_type = $input->nodeName; - $honeypot_id = $input->attributes->getNamedItem( 'id' )->textContent; - $honeypot_name = $input->attributes->getNamedItem( 'name' )->textContent; + // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $input_type = $input->nodeName; + $honeypot_id = $input->attributes->getNamedItem( 'id' )->textContent; + $honeypot_name = $input->attributes->getNamedItem( 'name' )->textContent; + // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $attributes_string = sprintf( 'id="%s" name="%s" aria-hidden="true" aria-label="hp-comment" autocomplete="new-password" tabindex="-1" style="padding:0 !important;clip:rect(1px, 1px, 1px, 1px) !important;position:absolute !important;white-space:nowrap !important;height:1px !important;width:1px !important;overflow:hidden !important;"', $honeypot_id, @@ -77,7 +98,7 @@ function ( $matches ) use ( $honeypot_id, $honeypot_name, $attributes_string ) { $id_script = ''; if ( ! empty( $matches['id1'] ) || ! empty( $matches['id2'] ) ) { $output .= 'id="' . self::get_secret_id_for_post() . '" '; - if ( ! self::_is_amp() ) { + if ( ! self::is_amp() ) { $id_script = sprintf( '', $honeypot_id, @@ -118,10 +139,8 @@ function ( $matches ) use ( $honeypot_id, $honeypot_name, $attributes_string ) { /** * Returns the secret of a post used in the textarea id attribute. * - * @param int $post_id The post ID. - * * @return string - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * @since 2.10.0 Modify secret generation because `always_allowed` option no longer exists */ public static function get_secret_id_for_post() { $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); @@ -132,10 +151,8 @@ public static function get_secret_id_for_post() { /** * Returns the secret of a post used in the textarea name attribute. * - * @param int $post_id The Post ID. - * * @return string - * @since 2.10.0 Modify secret generation because `always_allowed` option not longer exists + * @since 2.10.0 Modify secret generation because `always_allowed` option no longer exists */ public static function get_secret_name_for_post() { $secret = substr( sha1( md5( 'comment-id' . self::get_salt() ) ), 0, 10 ); @@ -167,10 +184,15 @@ public static function ensure_secret_starts_with_letter( $secret ) { * * @return bool */ - private static function _is_amp() { + private static function is_amp() { return ( function_exists( 'amp_is_request' ) && amp_is_request() ) || ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ); } + /** + * Get the current salt. + * + * @return string + */ private static function get_salt() { $salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : ABSPATH; From af4f4ef63e2e06578f505af2fe4050bad537f3c8 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Thu, 7 Apr 2022 08:54:55 +0200 Subject: [PATCH 046/184] extract the honeypot inject to the init method of the rule --- lib/Rules/Honeypot.php | 16 ++++++++++++++++ lib/load.php | 7 ------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/Rules/Honeypot.php b/lib/Rules/Honeypot.php index e4a61473..aca65df5 100644 --- a/lib/Rules/Honeypot.php +++ b/lib/Rules/Honeypot.php @@ -14,6 +14,22 @@ class Honeypot implements Verifiable, Controllable { use IsActive; use InitRule; + /** + * Initialize the rule. + * + * @return void + */ + public static function init() { + add_filter( 'asb_rules', [ __CLASS__, 'add_rule' ] ); + + add_filter( + 'comment_form_field_comment', + function ( $field_markup ) { + return HoneypotField::inject( $field_markup, [ 'field_id' => 'comment' ] ); + } + ); + } + public static function verify( $data ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( isset( $_POST['ab_spam__hidden_field'] ) && 1 === $_POST['ab_spam__hidden_field'] ) { diff --git a/lib/load.php b/lib/load.php index dffcd746..180550c4 100644 --- a/lib/load.php +++ b/lib/load.php @@ -74,13 +74,6 @@ function init() { call_user_func( [ $module, 'init' ] ); } } - - add_filter( - 'comment_form_field_comment', - function ( $field_markup ) { - return HoneypotField::inject( $field_markup, [ 'field_id' => 'comment' ] ); - } - ); } add_action( 'plugins_loaded', 'AntispamBee\init' ); From 8532369ae5ddf1f11b492a5db595d84ca64becb3 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Thu, 7 Apr 2022 16:20:47 +0200 Subject: [PATCH 047/184] Work on settings --- lib/Admin/Fields/Checkbox.php | 7 ++- lib/Admin/Fields/Field.php | 34 +++++------ lib/Admin/Fields/Select.php | 7 --- lib/Admin/Fields/Text.php | 11 ++-- lib/Admin/Fields/Textarea.php | 3 +- lib/Admin/Section.php | 71 +++++++++++++++------- lib/Admin/SettingsPage.php | 84 +++++++++++++++++++------- lib/Handlers/PostProcessors.php | 5 ++ lib/Handlers/Rules.php | 28 +++++---- lib/Helpers/CommentsColumns.php | 4 +- lib/Helpers/InterfaceHelper.php | 7 ++- lib/Helpers/ItemTypeHelper.php | 1 + lib/Helpers/Settings.php | 102 ++++++++++---------------------- lib/Rules/BBCode.php | 33 +---------- lib/Rules/CountrySpam.php | 8 +-- lib/Rules/Honeypot.php | 4 +- lib/Rules/LangSpam.php | 4 +- lib/Rules/RegexpSpam.php | 4 +- lib/Rules/ValidGravatar.php | 6 +- lib/load.php | 41 +++++++++++++ 20 files changed, 253 insertions(+), 211 deletions(-) diff --git a/lib/Admin/Fields/Checkbox.php b/lib/Admin/Fields/Checkbox.php index 07fafec0..e9de1de8 100644 --- a/lib/Admin/Fields/Checkbox.php +++ b/lib/Admin/Fields/Checkbox.php @@ -18,9 +18,12 @@ class Checkbox extends Field implements RenderElement { */ public function render() { printf( - '', + '', esc_attr( $this->get_name() ), - checked( 1, $this->get_value(), false ) + checked( 'on', $this->get_value(), false ), + esc_html( $this->get_label() ) ); $this->maybe_show_description(); } diff --git a/lib/Admin/Fields/Field.php b/lib/Admin/Fields/Field.php index f69eeb54..bf6dbc44 100644 --- a/lib/Admin/Fields/Field.php +++ b/lib/Admin/Fields/Field.php @@ -7,35 +7,35 @@ namespace AntispamBee\Admin\Fields; +use AntispamBee\Helpers\Settings; + /** * Abstract class for field. */ abstract class Field { /** - * Field Name. + * Item type. * * @var string */ - private $name; + protected $type; /** - * Field Description. + * Field options. * - * @var string + * @var array */ - private $description; + protected $option; /** * Initializing field * - * @param string $name Name of the field. - * @param string $label Label of the field. - * @param string $description Description of the field. + * @param string $type Item type. + * @param array $option Field options. */ - public function __construct( $name, $label, $description = '' ) { - $this->name = $name; - $this->label = $label; - $this->description = $description; + public function __construct( $type, $option ) { + $this->type = $type; + $this->option = $option; } /** @@ -44,7 +44,7 @@ public function __construct( $name, $label, $description = '' ) { * @return string Name of the field. */ public function get_name() { - return $this->name; + return str_replace( '-', '_', 'antispam_bee[' . $this->type . '][' . $this->option['option_name'] . ']' ); } /** @@ -53,7 +53,7 @@ public function get_name() { * @return string Label of the field. */ public function get_label() { - return $this->label; + return isset( $this->option['label'] ) ? $this->option['label'] : ''; } /** @@ -62,7 +62,7 @@ public function get_label() { * @return string Description of the field. */ public function get_description() { - return $this->description; + return isset( $this->option['description'] ) ? $this->option['description'] : ''; } /** @@ -71,7 +71,7 @@ public function get_description() { * @return mixed Value stored in database. */ protected function get_value() { - return get_option( $this->name ); + return Settings::get_option( $this->option['option_name'], $this->type ); } /** @@ -80,7 +80,7 @@ protected function get_value() { protected function maybe_show_description() { if ( ! empty( $this->get_description() ) ) { printf( - '%s', + '

%s

', wp_kses_post( $this->get_description() ) ); } diff --git a/lib/Admin/Fields/Select.php b/lib/Admin/Fields/Select.php index 16f5b88a..c240eda2 100644 --- a/lib/Admin/Fields/Select.php +++ b/lib/Admin/Fields/Select.php @@ -13,13 +13,6 @@ class Select extends Field implements RenderElement { protected $multiple; - public function __construct( $name, $label, $description = '', $options = [], $multiple = false ) { - parent::__construct( $name, $label, $description ); - - $this->options = $options; - $this->multiple = $multiple; - } - /** * Get HTML. * diff --git a/lib/Admin/Fields/Text.php b/lib/Admin/Fields/Text.php index 4c863f71..5544022a 100644 --- a/lib/Admin/Fields/Text.php +++ b/lib/Admin/Fields/Text.php @@ -16,10 +16,8 @@ class Text extends Field implements RenderElement { protected $placeholder; - public function __construct( $name, $label, $description = '', $placeholder = '' ) { - parent::__construct( $name, $label, $description ); - - $this->placeholder = $placeholder; + public function get_placeholder() { + return $this->placeholder; } /** @@ -27,10 +25,11 @@ public function __construct( $name, $label, $description = '', $placeholder = '' */ public function render() { printf( - '', + '

', esc_attr( $this->get_name() ), + esc_html( $this->get_label() ), esc_attr( $this->get_value() ), - esc_attr( $this->placeholder ) + esc_attr( $this->get_placeholder() ) ); $this->maybe_show_description(); } diff --git a/lib/Admin/Fields/Textarea.php b/lib/Admin/Fields/Textarea.php index 6a50e396..8d994b8d 100644 --- a/lib/Admin/Fields/Textarea.php +++ b/lib/Admin/Fields/Textarea.php @@ -18,8 +18,9 @@ class Textarea extends Field implements RenderElement { */ public function render() { printf( - '', + '

', esc_attr( $this->get_name() ), + esc_html( $this->get_label() ), esc_html( $this->get_value() ) ); $this->maybe_show_description(); diff --git a/lib/Admin/Section.php b/lib/Admin/Section.php index a3874db9..e5081109 100644 --- a/lib/Admin/Section.php +++ b/lib/Admin/Section.php @@ -7,6 +7,7 @@ namespace AntispamBee\Admin; +use AntispamBee\Admin\Fields\Checkbox; use AntispamBee\Admin\Fields\Select; use AntispamBee\Admin\Fields\Text; use AntispamBee\Admin\Fields\Textarea; @@ -41,10 +42,15 @@ class Section { /** * Fields. * - * @var Field[] + * @var array */ - private $fields = []; + private $rows = []; + /** + * Item type. + * + * @var string + */ private $type; /** @@ -62,8 +68,12 @@ public function __construct( $name, $title, $description = '', $type = null ) { $this->type = $type; } - public function add_fields( $fields ) { - $this->fields = array_merge( $this->fields, $fields ); + + + public function add_rows( $rows ) { + foreach ( $rows as $row ) { + $this->rows[] = $row; + } } public function add_controllables( $controllables ) { @@ -71,33 +81,46 @@ public function add_controllables( $controllables ) { } private function generate_fields( $controllables ) { - $fields = []; + // Todo: DRY - Don’t run for other types than displayed foreach ( $controllables as $controllable ) { - // Todo: Generate checkbox to activate/deactivate rule + $slug = InterfaceHelper::call( $controllable, 'controllable', 'get_slug' ); + $label = InterfaceHelper::call( $controllable, 'controllable', 'get_label' ); + $description = InterfaceHelper::call( $controllable, 'controllable', 'get_description' ); + $fields = []; + $fields[] = $this->generate_field( [ + 'type' => 'checkbox', + 'option_name' => $slug . '_active', + 'label' => $label, + 'description' => $description + ] ); $options = InterfaceHelper::call( $controllable, 'controllable', 'get_options' ); - if ( empty( $options ) ) { - continue; + if ( ! empty( $options ) ) { + foreach ( $options as $option ) { + $fields[] = $this->generate_field( $option ); + } } - foreach ( $options as $option ) { - $fields[] = $this->generate_field( $option ); - } + $this->rows[] = [ + 'label' => InterfaceHelper::call( $controllable, 'controllable', 'get_name' ), + 'fields' => $fields + ]; } - - $this->fields = array_merge( $this->fields, $fields ); } private function generate_field( $option ) { + $description = isset( $option['description'] ) ? $option['description'] : ''; + // Todo: Find a more descriptive name for option_name + $name = 'antispam_bee[' . $this->type . '][' . $option['option_name'] . ']'; switch ( $option['type'] ) { case 'input': - return new Text( $this->type . '_' . $option['option_name'], $option['label'], '' ); + return new Text( $this->type, $option ); case 'select': - return new Select( $this->type . '_' . $option['option_name'], $option['label'], - 'Hold CTRL to select multiple entries', $option['options'], false ); + return new Select( $this->type, $option ); case 'textarea': - return new Textarea( $this->type . '_' . $option['option_name'], $option['label'], - $option['label'] ); + return new Textarea( $this->type, $option ); + case 'checkbox': + return new Checkbox( $this->type, $option ); } } @@ -133,8 +156,8 @@ public function get_description() { * * @return Field[] */ - public function get_fields() { - return $this->fields; + public function get_rows() { + return $this->rows; } /** @@ -148,4 +171,12 @@ public function get_callback() { ); } } + + /** + * Section + * Field Lists/Rows array + * Left-side Label string + * Fields array + * Field + */ } diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 736a10ab..53a1eda5 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -15,6 +15,7 @@ use AntispamBee\Handlers\Trackback; use AntispamBee\Helpers\InterfaceHelper; use AntispamBee\Helpers\ItemTypeHelper; +use AntispamBee\Helpers\Settings; use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\Verifiable; @@ -30,18 +31,18 @@ class SettingsPage { private $active_tab = []; /** - * Active section + * Tabs * - * @var string + * @var Tab[] */ - private $active_section = []; + private $tabs = []; /** - * Tabs + * The slug used for the Settings page * - * @var Tab[] + * @var string */ - private $tabs = []; + const SETTINGS_PAGE_SLUG = 'antispam_bee'; /** * Add Hooks. @@ -62,7 +63,7 @@ public function add_menu() { __( 'Antispam Bee', 'antispam-bee' ), __( 'Antispam Bee', 'antispam-bee' ), 'manage_options', - 'antispam_bee', + self::SETTINGS_PAGE_SLUG, [ $this, 'options_page' ] ); } @@ -71,16 +72,45 @@ public function add_menu() { * Setup tabs content. */ public function setup_settings() { + // Todo: Extract parts of the method in new methods. $general_section = new Section( 'general', __( 'General', 'antispam-bee' ), __( 'Setup global plugin spam settings.', 'antispam-bee' ) ); - $general_section->add_fields( [ - new Checkbox( 'ab_dashboard_chart', esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ) ), - new Checkbox( 'ab_dashboard_count', esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), esc_html( 'Amount of identified spam comments', 'antispam-bee' ) ), - new Checkbox( 'ab_ignore_pings', esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), esc_html( 'No spam check for link notifications', 'antispam-bee' ) ), - new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), + + $general_section->add_rows( [ + [ + 'label' => __( 'Statistics', 'antispam-bee' ), + 'fields' => [ + new Checkbox( 'general', [ + 'option_name' => 'ab_dashboard_chart', + 'label' => esc_html( 'Generate statistics as a dashboard widget', 'antispam-bee' ), + 'description' => esc_html( 'Daily updates of spam detection rate', 'antispam-bee' ), + ] ), + new Checkbox( 'general', [ + 'option_name' => 'ab_dashboard_count', + 'label' => esc_html( 'Spam counter on the dashboard', 'antispam-bee' ), + 'description' => esc_html( 'Amount of identified spam comments', 'antispam-bee' ) + ] ), + ] + ], + [ + 'label' => __( 'Pings', 'antispam-bee' ), + 'fields' => [ + new Checkbox( 'general', [ + 'option_name' => 'ab_ignore_pings', + 'label' => esc_html( 'Do not check trackbacks / pingbacks', 'antispam-bee' ), + 'description' => esc_html( 'No spam check for link notifications', 'antispam-bee' ), + ] ), + ] + ] ] ); + + // Todo: Add a way to build rows and fields with a fluent interface? + // Todo: Fix the weird naming + // Todo: Discuss if we want to remove that setting in V3 and maybe have a filter for that. + // If we keep it, we have to add it to the comments tab. + // new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), $general_tab = new Tab( 'general', __( 'General','antispam-bee' ), @@ -112,7 +142,7 @@ public function setup_settings() { 'type' => $type, ] ) ); $tabs[$type] = new Tab( - $type . '_tab', + $type, ItemTypeHelper::get_type_name( $type ), [ 'rules' => $section @@ -128,18 +158,28 @@ public function setup_settings() { continue; } - add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], 'antispam_bee' ); + add_settings_section( $section->get_name(), $section->get_title(), [ $section, 'get_callback' ], self::SETTINGS_PAGE_SLUG ); - foreach ( $section->get_fields() as $field ) { + foreach ( $section->get_rows() as $row ) { add_settings_field( - $field->get_name(), - $field->get_label(), - [ $field, 'render' ], - 'antispam_bee', + sanitize_title( $row['label'] ), + $row['label'], + function() use ( $row ) { + $last_field = false; + foreach ( $row['fields'] as $key => $field ) { + $field->render( $last_field ); + if ( $key !== count( $row['fields'] ) - 1 ) { + echo '
'; + } + } + }, + self::SETTINGS_PAGE_SLUG, $section->get_name() ); - register_setting( 'antispam_bee', $field->get_name() ); + register_setting( self::SETTINGS_PAGE_SLUG, Settings::ANTISPAM_BEE_OPTION_NAME, [ + 'sanitize_callback' => [ Settings::class, 'sanitize' ], + ] ); } } } @@ -166,8 +206,8 @@ public function options_page() {
- - active_tab ); ?> + + active_tab ); ?>
diff --git a/lib/Handlers/PostProcessors.php b/lib/Handlers/PostProcessors.php index 9e8fea21..6ec35a00 100644 --- a/lib/Handlers/PostProcessors.php +++ b/lib/Handlers/PostProcessors.php @@ -29,6 +29,9 @@ public static function apply( $type, $item, $reasons = [] ) { } public static function get( $type = null, $only_active = false ) { + // Todo: Fix: The name mustn't break the options page, we should sort out everything that can break the plugin. + // Todo: Check if other things can break it too + $all_post_processors = apply_filters( 'asb_post_processors', [] ); $post_processors = []; foreach ( $all_post_processors as $key => $post_processor ) { @@ -74,4 +77,6 @@ private static function is_valid_post_processor( $post_processor ) { return InterfaceHelper::array_has_callables( $post_processor, $post_processor_callables ); } + + // Todo: Add a filter method like in Rules } diff --git a/lib/Handlers/Rules.php b/lib/Handlers/Rules.php index 5e500b4c..32f94ad1 100644 --- a/lib/Handlers/Rules.php +++ b/lib/Handlers/Rules.php @@ -23,15 +23,13 @@ public function apply( $item ) { $score = 0.0; foreach ( $rules as $rule ) { - $verify_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'verify' ] : $rule['verify']; - $get_weight_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_weight' ] : $rule['get_weight']; - $get_slug_function = isset( $rule['verifiable'] ) ? [ $rule['verifiable'], 'get_slug' ] : $rule['get_slug']; + $rule_score = InterfaceHelper::call( $rule, 'verifiable', 'verify', $item ) + * InterfaceHelper::call( $rule, 'verifiable', 'get_weight' ); - $rule_score = call_user_func( $verify_function, $item ) * call_user_func( $get_weight_function ); if ( $rule_score > 0.0 ) { - $this->spam_reasons[] = call_user_func( $get_slug_function ); + $this->spam_reasons[] = InterfaceHelper::call( $rule, 'verifiable', 'get_slug' ); } else { - $this->no_spam_reasons[] = call_user_func( $get_slug_function ); + $this->no_spam_reasons[] = InterfaceHelper::call( $rule, 'verifiable', 'get_slug' ); } $score += $rule_score; @@ -82,9 +80,13 @@ public function get_no_spam_reasons() { * ); */ public static function filter( $rules, $options ) { + // Todo: Fix: The name mustn't break the options page, we should sort out everything that can break the plugin. + // Todo: Check if other things can break it too + $type = isset( $options['type'] ) ? $options['type'] : null; $only_active = isset( $options['only_active'] ) ? $options['only_active'] : false; - $is_controllable = isset( $options['is_controllable'] ) ? $options['is_controllable'] : false; + // Todo: Change the key from is_controllable to only_controllables + $only_controllables = isset( $options['is_controllable'] ) ? $options['is_controllable'] : false; $filtered_rules = []; foreach ( $rules as $rule ) { @@ -94,15 +96,15 @@ public static function filter( $rules, $options ) { continue; } - if ( $is_controllable ) { - if ( ! isset( $rule['controllable'] ) - || ! InterfaceHelper::conforms_to_interface( $rule['controllable'], Controllable::class ) ) { - continue; - } + + $conforms_to_controllable = isset( $rule['controllable'] ) ? + InterfaceHelper::conforms_to_interface( $rule['controllable'], Controllable::class ) : false; + if ( $only_controllables && ! $conforms_to_controllable ) { + continue; } if ( $only_active ) { - if ( ! InterfaceHelper::call( $rule, 'verifiable', 'is_active', $type ) ) { + if ( $conforms_to_controllable && ! InterfaceHelper::call( $rule, 'verifiable', 'is_active', $type ) ) { continue; } } diff --git a/lib/Helpers/CommentsColumns.php b/lib/Helpers/CommentsColumns.php index fad027bd..6dbd22ce 100644 --- a/lib/Helpers/CommentsColumns.php +++ b/lib/Helpers/CommentsColumns.php @@ -64,11 +64,11 @@ public static function print_plugin_column( $column, $comment_id ) { $spam_reason = get_comment_meta( $comment_id, $column, true ); $spam_reasons = Settings::get_options( 'reasons' ); - if ( empty( $spam_reason ) || empty( $spam_reasons[ $spam_reason ] ) ) { + if ( empty( $spam_reason ) ) { return; } - echo esc_html( $spam_reasons[ $spam_reason ] ); + echo esc_html( $spam_reason ); } /** diff --git a/lib/Helpers/InterfaceHelper.php b/lib/Helpers/InterfaceHelper.php index ed7fb9c6..28ff6aa4 100644 --- a/lib/Helpers/InterfaceHelper.php +++ b/lib/Helpers/InterfaceHelper.php @@ -5,9 +5,10 @@ class InterfaceHelper { // Todo: adapt method because the methods have to be stored under the verifiable key - public static function call( $array, $interface, $method, ...$args ) { - if ( isset( $array[ $method ] ) && is_callable( $array[ $method ] ) ) { - return call_user_func( $array[ $method ], $args ); + public static function call( $array, $interface, $method, $args = [] ) { + $callable = isset( $array[ $interface ][ $method ] ) ? $array[ $interface ][ $method ] : null; + if ( is_callable( $callable ) ) { + return call_user_func( $callable, $args ); } if ( isset( $array[ $interface ] ) && is_callable( array( $array[ $interface ], $method ) ) ) { diff --git a/lib/Helpers/ItemTypeHelper.php b/lib/Helpers/ItemTypeHelper.php index d7517305..6bb4d648 100644 --- a/lib/Helpers/ItemTypeHelper.php +++ b/lib/Helpers/ItemTypeHelper.php @@ -15,6 +15,7 @@ public static function get_type_name( $item_type ) { self::PINGBACK_TYPE => __( 'Pingback', 'antispam-bee' ), ]; + // Todo: Write a doc how to add custom types. $type_names = array_merge( apply_filters( 'asb_item_types', [] ), $type_names ); return isset( $type_names[ $item_type ] ) ? $type_names[ $item_type ] : $item_type; } diff --git a/lib/Helpers/Settings.php b/lib/Helpers/Settings.php index b71eb059..0539bb84 100644 --- a/lib/Helpers/Settings.php +++ b/lib/Helpers/Settings.php @@ -2,68 +2,12 @@ namespace AntispamBee\Helpers; -use AntispamBee\Interfaces\Controllable; - class Settings { protected static $defaults; - public static function init() { - self::init_options(); - } + const ANTISPAM_BEE_OPTION_NAME = 'antispam_bee'; - protected static function init_options() { - $defaults = [ - 'options' => [ - 'regexp_check' => 1, - 'spam_ip' => 1, - 'already_commented' => 1, - 'gravatar_check' => 0, - 'time_check' => 0, - 'ignore_pings' => 0, - - 'dashboard_chart' => 0, - 'dashboard_count' => 0, - - 'country_code' => 0, - 'country_denied' => '', - 'country_allowed' => '', - - 'translate_api' => 0, - 'translate_lang' => [], - - 'bbcode_check' => 1, - - 'flag_spam' => 1, - 'email_notify' => 0, - 'no_notice' => 0, - 'cronjob_enable' => 0, - 'cronjob_interval' => 0, - - 'ignore_filter' => 0, - 'ignore_type' => 0, - - 'reasons_enable' => 0, - 'ignore_reasons' => [], - - 'delete_data_on_uninstall' => 1, - ], - 'reasons' => [ - 'css' => esc_attr__( 'Honeypot', 'antispam-bee' ), - 'time' => esc_attr__( 'Comment time', 'antispam-bee' ), - 'empty' => esc_attr__( 'Empty Data', 'antispam-bee' ), - 'localdb' => esc_attr__( 'Local DB Spam', 'antispam-bee' ), - 'server' => esc_attr__( 'Fake IP', 'antispam-bee' ), - 'country' => esc_attr__( 'Country Check', 'antispam-bee' ), - 'bbcode' => esc_attr__( 'BBCode', 'antispam-bee' ), - 'lang' => esc_attr__( 'Comment Language', 'antispam-bee' ), - 'regexp' => esc_attr__( 'Regular Expression', 'antispam-bee' ), - 'title_is_name' => esc_attr__( 'Identical Post title and blog title', 'antispam-bee' ), - 'manually' => esc_attr__( 'Manually', 'antispam-bee' ), - ], - ]; - - self::$defaults = apply_filters( 'asb_default_options', $defaults ); - } + public static function init() {} /** * Get all plugin options @@ -79,29 +23,23 @@ public static function get_options() { ); } - if ( null === self::$defaults ) { - self::init_options(); - } - - return wp_parse_args( - $options, - self::$defaults['options'] - ); + return $options; } /** * Get single option field * - * @param string $field Field name. + * @param string $option_name Option name. + * @param string $type The type. * - * @return mixed Field value. - * @since 0.1 - * @since 2.4.2 + * @return mixed Field value. */ - public static function get_option( $field ) { + public static function get_option( $option_name, $type = 'general' ) { $options = self::get_options(); - return self::get_key( $options, $field ); + $type = str_replace( '-', '_', $type ); + $option_name = str_replace( '-', '_', $option_name ); + return isset( $options[ $type ][ $option_name ] ) ? $options[ $type ][ $option_name ] : null; } /** @@ -164,4 +102,24 @@ public static function get_key( $array, $key ) { return $array[ $key ]; } + + public static function sanitize( $options ) { + $current_options = self::get_options(); + + // Todo: Call the sanitize functions for the rules/post processors/settings + + if ( ! isset( $_GET['tab'] ) || empty ( $_GET['tab'] ) ) { + return $current_options; + } + + $tab = $_GET['tab']; + $options = ! empty( $options ) ? $options : [ $tab => [] ]; + $current_options[ $tab ] = $options[ $tab ]; + + echo '
';
+		var_dump( $options, $current_options );
+		echo '
'; + + return $current_options; + } } diff --git a/lib/Rules/BBCode.php b/lib/Rules/BBCode.php index b3dc9232..fda0aa13 100644 --- a/lib/Rules/BBCode.php +++ b/lib/Rules/BBCode.php @@ -30,7 +30,7 @@ public static function get_label() { } public static function get_description() { - __( 'Review the comment contents for BBCode links', 'antispam-bee' ); + return __( 'Review the comment contents for BBCode links', 'antispam-bee' ); } public static function get_weight() { @@ -46,36 +46,7 @@ public static function is_final() { } public static function get_options() { - return [ - [ - 'type' => 'input', - 'input_type' => 'email|password|number...', - 'label' => __( 'BBCodes to allow', 'antispam-bee' ), - 'option_name' => 'asb_deny_langcodes', - 'options' => [ 'Option A', 'Option B' ], - 'multiple' => true, - 'placeholder' => 'My placeholder text', - 'default' => 'Default value' - ], - [ - 'type' => 'select', - 'label' => __( 'BBCodes to allow', 'antispam-bee' ), - 'option_name' => 'asb_deny_langcodes', - 'options' => [ - [ - 'value' => 1, - 'label' => 'Option A' - ], - [ - 'value' => 2, - 'label' => 'Option B' - ], - ], - 'multiple' => false, - 'placeholder' => 'My placeholder text', - 'default' => 'Default value' - ] - ]; + return null; } public static function get_supported_types() { diff --git a/lib/Rules/CountrySpam.php b/lib/Rules/CountrySpam.php index dd8d87d4..6cfd3aaf 100644 --- a/lib/Rules/CountrySpam.php +++ b/lib/Rules/CountrySpam.php @@ -3,6 +3,7 @@ namespace AntispamBee\Rules; use AntispamBee\Helpers\ItemTypeHelper; +use AntispamBee\Helpers\Settings; use AntispamBee\Interfaces\Controllable; use AntispamBee\Interfaces\Verifiable; @@ -17,7 +18,7 @@ public static function verify( $data ) { } $ip = $data['comment_author_IP']; - $options = self::get_options(); + $options = Settings::get_options(); $allowed = preg_split( '/[\s,;]+/', @@ -178,13 +179,8 @@ public static function get_supported_types() { return [ ItemTypeHelper::COMMENT_TYPE, ItemTypeHelper::TRACKBACK_TYPE ]; } - public static function is_active( $type ) { - return true; - } - private static function sanitize_input( $value ) { return false; } - } diff --git a/lib/Rules/Honeypot.php b/lib/Rules/Honeypot.php index aca65df5..1bed6ab6 100644 --- a/lib/Rules/Honeypot.php +++ b/lib/Rules/Honeypot.php @@ -72,11 +72,11 @@ public static function precheck() { } public static function get_name() { - return __( 'Approved Email', 'antispam-bee' ); + return __( 'Honeypot', 'antispam-bee' ); } public static function get_label() { - return ''; + return __( 'Inject hidden field', 'antispam-bee' ); } public static function get_description() { diff --git a/lib/Rules/LangSpam.php b/lib/Rules/LangSpam.php index 7a80c32e..d4296332 100644 --- a/lib/Rules/LangSpam.php +++ b/lib/Rules/LangSpam.php @@ -108,7 +108,7 @@ public static function is_final() { } public static function get_label() { - __( 'Allow comments only in certain language', 'antispam-bee' ); + return __( 'Allow comments only in certain language', 'antispam-bee' ); } public static function get_description() { @@ -120,7 +120,7 @@ public static function get_description() { ) ); - printf( + return sprintf( /* translators: 1: opening tag with link to documentation. 2: closing tag. */ esc_html__( 'Detect and approve only the specified language. Please note the %1$sprivacy notice%2$s for this option.', 'antispam-bee' ), wp_kses_post( $link1 ), diff --git a/lib/Rules/RegexpSpam.php b/lib/Rules/RegexpSpam.php index 06e081c1..ec1ed49e 100644 --- a/lib/Rules/RegexpSpam.php +++ b/lib/Rules/RegexpSpam.php @@ -179,11 +179,11 @@ public static function get_supported_types() { } public static function get_label() { - __( 'Use regular expressions', 'antispam-bee' ); + return __( 'Use regular expressions', 'antispam-bee' ); } public static function get_description() { - __( 'Predefined and custom patterns by plugin hook', 'antispam-bee' ); + return __( 'Predefined and custom patterns by plugin hook', 'antispam-bee' ); } public static function get_options() { diff --git a/lib/Rules/ValidGravatar.php b/lib/Rules/ValidGravatar.php index 9cdca833..dd7ca957 100644 --- a/lib/Rules/ValidGravatar.php +++ b/lib/Rules/ValidGravatar.php @@ -35,7 +35,7 @@ public static function verify( $data ) { } public static function get_name() { - return ''; + return __( 'Valid Gravatar', 'antispam-bee' ); } public static function get_weight() { @@ -51,7 +51,7 @@ public static function is_final() { } public static function get_label() { - __( 'Trust commenters with a Gravatar', 'antispam-bee' ); + return __( 'Trust commenters with a Gravatar', 'antispam-bee' ); } public static function get_description() { @@ -62,7 +62,7 @@ public static function get_description() { 'https' ) ); - printf( + return sprintf( /* translators: 1: opening tag with link to documentation. 2: closing tag */ esc_html__( 'Check if commenter has a Gravatar image. Please note the %1$sprivacy notice%2$s for this option.', 'antispam-bee' ), wp_kses_post( $link1 ), diff --git a/lib/load.php b/lib/load.php index 180550c4..a2565f86 100644 --- a/lib/load.php +++ b/lib/load.php @@ -14,8 +14,12 @@ use AntispamBee\Handlers\Trackback; use AntispamBee\Helpers\AssetsLoader; use AntispamBee\Helpers\CommentsColumns; +use AntispamBee\Helpers\DataHelper; use AntispamBee\Helpers\Installer; +use AntispamBee\Helpers\InterfaceHelper; +use AntispamBee\Helpers\ItemTypeHelper; use AntispamBee\Helpers\Settings; +use AntispamBee\Interfaces\Controllable; use AntispamBee\PostProcessors\Delete; use AntispamBee\PostProcessors\DeleteForReasons; use AntispamBee\PostProcessors\SaveReason; @@ -74,6 +78,43 @@ function init() { call_user_func( [ $module, 'init' ] ); } } + + // Todo: Allow to give values instead of callables. Test for return types. + // Todo: Write a doc how to implement a custom rule and postprocessor. + add_filter( 'asb_rules', function( $rules ) { + $rule = []; + $rule['verifiable']['verify'] = function() { + return 1; + }; + $rule['verifiable']['get_name'] = function() { + return "Imaginary Rule"; + }; + $rule['verifiable']['get_weight'] = function() { + return 1000.0; + }; + $rule['verifiable']['get_slug'] = function() { + return 'imaginary_rule'; + }; + $rule['verifiable']['get_supported_types'] = function() { + return [ 'comment', 'webmention' ]; + }; + $rule['verifiable']['is_final'] = function() { + return true; + }; + + $rule['controllable']['get_label'] = function() { + return 'Imaginary Rule'; + }; + $rule['controllable']['get_description'] = function() { + return 'Description for our Imaginary Rule'; + }; + $rule['controllable']['get_description'] = function() { + return 'Description for our Imaginary Rule'; + }; + + $rules[] = $rule; + return $rules; + } ); } add_action( 'plugins_loaded', 'AntispamBee\init' ); From 68573cd466166222de857eb663db4273e8e58183 Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Thu, 14 Apr 2022 11:18:33 +0200 Subject: [PATCH 048/184] Further work on settings and interfaces --- lib/Admin/SettingsPage.php | 3 ++- lib/Handlers/Rules.php | 1 - lib/Helpers/InterfaceHelper.php | 30 ++++++++++++++++++++++++++---- lib/Helpers/Settings.php | 4 ---- lib/Rules/CountrySpam.php | 3 +++ lib/load.php | 30 ++++++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/lib/Admin/SettingsPage.php b/lib/Admin/SettingsPage.php index 53a1eda5..4e218e88 100644 --- a/lib/Admin/SettingsPage.php +++ b/lib/Admin/SettingsPage.php @@ -107,7 +107,8 @@ public function setup_settings() { ] ); // Todo: Add a way to build rows and fields with a fluent interface? - // Todo: Fix the weird naming + // Todo: Fix the confusing naming. We have a lot of type e.g. + // Todo: Discuss if we want to remove that setting in V3 and maybe have a filter for that. // If we keep it, we have to add it to the comments tab. // new Checkbox( 'ab_use_output_buffer', esc_html( 'Check complete site markup for comment forms', 'antispam-bee' ), sprintf( /* translators: s=filter name */ esc_html( 'Uses output buffering instead of the %s filter.', 'antispam-bee' ), 'comment_form_field_comment' ) ), diff --git a/lib/Handlers/Rules.php b/lib/Handlers/Rules.php index 32f94ad1..a6fb7779 100644 --- a/lib/Handlers/Rules.php +++ b/lib/Handlers/Rules.php @@ -96,7 +96,6 @@ public static function filter( $rules, $options ) { continue; } - $conforms_to_controllable = isset( $rule['controllable'] ) ? InterfaceHelper::conforms_to_interface( $rule['controllable'], Controllable::class ) : false; if ( $only_controllables && ! $conforms_to_controllable ) { diff --git a/lib/Helpers/InterfaceHelper.php b/lib/Helpers/InterfaceHelper.php index 28ff6aa4..6697f907 100644 --- a/lib/Helpers/InterfaceHelper.php +++ b/lib/Helpers/InterfaceHelper.php @@ -4,16 +4,38 @@ class InterfaceHelper { - // Todo: adapt method because the methods have to be stored under the verifiable key + // Todo: adapt class methods because the callable methods now have to be stored under the interface key + /** + * Tries to call a method with different approaches. Firstly it tries to call it via object/fqn and method name. + * Next it tries to call the array element directly. At least it returns the value of the node. + * + * @param array $array + * @param string $interface + * @param string $method + * @param array $args + * + * @return mixed|null + */ public static function call( $array, $interface, $method, $args = [] ) { - $callable = isset( $array[ $interface ][ $method ] ) ? $array[ $interface ][ $method ] : null; + // Just return if there is no interface key in the array + if ( ! isset ( $array[ $interface ] ) ) { + return null; + } + + // Call the method if it is an object or fully qualified name and the method is callable + $callable = [ $array[ $interface ], $method ]; if ( is_callable( $callable ) ) { return call_user_func( $callable, $args ); } - if ( isset( $array[ $interface ] ) && is_callable( array( $array[ $interface ], $method ) ) ) { - return call_user_func( [ $array[ $interface ], $method ], $args ); + // Call the method if the callable is stored in the array + $callable = isset( $array[ $interface ][ $method ] ) ? $array[ $interface ][ $method ] : null; + if ( is_callable( $callable ) ) { + return call_user_func( $callable, $args ); } + + // Return the value at least, if nothing other works + return $callable; } public static function class_implements_interface( $class_name, $interface ) { diff --git a/lib/Helpers/Settings.php b/lib/Helpers/Settings.php index 0539bb84..67932082 100644 --- a/lib/Helpers/Settings.php +++ b/lib/Helpers/Settings.php @@ -116,10 +116,6 @@ public static function sanitize( $options ) { $options = ! empty( $options ) ? $options : [ $tab => [] ]; $current_options[ $tab ] = $options[ $tab ]; - echo '
';
-		var_dump( $options, $current_options );
-		echo '
'; - return $current_options; } } diff --git a/lib/Rules/CountrySpam.php b/lib/Rules/CountrySpam.php index 6cfd3aaf..40ff0fd2 100644 --- a/lib/Rules/CountrySpam.php +++ b/lib/Rules/CountrySpam.php @@ -19,6 +19,9 @@ public static function verify( $data ) { $ip = $data['comment_author_IP']; $options = Settings::get_options(); + if ( ! ( isset( $options['country_allowed'] ) && isset( $options['country_denied'] ) ) ) { + return 0; + } $allowed = preg_split( '/[\s,;]+/', diff --git a/lib/load.php b/lib/load.php index a2565f86..929658d3 100644 --- a/lib/load.php +++ b/lib/load.php @@ -81,6 +81,10 @@ function init() { // Todo: Allow to give values instead of callables. Test for return types. // Todo: Write a doc how to implement a custom rule and postprocessor. + // Todo: Remove the following code as it is only for testing the extendibility at the moment + /* + * Example with callables + * add_filter( 'asb_rules', function( $rules ) { $rule = []; $rule['verifiable']['verify'] = function() { @@ -115,6 +119,32 @@ function init() { $rules[] = $rule; return $rules; } ); + */ + + /* + * Example without callables + * + add_filter( 'asb_rules', function( $rules ) { + $rule = []; + $rule['verifiable']['verify'] = function() { + return 1; + }; + $rule['verifiable']['get_name'] = 'Imaginary Rule'; + $rule['verifiable']['get_weight'] = 1000.0; + $rule['verifiable']['get_slug'] = 'imaginary_rule'; + $rule['verifiable']['get_supported_types'] = [ 'comment', 'webmention' ]; + $rule['verifiable']['is_final'] = true; + + $rule['controllable']['get_label'] = 'Imaginary Rule'; + $rule['controllable']['get_description'] = 'Description for our Imaginary Rule'; + $rule['controllable']['is_active'] = function( $type ) { + return true; + }; + + $rules[] = $rule; + return $rules; + } ); + */ } add_action( 'plugins_loaded', 'AntispamBee\init' ); From 285f4d557ed8e52a479ac96988b3eac0607b096a Mon Sep 17 00:00:00 2001 From: Angelo Cali Date: Thu, 14 Apr 2022 18:17:25 +0200 Subject: [PATCH 049/184] Add PostProcessors, general settings, inline fields --- lib/Admin/Fields/Checkbox.php | 12 ++- lib/Admin/Fields/CheckboxGroup.php | 34 ++++++- lib/Admin/Fields/Field.php | 1 + lib/Admin/Fields/Inline.php | 25 +++++ lib/Admin/Fields/Text.php | 35 ++++++- lib/Admin/Section.php | 24 ++--- lib/Admin/SettingsPage.php | 74 +++++++++++---- lib/Handlers/PostProcessors.php | 62 ++++--------- lib/Handlers/Rules.php | 72 +++------------ lib/Helpers/Components.php | 64 +++++++++++++ lib/Helpers/InterfaceHelper.php | 112 +++++------------------ lib/Interfaces/Controllable.php | 2 + lib/Interfaces/Verifiable.php | 2 - lib/PostProcessors/Delete.php | 10 +- lib/PostProcessors/DeleteForReasons.php | 39 +++++++- lib/PostProcessors/InitPostProcessor.php | 14 +-- lib/PostProcessors/SaveReason.php | 8 +- lib/PostProcessors/SendEmail.php | 4 + lib/PostProcessors/UpdateDailyStats.php | 2 +- lib/PostProcessors/UpdateSpamCount.php | 2 +- lib/PostProcessors/UpdateSpamLog.php | 2 +- lib/Rules/InitRule.php | 8 +- lib/load.php | 72 --------------- 23 files changed, 348 insertions(+), 332 deletions(-) create mode 100644 lib/Admin/Fields/Inline.php create mode 100644 lib/Helpers/Components.php diff --git a/lib/Admin/Fields/Checkbox.php b/lib/Admin/Fields/Checkbox.php index e9de1de8..1a416c5a 100644 --- a/lib/Admin/Fields/Checkbox.php +++ b/lib/Admin/Fields/Checkbox.php @@ -17,13 +17,17 @@ class Checkbox extends Field implements RenderElement { * Get HTML. */ public function render() { + $label = ! empty( $this->get_label() ) ? sprintf( + '', + esc_attr( $this->get_name() ), + esc_html( $this->get_label() ) + ) : ''; + printf( - '', + '%3$s', esc_attr( $this->get_name() ), checked( 'on', $this->get_value(), false ), - esc_html( $this->get_label() ) + $label ); $this->maybe_show_description(); } diff --git a/lib/Admin/Fields/CheckboxGroup.php b/lib/Admin/Fields/CheckboxGroup.php index 2254205a..49937ddd 100644 --- a/lib/Admin/Fields/CheckboxGroup.php +++ b/lib/Admin/Fields/CheckboxGroup.php @@ -3,16 +3,46 @@ namespace AntispamBee\Admin\Fields; use AntispamBee\Admin\RenderElement; +use AntispamBee\Helpers\Settings; /** * Checkbox field. */ class CheckboxGroup extends Field implements RenderElement { /** - * Get HTML. + * Render HTML. */ public function render() { - echo 'get_value(), false ) . ' />'; + $options = isset( $this->option['options'] ) ? $this->option['options'] : []; + if ( ! is_array( $options ) ) { + return; + } + + printf( + '

%s

', + $this->get_label() + ); + foreach ( $options as $key => $value ) { + printf( + '
', + esc_attr( $this->get_name() . '[' . $key . ']' ), + checked( 'on', $this->get_custom_value( $key ), false ), + esc_html( $value ) + ); + } $this->maybe_show_description(); } + + /** + * Get Value. + * + * @return mixed Value stored in database. + */ + protected function get_custom_value( $key ) { + $options = Settings::get_option( $this->option['option_name'], $this->type ); + + return isset ( $options[ $key ] ) ? $options[ $key ] : null; + } } diff --git a/lib/Admin/Fields/Field.php b/lib/Admin/Fields/Field.php index bf6dbc44..238b51ac 100644 --- a/lib/Admin/Fields/Field.php +++ b/lib/Admin/Fields/Field.php @@ -44,6 +44,7 @@ public function __construct( $type, $option ) { * @return string Name of the field. */ public function get_name() { + // Todo: Find a more descriptive name for option_name return str_replace( '-', '_', 'antispam_bee[' . $this->type . '][' . $this->option['option_name'] . ']' ); } diff --git a/lib/Admin/Fields/Inline.php b/lib/Admin/Fields/Inline.php new file mode 100644 index 00000000..85b18169 --- /dev/null +++ b/lib/Admin/Fields/Inline.php @@ -0,0 +1,25 @@ +option['input']; + $inject_markup = $inject_field_object->get_injectable_markup(); + $label_with_inline_field = sprintf( + $this->get_label(), + '' . $inject_markup . sprintf( + '