Admin
1 month ago
Commands
2 years ago
Db
1 year ago
Ecommerce
1 month ago
Report
2 months ago
Site
2 months ago
TrackingCode
4 months ago
Updater
4 years ago
User
2 months ago
Workarounds
2 years ago
WpStatistics
5 months ago
views
1 month ago
AIBotTracking.php
4 months ago
API.php
2 months ago
Access.php
4 years ago
AjaxTracker.php
4 months ago
Annotations.php
2 months ago
Bootstrap.php
10 months ago
Capabilities.php
2 months ago
Compatibility.php
2 months ago
Email.php
2 years ago
ErrorNotice.php
1 month ago
Feature.php
2 months ago
Installer.php
1 month ago
Logger.php
1 year ago
OptOut.php
1 month ago
Paths.php
5 months ago
PluginActionLinks.php
2 months ago
PluginAdminOverrides.php
2 months ago
PluginInit.php
2 months ago
PrivacyBadge.php
4 years ago
RedirectOnActivation.php
2 months ago
Referral.php
2 months ago
Roles.php
2 months ago
ScheduledTasks.php
2 months ago
Settings.php
4 months ago
Site.php
3 years ago
TrackingCode.php
2 months ago
Uninstaller.php
5 months ago
Updater.php
10 months ago
User.php
4 years ago
Paths.php
257 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Matomo - free/libre analytics platform |
| 4 | * |
| 5 | * @link https://matomo.org |
| 6 | * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later |
| 7 | * @package matomo |
| 8 | */ |
| 9 | |
| 10 | namespace WpMatomo; |
| 11 | |
| 12 | use stdClass; |
| 13 | use WP_Filesystem_Direct; |
| 14 | |
| 15 | if ( ! defined( 'ABSPATH' ) ) { |
| 16 | exit; // if accessed directly |
| 17 | } |
| 18 | |
| 19 | class Paths { |
| 20 | |
| 21 | private static $host_init_filesystem = false; |
| 22 | private static $host_init_filesystem_succeeded = false; |
| 23 | |
| 24 | public function get_file_system() { |
| 25 | if ( ! function_exists( 'WP_Filesystem' ) ) { |
| 26 | require_once ABSPATH . '/wp-admin/includes/file.php'; |
| 27 | } |
| 28 | |
| 29 | if ( ! self::$host_init_filesystem ) { |
| 30 | self::$host_init_filesystem = true; |
| 31 | self::$host_init_filesystem_succeeded = WP_Filesystem(); |
| 32 | } |
| 33 | |
| 34 | if ( ! class_exists( '\WP_Filesystem_Direct' ) ) { |
| 35 | require_once ABSPATH . '/wp-admin/includes/class-wp-filesystem-base.php'; |
| 36 | require_once ABSPATH . '/wp-admin/includes/class-wp-filesystem-direct.php'; |
| 37 | } |
| 38 | |
| 39 | return new WP_Filesystem_Direct( new stdClass() ); |
| 40 | } |
| 41 | |
| 42 | public function get_host_init_filesystem_succeeded() { |
| 43 | return self::$host_init_filesystem_succeeded; |
| 44 | } |
| 45 | |
| 46 | public function get_upload_base_url() { |
| 47 | $upload_dir = wp_upload_dir(); |
| 48 | $path_upload_url = $upload_dir['baseurl']; |
| 49 | |
| 50 | return rtrim( $path_upload_url, '/' ) . '/' . MATOMO_UPLOAD_DIR; |
| 51 | } |
| 52 | |
| 53 | public function get_upload_base_dir() { |
| 54 | $upload_dir = wp_upload_dir(); |
| 55 | $path_upload_dir = $upload_dir['basedir']; |
| 56 | $path_upload_dir = rtrim( $path_upload_dir, '/' ) . '/' . MATOMO_UPLOAD_DIR; |
| 57 | |
| 58 | return $path_upload_dir; |
| 59 | } |
| 60 | |
| 61 | public function get_matomo_js_upload_path() { |
| 62 | return $this->get_upload_base_dir() . '/' . MATOMO_JS_NAME; |
| 63 | } |
| 64 | |
| 65 | public function get_config_ini_path() { |
| 66 | return $this->get_upload_base_dir() . '/' . MATOMO_CONFIG_PATH; |
| 67 | } |
| 68 | |
| 69 | public function get_tracker_api_rest_api_endpoint() { |
| 70 | return path_join( get_rest_url(), API::VERSION . '/' . API::ROUTE_HIT . '/' ); |
| 71 | } |
| 72 | |
| 73 | public function get_tracker_api_url_in_matomo_dir() { |
| 74 | return plugins_url( 'app/matomo.php', MATOMO_ANALYTICS_FILE ); |
| 75 | } |
| 76 | |
| 77 | public function get_js_tracker_rest_api_endpoint() { |
| 78 | return $this->get_tracker_api_rest_api_endpoint(); |
| 79 | } |
| 80 | |
| 81 | public function get_js_tracker_url_in_matomo_dir() { |
| 82 | $paths = new Paths(); |
| 83 | |
| 84 | if ( file_exists( $paths->get_matomo_js_upload_path() ) ) { |
| 85 | return $this->get_upload_base_url() . '/' . MATOMO_JS_NAME; |
| 86 | } |
| 87 | |
| 88 | return plugins_url( 'app/matomo.js', MATOMO_ANALYTICS_FILE ); |
| 89 | } |
| 90 | |
| 91 | public function get_tmp_dir() { |
| 92 | $is_multi_site = function_exists( 'is_multisite' ) && is_multisite(); |
| 93 | |
| 94 | $cache_dir_alternative = $this->get_upload_base_dir() . '/tmp'; |
| 95 | $base_cache_dir = WP_CONTENT_DIR . '/cache'; |
| 96 | $default_cache_dir = $base_cache_dir . '/' . MATOMO_UPLOAD_DIR; |
| 97 | |
| 98 | if ( ! $is_multi_site && |
| 99 | ( ( is_writable( WP_CONTENT_DIR ) && ! is_dir( $base_cache_dir ) ) |
| 100 | || is_writable( $base_cache_dir ) ) ) { |
| 101 | // we prefer wp-content/cache |
| 102 | $cache_dir = $default_cache_dir; |
| 103 | |
| 104 | if ( ! is_dir( $cache_dir ) ) { |
| 105 | wp_mkdir_p( $cache_dir ); |
| 106 | } |
| 107 | |
| 108 | if ( ! is_writable( $cache_dir ) ) { |
| 109 | // wasn't made writable for some reason so we prefer to use the upload dir just to be safe |
| 110 | $cache_dir = $cache_dir_alternative; |
| 111 | } |
| 112 | } else { |
| 113 | // fallback wp-content/uploads/matomo/tmp if $defaultCacheDir is not writable or if multisite is used |
| 114 | // with multisite we need to make sure to cache files per site |
| 115 | $cache_dir = $cache_dir_alternative; |
| 116 | |
| 117 | if ( ! is_dir( $cache_dir ) ) { |
| 118 | wp_mkdir_p( $cache_dir ); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | return $cache_dir; |
| 123 | } |
| 124 | |
| 125 | /** |
| 126 | * parameter matomo_file is required for the unit test cases (when checking with a path including the string matomo) |
| 127 | * |
| 128 | * @param string $target_dir |
| 129 | * @param string $matomo_file |
| 130 | * |
| 131 | * @return string |
| 132 | */ |
| 133 | public function get_relative_dir_to_matomo( $target_dir, $matomo_file = MATOMO_ANALYTICS_FILE ) { |
| 134 | // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged |
| 135 | return matomo_rel_path( $target_dir, dirname( $matomo_file ) . '/app' ); |
| 136 | } |
| 137 | |
| 138 | public function get_gloal_upload_dir_if_possible( $file_to_look_for = '' ) { |
| 139 | if ( defined( 'MATOMO_GLOBAL_UPLOAD_DIR' ) ) { |
| 140 | return MATOMO_GLOBAL_UPLOAD_DIR; |
| 141 | } |
| 142 | |
| 143 | $path_upload_dir = $this->get_upload_base_dir(); |
| 144 | |
| 145 | if ( ! is_multisite() || is_network_admin() ) { |
| 146 | return $path_upload_dir; |
| 147 | } |
| 148 | |
| 149 | $global_path_upload_dir = $this->get_global_path_upload_dir_if_matches_site_specific_dir( $path_upload_dir ); |
| 150 | if ( ! empty( $global_path_upload_dir ) ) { |
| 151 | $path_upload_dir = $global_path_upload_dir; |
| 152 | } else { |
| 153 | // re-implement _wp_upload_dir to find hopefully the upload_dir for the network site |
| 154 | $upload_path = trim( get_option( 'upload_path' ) ); |
| 155 | if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) { |
| 156 | $path_upload_dir = WP_CONTENT_DIR . '/uploads'; |
| 157 | } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) { |
| 158 | // $dir is absolute, $upload_path is (maybe) relative to ABSPATH |
| 159 | $path_upload_dir = path_join( ABSPATH, $upload_path ); |
| 160 | } else { |
| 161 | $path_upload_dir = $upload_path; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | if ( ! empty( $file_to_look_for ) ) { |
| 166 | $file_to_look_for = MATOMO_UPLOAD_DIR . '/' . ltrim( $file_to_look_for, '/' ); |
| 167 | } |
| 168 | |
| 169 | $path_upload_dir = rtrim( $path_upload_dir, '/' ) . '/'; |
| 170 | if ( ! empty( $file_to_look_for ) |
| 171 | && ! file_exists( $path_upload_dir . $file_to_look_for ) ) { |
| 172 | // seems we haven't auto detected the right one yet... (or it is not yet installed) |
| 173 | // we go up the site upload dir step by step to try and find the network upload dir |
| 174 | $parent_dir = $path_upload_dir; |
| 175 | do { |
| 176 | $parent_dir = dirname( $parent_dir ); |
| 177 | $parent_dir = rtrim( $parent_dir, '/' ) . '/'; |
| 178 | // NOTE: file_exists here can trigger an open_basedir warning on some setups |
| 179 | // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged |
| 180 | if ( @file_exists( $parent_dir . $file_to_look_for ) ) { |
| 181 | return $parent_dir; |
| 182 | } |
| 183 | } while ( strpos( $parent_dir, ABSPATH ) === 0 ); // we don't go outside WP dir |
| 184 | } |
| 185 | |
| 186 | $path_upload_dir = rtrim( $path_upload_dir, '/' ) . '/' . MATOMO_UPLOAD_DIR; |
| 187 | |
| 188 | return $path_upload_dir; |
| 189 | } |
| 190 | |
| 191 | public function clear_assets_dir() { |
| 192 | $tmp_dir = $this->get_tmp_dir() . '/assets'; |
| 193 | if ( $tmp_dir && is_dir( $tmp_dir ) ) { |
| 194 | $file_system_direct = $this->get_file_system(); |
| 195 | $file_system_direct->rmdir( $tmp_dir, true ); |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | public function clear_cache_dir() { |
| 200 | $tmp_dir = $this->get_tmp_dir(); |
| 201 | if ( $tmp_dir |
| 202 | && is_dir( $tmp_dir ) |
| 203 | && is_dir( $tmp_dir . '/cache' ) ) { |
| 204 | // we make sure it's a matomo cache dir to not delete something falsely |
| 205 | $file_system_direct = $this->get_file_system(); |
| 206 | $file_system_direct->rmdir( $tmp_dir, true ); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | public function uninstall() { |
| 211 | $this->clear_cache_dir(); |
| 212 | |
| 213 | $dir = $this->get_upload_base_dir(); |
| 214 | |
| 215 | $file_system_direct = $this->get_file_system(); |
| 216 | $file_system_direct->rmdir( $dir, true ); |
| 217 | |
| 218 | $global_dir = $this->get_upload_base_dir(); |
| 219 | if ( $global_dir && $global_dir !== $dir ) { |
| 220 | $file_system_direct->rmdir( $dir ); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * Must be called after Paths::get_file_system(). |
| 226 | * |
| 227 | * @return bool |
| 228 | */ |
| 229 | public function is_upload_dir_writable() { |
| 230 | $upload_dir = $this->get_upload_base_dir(); |
| 231 | |
| 232 | // the WP direct filesystem abstraction may not be available based on user |
| 233 | // configuration. in this case, we can't write to the upload dir using WP_Filesystem |
| 234 | $is_filesystem_direct_available = defined( 'FS_CHMOD_FILE' ); |
| 235 | return is_dir( $upload_dir ) |
| 236 | && is_writable( $upload_dir ) |
| 237 | && $this->get_host_init_filesystem_succeeded() |
| 238 | && $is_filesystem_direct_available; |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * public for tests |
| 243 | * |
| 244 | * @param string $path_upload_dir |
| 245 | * @return string|null |
| 246 | */ |
| 247 | public function get_global_path_upload_dir_if_matches_site_specific_dir( $path_upload_dir ) { |
| 248 | $multisite_path_regex = '%sites/(\d)+/' . preg_quote( MATOMO_UPLOAD_DIR, '%' ) . '$%'; |
| 249 | |
| 250 | if ( ! preg_match( $multisite_path_regex, $path_upload_dir ) ) { |
| 251 | return null; |
| 252 | } |
| 253 | |
| 254 | return preg_replace( $multisite_path_regex, '', $path_upload_dir ); |
| 255 | } |
| 256 | } |
| 257 |