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