API
3 months ago
Access
3 months ago
Application
3 months ago
Archive
3 months ago
ArchiveProcessor
3 months ago
Archiver
2 years ago
AssetManager
3 months ago
Auth
6 months ago
Category
6 months ago
Changes
3 months ago
CliMulti
1 year ago
Columns
3 months ago
Concurrency
3 months ago
Config
3 months ago
Container
3 months ago
CronArchive
3 months ago
DataAccess
3 months ago
DataFiles
2 years ago
DataTable
3 months ago
Db
3 months ago
DeviceDetector
1 year ago
Email
2 years ago
Exception
4 months ago
Http
4 months ago
Intl
3 months ago
Log
2 years ago
Mail
1 year ago
Measurable
6 months ago
Menu
3 months ago
Metrics
3 months ago
Notification
6 months ago
Period
3 months ago
Plugin
3 months ago
Policy
3 months ago
ProfessionalServices
1 year ago
Report
1 year ago
ReportRenderer
3 months ago
Request
3 months ago
Scheduler
3 months ago
Segment
3 months ago
Session
3 months ago
Settings
3 months ago
Tracker
3 months ago
Translation
3 months ago
Twig
1 year ago
UpdateCheck
3 months ago
Updater
4 months ago
Updates
3 months ago
Validators
1 year ago
View
6 months ago
ViewDataTable
3 months ago
Visualization
1 year ago
Widget
3 months ago
.htaccess
2 years ago
Access.php
3 months ago
Archive.php
3 months ago
ArchiveProcessor.php
4 months ago
AssetManager.php
3 months ago
Auth.php
6 months ago
AuthResult.php
6 months ago
BaseFactory.php
2 years ago
Cache.php
2 years ago
CacheId.php
4 months ago
CliMulti.php
3 months ago
Common.php
3 months ago
Config.php
3 months ago
Console.php
3 months ago
Context.php
2 years ago
Cookie.php
1 year ago
CronArchive.php
3 months ago
DI.php
3 months ago
DataArray.php
5 months ago
DataTable.php
3 months ago
Date.php
3 months ago
Db.php
3 months ago
DbHelper.php
3 months ago
Development.php
1 year ago
ErrorHandler.php
6 months ago
EventDispatcher.php
1 year ago
ExceptionHandler.php
4 months ago
FileIntegrity.php
3 months ago
Filechecks.php
1 year ago
Filesystem.php
3 months ago
FrontController.php
4 months ago
Http.php
4 months ago
IP.php
1 year ago
Log.php
3 months ago
LogDeleter.php
1 year ago
Mail.php
1 year ago
Metrics.php
3 months ago
NoAccessException.php
2 years ago
Nonce.php
6 months ago
Notification.php
6 months ago
NumberFormatter.php
5 months ago
Option.php
5 months ago
Period.php
3 months ago
Piwik.php
3 months ago
Plugin.php
3 months ago
Process.php
1 year ago
Profiler.php
6 months ago
ProxyHeaders.php
4 months ago
ProxyHttp.php
5 months ago
QuickForm2.php
3 months ago
RankingQuery.php
5 months ago
ReportRenderer.php
3 months ago
Request.php
3 months ago
Segment.php
3 months ago
Sequence.php
6 months ago
Session.php
3 months ago
SettingsPiwik.php
3 months ago
SettingsServer.php
1 year ago
Singleton.php
2 years ago
Site.php
4 months ago
SiteContentDetector.php
3 months ago
SupportedBrowser.php
2 years ago
TCPDF.php
1 year ago
Theme.php
1 year ago
Timer.php
2 years ago
Tracker.php
3 months ago
Twig.php
3 months ago
Unzip.php
1 year ago
UpdateCheck.php
3 months ago
Updater.php
3 months ago
UpdaterErrorException.php
2 years ago
Updates.php
3 months ago
Url.php
3 months ago
UrlHelper.php
3 months ago
Version.php
3 months ago
View.php
3 months ago
bootstrap.php
1 year ago
dispatch.php
2 years ago
testMinimumPhpVersion.php
6 months 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 |