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