API
1 year ago
Access
1 year ago
Application
1 year ago
Archive
1 year ago
ArchiveProcessor
1 year ago
Archiver
2 years ago
AssetManager
1 year ago
Auth
1 year ago
Category
2 years ago
Changes
1 year ago
CliMulti
1 year ago
Columns
1 year ago
Concurrency
1 year ago
Config
1 year ago
Container
1 year ago
CronArchive
1 year ago
DataAccess
1 year ago
DataFiles
2 years ago
DataTable
1 year ago
Db
1 year ago
DeviceDetector
1 year ago
Email
2 years ago
Exception
1 year ago
Http
1 year ago
Intl
1 year ago
Log
2 years ago
Mail
1 year ago
Measurable
1 year ago
Menu
1 year ago
Metrics
1 year ago
Notification
1 year ago
Period
1 year ago
Plugin
1 year ago
ProfessionalServices
1 year ago
Report
1 year ago
ReportRenderer
1 year ago
Scheduler
1 year ago
Segment
1 year ago
Session
1 year ago
Settings
1 year ago
Tracker
1 year ago
Translation
1 year ago
Twig
1 year ago
UpdateCheck
1 year ago
Updater
1 year ago
Updates
1 year ago
Validators
1 year ago
View
1 year ago
ViewDataTable
1 year ago
Visualization
1 year ago
Widget
1 year ago
.htaccess
2 years ago
Access.php
1 year ago
Archive.php
1 year ago
ArchiveProcessor.php
1 year ago
AssetManager.php
1 year ago
Auth.php
2 years ago
AuthResult.php
2 years ago
BaseFactory.php
2 years ago
Cache.php
2 years ago
CacheId.php
1 year ago
CliMulti.php
1 year ago
Common.php
1 year ago
Config.php
1 year ago
Console.php
1 year ago
Context.php
2 years ago
Cookie.php
1 year ago
CronArchive.php
1 year ago
DI.php
1 year ago
DataArray.php
1 year ago
DataTable.php
1 year ago
Date.php
1 year ago
Db.php
1 year ago
DbHelper.php
1 year ago
Development.php
1 year ago
ErrorHandler.php
1 year ago
EventDispatcher.php
1 year ago
ExceptionHandler.php
1 year ago
FileIntegrity.php
1 year ago
Filechecks.php
1 year ago
Filesystem.php
1 year ago
FrontController.php
1 year ago
Http.php
1 year ago
IP.php
1 year ago
Log.php
2 years ago
LogDeleter.php
1 year ago
Mail.php
1 year ago
Metrics.php
1 year ago
NoAccessException.php
2 years ago
Nonce.php
1 year ago
Notification.php
1 year ago
NumberFormatter.php
1 year ago
Option.php
1 year ago
Period.php
1 year ago
Piwik.php
1 year ago
Plugin.php
1 year ago
Process.php
1 year ago
Profiler.php
1 year ago
ProxyHeaders.php
2 years ago
ProxyHttp.php
1 year ago
QuickForm2.php
1 year ago
RankingQuery.php
1 year ago
ReportRenderer.php
1 year ago
Request.php
1 year ago
Segment.php
1 year ago
Sequence.php
2 years ago
Session.php
1 year ago
SettingsPiwik.php
1 year ago
SettingsServer.php
1 year ago
Singleton.php
2 years ago
Site.php
1 year ago
SiteContentDetector.php
1 year ago
SupportedBrowser.php
2 years ago
TCPDF.php
1 year ago
Theme.php
1 year ago
Timer.php
2 years ago
Tracker.php
1 year ago
Twig.php
1 year ago
Unzip.php
1 year ago
UpdateCheck.php
1 year ago
Updater.php
1 year ago
UpdaterErrorException.php
2 years ago
Updates.php
1 year ago
Url.php
1 year ago
UrlHelper.php
1 year ago
Version.php
1 year ago
View.php
1 year ago
bootstrap.php
1 year ago
dispatch.php
2 years ago
testMinimumPhpVersion.php
2 years ago
Filechecks.php
211 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Matomo - free/libre analytics platform |
| 5 | * |
| 6 | * @link https://matomo.org |
| 7 | * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later |
| 8 | */ |
| 9 | namespace Piwik; |
| 10 | |
| 11 | use Piwik\Exception\MissingFilePermissionException; |
| 12 | class Filechecks |
| 13 | { |
| 14 | /** |
| 15 | * Check if this installation can be auto-updated. |
| 16 | * For performance, we look for clues rather than an exhaustive test. |
| 17 | * |
| 18 | * @return bool |
| 19 | */ |
| 20 | public static function canAutoUpdate() |
| 21 | { |
| 22 | if (!is_writable(PIWIK_INCLUDE_PATH . '/') || !is_writable(PIWIK_DOCUMENT_ROOT . '/index.php') || !is_writable(PIWIK_INCLUDE_PATH . '/core') || !is_writable(PIWIK_DOCUMENT_ROOT . '/config/global.ini.php')) { |
| 23 | return \false; |
| 24 | } |
| 25 | return \true; |
| 26 | } |
| 27 | /** |
| 28 | * Checks if directories are writable and create them if they do not exist. |
| 29 | * |
| 30 | * @param array $directoriesToCheck array of directories to check - if not given default Piwik directories that needs write permission are checked |
| 31 | * @return array directory name => true|false (is writable) |
| 32 | */ |
| 33 | public static function checkDirectoriesWritable($directoriesToCheck) |
| 34 | { |
| 35 | $resultCheck = array(); |
| 36 | foreach ($directoriesToCheck as $directoryToCheck) { |
| 37 | \Piwik\Filesystem::mkdir($directoryToCheck); |
| 38 | $directory = \Piwik\Filesystem::realpath($directoryToCheck); |
| 39 | if ($directory !== \false) { |
| 40 | $resultCheck[$directory] = is_writable($directoryToCheck); |
| 41 | } |
| 42 | } |
| 43 | return $resultCheck; |
| 44 | } |
| 45 | /** |
| 46 | * Checks that the directories Piwik needs write access are actually writable |
| 47 | * Displays a nice error page if permissions are missing on some directories |
| 48 | * |
| 49 | * @param array $directoriesToCheck Array of directory names to check |
| 50 | */ |
| 51 | public static function dieIfDirectoriesNotWritable($directoriesToCheck = null) |
| 52 | { |
| 53 | $resultCheck = self::checkDirectoriesWritable($directoriesToCheck); |
| 54 | if (array_search(\false, $resultCheck) === \false) { |
| 55 | return; |
| 56 | } |
| 57 | $directoryList = ''; |
| 58 | foreach ($resultCheck as $dir => $bool) { |
| 59 | $realpath = \Piwik\Filesystem::realpath($dir); |
| 60 | if (!empty($realpath) && $bool === \false) { |
| 61 | $directoryList .= self::getMakeWritableCommand($realpath); |
| 62 | } |
| 63 | } |
| 64 | // Also give the chown since the chmod is only 755 |
| 65 | if (!\Piwik\SettingsServer::isWindows()) { |
| 66 | $realpath = \Piwik\Filesystem::realpath(PIWIK_INCLUDE_PATH . '/'); |
| 67 | $directoryList = "<code>chown -R " . self::getUserAndGroup() . " " . $realpath . "</code><br />" . $directoryList; |
| 68 | } |
| 69 | $optionalUserInfo = ''; |
| 70 | if (function_exists('shell_exec')) { |
| 71 | $currentUser = self::getUser(); |
| 72 | if (!empty($currentUser)) { |
| 73 | $optionalUserInfo = " (running as user '" . $currentUser . "')"; |
| 74 | } |
| 75 | } |
| 76 | $directoryMessage = "<p><b>Matomo couldn't write to some directories {$optionalUserInfo}</b>.</p>"; |
| 77 | $directoryMessage .= "<p>Try to Execute the following commands on your server, to allow Write access on these directories" . ":</p>" . "<blockquote>{$directoryList}</blockquote>" . "<p>If this doesn't work, you can try to create the directories with your FTP software, and set the CHMOD to 0755 (or 0777 if 0755 is not enough). To do so with your FTP software, right click on the directories then click permissions.</p>" . "<p>After applying the modifications, you can <a href='index.php'>refresh the page</a>.</p>" . "<p>If you need more help, try <a target='_blank' rel='noreferrer noopener' href='https://matomo.org'>Matomo.org</a>.</p>"; |
| 78 | $ex = new MissingFilePermissionException($directoryMessage); |
| 79 | $ex->setIsHtmlMessage(); |
| 80 | throw $ex; |
| 81 | } |
| 82 | /** |
| 83 | * Returns the help message when the auto update can't run because of missing permissions |
| 84 | * |
| 85 | * @return string |
| 86 | */ |
| 87 | public static function getAutoUpdateMakeWritableMessage() |
| 88 | { |
| 89 | $realpath = \Piwik\Filesystem::realpath(PIWIK_INCLUDE_PATH . '/'); |
| 90 | $message = ''; |
| 91 | if (!\Piwik\SettingsServer::isWindows()) { |
| 92 | $message .= "<br /><code>" . self::getCommandToChangeOwnerOfPiwikFiles() . "</code><br />"; |
| 93 | } |
| 94 | $message .= self::getMakeWritableCommand($realpath); |
| 95 | if (!\Piwik\SettingsServer::isWindows()) { |
| 96 | $message .= '<code>chmod 755 ' . $realpath . '/console</code><br />'; |
| 97 | } |
| 98 | $message .= 'After you execute these commands (or change permissions via your FTP software), refresh the page and you should be able to use the "Automatic Update" feature.'; |
| 99 | return $message; |
| 100 | } |
| 101 | /** |
| 102 | * Returns friendly error message explaining how to fix permissions |
| 103 | * |
| 104 | * @param string $path to the directory missing permissions |
| 105 | * @return string Error message |
| 106 | */ |
| 107 | public static function getErrorMessageMissingPermissions($path) |
| 108 | { |
| 109 | $message = "Please check that the web server has enough permission to write to these files/directories:<br />"; |
| 110 | if (\Piwik\SettingsServer::isWindows()) { |
| 111 | $message .= "On Windows, check that the folder is not read only and is writable.\n\n\t\t\t\t\t\tYou can try to execute:<br />"; |
| 112 | } else { |
| 113 | $message .= "For example, on a GNU/Linux server if your Apache httpd user is " . \Piwik\Common::sanitizeInputValue(self::getUser()) . ", you can try to execute:<br />\n" . "<code>chown -R " . \Piwik\Common::sanitizeInputValue(self::getUserAndGroup()) . " " . \Piwik\Common::sanitizeInputValue($path) . "</code><br />"; |
| 114 | } |
| 115 | $message .= self::getMakeWritableCommand($path); |
| 116 | return $message; |
| 117 | } |
| 118 | public static function getUserAndGroup() |
| 119 | { |
| 120 | $user = self::getUser(); |
| 121 | if (!function_exists('shell_exec')) { |
| 122 | return $user . ':' . $user; |
| 123 | } |
| 124 | $group = trim(shell_exec('groups ' . $user . ' | cut -f3 -d" "') ?? ''); |
| 125 | if (empty($group) && function_exists('posix_getegid') && function_exists('posix_getgrgid')) { |
| 126 | $currentGroupId = posix_getegid(); |
| 127 | $group = posix_getpwuid($currentGroupId); |
| 128 | if (!empty($group['name'])) { |
| 129 | $group = $group['name']; |
| 130 | } else { |
| 131 | $group = $currentGroupId; |
| 132 | } |
| 133 | } |
| 134 | if (empty($group)) { |
| 135 | $group = 'www-data'; |
| 136 | } |
| 137 | return $user . ':' . $group; |
| 138 | } |
| 139 | public static function getUser() |
| 140 | { |
| 141 | if (function_exists('shell_exec')) { |
| 142 | return trim(shell_exec('whoami') ?? ''); |
| 143 | } |
| 144 | $currentUser = get_current_user(); |
| 145 | if (empty($currentUser) && function_exists('posix_geteuid') && function_exists('posix_getpwuid')) { |
| 146 | $currentUserId = posix_geteuid(); |
| 147 | $user = posix_getpwuid($currentUserId); |
| 148 | if (!empty($user['name'])) { |
| 149 | $currentUser = $user['name']; |
| 150 | } else { |
| 151 | $currentUser = $currentUserId; |
| 152 | } |
| 153 | } |
| 154 | if (empty($currentUser)) { |
| 155 | $currentUser = 'www-data'; |
| 156 | } |
| 157 | return $currentUser; |
| 158 | } |
| 159 | /** |
| 160 | * Returns the help text displayed to suggest which command to run to give writable access to a file or directory |
| 161 | * |
| 162 | * @param string $realpath |
| 163 | * @return string |
| 164 | */ |
| 165 | private static function getMakeWritableCommand($realpath) |
| 166 | { |
| 167 | $realpath = \Piwik\Common::sanitizeInputValue($realpath); |
| 168 | if (\Piwik\SettingsServer::isWindows()) { |
| 169 | return "<code>cacls {$realpath} /t /g " . \Piwik\Common::sanitizeInputValue(self::getUser()) . ":f</code><br />\n"; |
| 170 | } |
| 171 | return "<code>find {$realpath} -type f -exec chmod 644 {} \\;</code><br /><code>find {$realpath} -type d -exec chmod 755 {} \\;</code><br />"; |
| 172 | } |
| 173 | /** |
| 174 | * @return string |
| 175 | */ |
| 176 | public static function getCommandToChangeOwnerOfPiwikFiles() |
| 177 | { |
| 178 | $realpath = \Piwik\Filesystem::realpath(PIWIK_INCLUDE_PATH . '/'); |
| 179 | return "chown -R " . self::getUserAndGroup() . " " . $realpath; |
| 180 | } |
| 181 | public static function getOwnerOfPiwikFiles() |
| 182 | { |
| 183 | $index = \Piwik\Filesystem::realpath(PIWIK_INCLUDE_PATH . '/index.php'); |
| 184 | $stat = stat($index); |
| 185 | if (!$stat) { |
| 186 | return ''; |
| 187 | } |
| 188 | if (function_exists('posix_getgrgid')) { |
| 189 | $group = posix_getgrgid($stat[5]); |
| 190 | if (!empty($group['name'])) { |
| 191 | $group = $group['name']; |
| 192 | } else { |
| 193 | $group = $stat[5]; |
| 194 | } |
| 195 | } else { |
| 196 | return ''; |
| 197 | } |
| 198 | if (function_exists('posix_getpwuid')) { |
| 199 | $user = posix_getpwuid($stat[4]); |
| 200 | if (!empty($user['name'])) { |
| 201 | $user = $user['name']; |
| 202 | } else { |
| 203 | $user = $stat[4]; |
| 204 | } |
| 205 | } else { |
| 206 | return ''; |
| 207 | } |
| 208 | return "{$user}:{$group}"; |
| 209 | } |
| 210 | } |
| 211 |