PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.0.5
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.0.5
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / matomo.php
matomo Last commit date
app 2 years ago assets 2 years ago classes 2 years ago config 2 years ago languages 6 years ago node_modules 4 years ago plugins 2 years ago .htaccess 6 years ago LEGALNOTICE 2 years ago LICENSE 6 years ago matomo.php 2 years ago readme.txt 2 years ago shared.php 3 years ago uninstall.php 6 years ago wdio.conf.tracking.ts 2 years ago
matomo.php
304 lines
1 <?php
2 /**
3 * Plugin Name: Matomo Analytics - Ethical Stats. Powerful Insights.
4 * Description: The #1 Google Analytics alternative that gives you full control over your data and protects the privacy for your users. Free, secure and open.
5 * Author: Matomo
6 * Author URI: https://matomo.org
7 * Version: 5.0.5
8 * Domain Path: /languages
9 * WC requires at least: 2.4.0
10 * WC tested up to: 8.5.2
11 *
12 * Matomo - free/libre analytics platform
13 *
14 * @link https://matomo.org
15 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
16 * @package matomo
17 * phpcs:disable WordPress.Security.ValidatedSanitizedInput
18 * phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
19 * phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
20 */
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit; // if accessed directly
23 }
24
25 load_plugin_textdomain( 'matomo', false, basename( dirname( __FILE__ ) ) . '/languages' );
26
27 if ( ! defined( 'MATOMO_ANALYTICS_FILE' ) ) {
28 define( 'MATOMO_ANALYTICS_FILE', __FILE__ );
29 }
30
31 if ( ! defined( 'MATOMO_MARKETPLACE_PLUGIN_NAME' ) ) {
32 define( 'MATOMO_MARKETPLACE_PLUGIN_NAME', 'matomo-marketplace-for-wordpress/matomo-marketplace-for-wordpress.php' );
33 }
34
35 $GLOBALS['MATOMO_PLUGINS_ENABLED'] = array();
36
37 /** MATOMO_PLUGIN_FILES => used to check for updates etc */
38 $GLOBALS['MATOMO_PLUGIN_FILES'] = array( MATOMO_ANALYTICS_FILE );
39
40 function matomo_has_compatible_content_dir() {
41 if ( ! empty( $_SERVER['MATOMO_WP_ROOT_PATH'] )
42 && file_exists( rtrim( $_SERVER['MATOMO_WP_ROOT_PATH'], '/' ) . '/wp-load.php' ) ) {
43 return true;
44 }
45
46 if ( ! defined( 'WP_CONTENT_DIR' ) ) {
47 return false;
48 }
49
50 $content_dir = rtrim( rtrim( WP_CONTENT_DIR, '/' ), DIRECTORY_SEPARATOR );
51 $content_dir = wp_normalize_path( $content_dir );
52 $abs_path = wp_normalize_path( ABSPATH );
53
54 $abs_paths = array(
55 $abs_path . 'wp-content',
56 $abs_path . '/wp-content',
57 $abs_path . DIRECTORY_SEPARATOR . 'wp-content',
58 );
59
60 if ( in_array( $content_dir, $abs_paths, true ) ) {
61 return true;
62 }
63
64 $wpload_base = '../../../wp-load.php';
65 $wpload_full = dirname( __FILE__ ) . '/' . $wpload_base;
66 if ( file_exists( $wpload_full ) && is_readable( $wpload_full ) ) {
67 return true;
68 } elseif ( realpath( $wpload_full ) && file_exists( realpath( $wpload_full ) ) && is_readable( realpath( $wpload_full ) ) ) {
69 return true;
70 } elseif ( ! empty( $_SERVER['SCRIPT_FILENAME'] ) && file_exists( $_SERVER['SCRIPT_FILENAME'] ) ) {
71 // seems symlinked... eg the wp-content dir or wp-content/plugins dir is symlinked from some very much other place...
72 $wpload_full = dirname( $_SERVER['SCRIPT_FILENAME'] ) . '/' . $wpload_base;
73 if ( file_exists( $wpload_full ) ) {
74 return true;
75 } elseif ( realpath( $wpload_full ) && file_exists( realpath( $wpload_full ) ) ) {
76 return true;
77 } elseif ( file_exists( dirname( $_SERVER['SCRIPT_FILENAME'] ) ) . '/wp-load.php' ) {
78 return true;
79 }
80 }
81
82 // look in plugins directory if there is a config file for us
83 $wpload_config = dirname( __FILE__ ) . '/../matomo.wpload_dir.php';
84 if ( file_exists( $wpload_config ) && is_readable( $wpload_config ) ) {
85 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
86 $content = @file_get_contents( $wpload_config ); // we do not include that file for security reasons
87 if ( ! empty( $content ) ) {
88 $content = str_replace( array( '<?php', 'exit;' ), '', $content );
89 $content = preg_replace( '/\s/', '', $content );
90 $content = trim( ltrim( trim( $content ), '#' ) ); // the path may be commented out # /abs/path
91 if ( strpos( $content, DIRECTORY_SEPARATOR ) === 0 ) {
92 $wpload_file = rtrim( $content, DIRECTORY_SEPARATOR ) . '/wp-load.php';
93 return file_exists( $wpload_file ) && is_readable( $wpload_file );
94 }
95 }
96 }
97
98 return false;
99 }
100
101 function matomo_header_icon( $full = false ) {
102 $file = 'logo';
103 if ( $full ) {
104 $file = 'logo-full';
105 }
106 echo '<img height="32" src="' . esc_url( plugins_url( 'assets/img/' . $file . '.png', MATOMO_ANALYTICS_FILE ) ) . '" class="matomo-header-icon">';
107 }
108
109 function matomo_is_app_request() {
110 return ! empty( $_SERVER['SCRIPT_NAME'] )
111 && ( substr( $_SERVER['SCRIPT_NAME'], - 1 * strlen( 'matomo/app/index.php' ) ) === 'matomo/app/index.php' );
112 }
113
114 function matomo_has_tag_manager() {
115 if ( defined( 'MATOMO_ENABLE_TAG_MANAGER' ) ) {
116 return ! empty( MATOMO_ENABLE_TAG_MANAGER );
117 }
118
119 $is_multisite = function_exists( 'is_multisite' ) && is_multisite();
120 if ( $is_multisite ) {
121 return false;
122 }
123
124 return true;
125 }
126
127 function matomo_anonymize_value( $value ) {
128 if ( is_string( $value ) && ! empty( $value ) ) {
129 $values_to_anonymize = array(
130 ABSPATH => '$abs_path/',
131 str_replace( '/', '\/', ABSPATH ) => '$abs_path\/',
132 str_replace( '/', '\\', ABSPATH ) => '$abs_path\/',
133 WP_CONTENT_DIR => '$WP_CONTENT_DIR/',
134 str_replace( '/', '\\', WP_CONTENT_DIR ) => '$WP_CONTENT_DIR\\',
135 home_url() => '$home_url',
136 site_url() => '$site_url',
137 DB_PASSWORD => '$DB_PASSWORD',
138 DB_USER => '$DB_USER',
139 DB_HOST => '$DB_HOST',
140 DB_NAME => '$DB_NAME',
141 );
142 $keys = array( 'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', 'AUTH_SALT', 'NONCE_KEY', 'SECURE_AUTH_SALT', 'LOGGED_IN_SALT', 'NONCE_SALT' );
143 foreach ( $keys as $key ) {
144 if ( defined( $key ) ) {
145 $const_value = constant( $key );
146 if ( ! empty( $const_value ) && is_string( $const_value ) && strlen( $key ) > 3 ) {
147 $values_to_anonymize[ $const_value ] = '$' . $key;
148 }
149 }
150 }
151 foreach ( $values_to_anonymize as $search => $replace ) {
152 if ( $search ) {
153 $value = str_replace( $search, $replace, $value );
154 }
155 }
156 // replace anything like token_auth etc or md5 or sha1 ...
157 $value = preg_replace( '/[[:xdigit:]]{31,80}/', 'TOKEN_REPLACED', $value );
158 }
159
160 return $value;
161 }
162
163 $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] = array();
164
165 function matomo_rel_path( $to_dir, $from_dir ) {
166 $to_dir_parts = array_values( array_filter( explode( DIRECTORY_SEPARATOR, $to_dir ) ) );
167 $from_dir_parts = array_values( array_filter( explode( DIRECTORY_SEPARATOR, $from_dir ) ) );
168
169 $to_index = 0;
170 $from_index = 0;
171
172 $to_dir_segment_count = count( $to_dir_parts );
173 $from_dir_segment_count = count( $from_dir_parts );
174
175 // skip over common parts of $to_dir and $from_dir
176 for ( ; $to_index < $to_dir_segment_count && $from_index < $from_dir_segment_count && $to_dir_parts[ $to_index ] === $from_dir_parts[ $from_index ]; ++$to_index, ++$from_index );
177
178 // ascend from $to_dir to common root it has with $from_dir
179 $relative_path = str_repeat( '..' . DIRECTORY_SEPARATOR, count( $from_dir_parts ) - $from_index );
180
181 // descend from common root to target in rest of $to_dir
182 $rest = array_slice( $to_dir_parts, $to_index );
183 if ( ! empty( $rest ) ) {
184 $relative_path = $relative_path . implode( DIRECTORY_SEPARATOR, $rest );
185 }
186
187 return $relative_path;
188 }
189
190 function matomo_is_plugin_compatible( $wp_plugin_file ) {
191 require_once __DIR__ . '/app/core/Version.php';
192
193 $plugin_manifest_path = dirname( $wp_plugin_file ) . '/plugin.json';
194 clearstatcache( false, $plugin_manifest_path );
195
196 if ( ! is_file( $plugin_manifest_path )
197 || ! is_readable( $plugin_manifest_path )
198 ) {
199 return false;
200 }
201
202 $modified_time = filemtime( $plugin_manifest_path );
203 if ( false === $modified_time ) {
204 return false;
205 }
206
207 $cache_key = 'matomo_plugin_compatible_' . basename( $wp_plugin_file ) . '_' . \Piwik\Version::VERSION . '_' . $modified_time;
208 $cache_value = get_transient( $cache_key );
209 if ( false === $cache_value ) {
210 // assume the plugin is not compatible in case the below code fails.
211 // this way, the next request will work rather than trigger the same
212 // error.
213 $one_day = 24 * 60 * 60;
214 set_transient( $cache_key, 0, $one_day );
215
216 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
217 $plugin_manifest = file_get_contents( $plugin_manifest_path );
218 $plugin_manifest = json_decode( $plugin_manifest, true );
219 if ( empty( $plugin_manifest['require']['matomo'] )
220 && empty( $plugin_manifest['require']['piwik'] )
221 ) {
222 return false;
223 }
224
225 $core_requirement = isset( $plugin_manifest['require']['matomo'] )
226 ? $plugin_manifest['require']['matomo']
227 : $plugin_manifest['require']['piwik'];
228
229 require_once __DIR__ . '/app/vendor/autoload.php';
230
231 $dependency = new \Piwik\Plugin\Dependency();
232 $missing_dependencies = $dependency->getMissingDependencies( [ 'matomo' => $core_requirement ] );
233
234 $is_compatible = empty( $missing_dependencies );
235 $cache_value = (int) $is_compatible;
236
237 $two_months = 60 * 60 * 24 * 60;
238 set_transient( $cache_key, $cache_value, $two_months );
239 }
240
241 return 1 === (int) $cache_value;
242 }
243
244 function matomo_filter_incompatible_plugins( &$plugin_list ) {
245 if ( empty( $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] ) ) {
246 return;
247 }
248
249 $incompatible_plugins = [];
250 foreach ( $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] as $wp_plugin_file ) {
251 if ( matomo_is_plugin_compatible( $wp_plugin_file ) ) {
252 continue;
253 }
254
255 $plugin_name = basename( dirname( $wp_plugin_file ) );
256 $incompatible_plugins[] = $plugin_name;
257 }
258
259 $plugin_list = array_values( array_diff( $plugin_list, $incompatible_plugins ) );
260 }
261
262 function matomo_add_plugin( $plugins_directory, $wp_plugin_file, $is_marketplace_plugin = false ) {
263 if ( ! in_array( $wp_plugin_file, $GLOBALS['MATOMO_PLUGIN_FILES'], true ) ) {
264 $GLOBALS['MATOMO_PLUGIN_FILES'][] = $wp_plugin_file;
265 }
266
267 if ( empty( $GLOBALS['MATOMO_PLUGIN_DIRS'] ) ) {
268 $GLOBALS['MATOMO_PLUGIN_DIRS'] = array();
269 }
270
271 if ( $is_marketplace_plugin && dirname( $wp_plugin_file ) === $plugins_directory ) {
272 $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'][] = $wp_plugin_file;
273 }
274
275 $GLOBALS['MATOMO_PLUGINS_ENABLED'][] = basename( $plugins_directory );
276 $root_dir = dirname( $plugins_directory );
277 foreach ( $GLOBALS['MATOMO_PLUGIN_DIRS'] as $path ) {
278 if ( $path['pluginsPathAbsolute'] === $root_dir ) {
279 return; // already added
280 }
281 }
282
283 $matomo_dir = __DIR__ . DIRECTORY_SEPARATOR . 'app';
284 $webroot_dir = matomo_rel_path( $root_dir, $matomo_dir );
285
286 $GLOBALS['MATOMO_PLUGIN_DIRS'][] = array(
287 'pluginsPathAbsolute' => $root_dir,
288 'webrootDirRelativeToMatomo' => $webroot_dir,
289 );
290 }
291
292 if ( matomo_is_app_request() || ! empty( $GLOBALS['MATOMO_LOADED_DIRECTLY'] ) ) {
293 // prevent layout being broken when thegem theme is used. their lazy items class causes the reporting UI to not appear
294 // because it creates a JS error because of escaping " too often. only breaks when " Activate image loading optimization (for desktops)"
295 // is enabled in the general theme settings
296 add_filter( 'thegem_lazy_items_need_process_content', '__return_false', 99999999, $args = 0 );
297 }
298
299 require_once __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'WpMatomo.php';
300 require 'shared.php';
301 matomo_add_plugin( __DIR__ . '/plugins/WordPress', MATOMO_ANALYTICS_FILE );
302
303 new WpMatomo();
304