]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - application/ApplicationUtils.php
e67b29021504ccada967da6dea47d191aa5f6b67
[github/shaarli/Shaarli.git] / application / ApplicationUtils.php
1 <?php
2 /**
3 * Shaarli (application) utilities
4 */
5 class ApplicationUtils
6 {
7 private static $GIT_URL = 'https://raw.githubusercontent.com/shaarli/Shaarli';
8 private static $GIT_BRANCHES = array('master', 'stable');
9 private static $VERSION_FILE = 'shaarli_version.php';
10 private static $VERSION_START_TAG = '<?php /* ';
11 private static $VERSION_END_TAG = ' */ ?>';
12
13 /**
14 * Gets the latest version code from the Git repository
15 *
16 * The code is read from the raw content of the version file on the Git server.
17 *
18 * @return mixed the version code from the repository if available, else 'false'
19 */
20 public static function getLatestGitVersionCode($url, $timeout=2)
21 {
22 list($headers, $data) = get_http_response($url, $timeout);
23
24 if (strpos($headers[0], '200 OK') === false) {
25 error_log('Failed to retrieve ' . $url);
26 return false;
27 }
28
29 return str_replace(
30 array(self::$VERSION_START_TAG, self::$VERSION_END_TAG, PHP_EOL),
31 array('', '', ''),
32 $data
33 );
34 }
35
36 /**
37 * Checks if a new Shaarli version has been published on the Git repository
38 *
39 * Updates checks are run periodically, according to the following criteria:
40 * - the update checks are enabled (install, global config);
41 * - the user is logged in (or this is an open instance);
42 * - the last check is older than a given interval;
43 * - the check is non-blocking if the HTTPS connection to Git fails;
44 * - in case of failure, the update file's modification date is updated,
45 * to avoid intempestive connection attempts.
46 *
47 * @param string $currentVersion the current version code
48 * @param string $updateFile the file where to store the latest version code
49 * @param int $checkInterval the minimum interval between update checks (in seconds
50 * @param bool $enableCheck whether to check for new versions
51 * @param bool $isLoggedIn whether the user is logged in
52 *
53 * @throws Exception an invalid branch has been set for update checks
54 *
55 * @return mixed the new version code if available and greater, else 'false'
56 */
57 public static function checkUpdate($currentVersion,
58 $updateFile,
59 $checkInterval,
60 $enableCheck,
61 $isLoggedIn,
62 $branch='stable')
63 {
64 if (! $isLoggedIn) {
65 // Do not check versions for visitors
66 return false;
67 }
68
69 if (empty($enableCheck)) {
70 // Do not check if the user doesn't want to
71 return false;
72 }
73
74 if (is_file($updateFile) && (filemtime($updateFile) > time() - $checkInterval)) {
75 // Shaarli has checked for updates recently - skip HTTP query
76 $latestKnownVersion = file_get_contents($updateFile);
77
78 if (version_compare($latestKnownVersion, $currentVersion) == 1) {
79 return $latestKnownVersion;
80 }
81 return false;
82 }
83
84 if (! in_array($branch, self::$GIT_BRANCHES)) {
85 throw new Exception(
86 'Invalid branch selected for updates: "' . $branch . '"'
87 );
88 }
89
90 // Late Static Binding allows overriding within tests
91 // See http://php.net/manual/en/language.oop5.late-static-bindings.php
92 $latestVersion = static::getLatestGitVersionCode(
93 self::$GIT_URL . '/' . $branch . '/' . self::$VERSION_FILE
94 );
95
96 if (! $latestVersion) {
97 // Only update the file's modification date
98 file_put_contents($updateFile, $currentVersion);
99 return false;
100 }
101
102 // Update the file's content and modification date
103 file_put_contents($updateFile, $latestVersion);
104
105 if (version_compare($latestVersion, $currentVersion) == 1) {
106 return $latestVersion;
107 }
108
109 return false;
110 }
111
112 /**
113 * Checks the PHP version to ensure Shaarli can run
114 *
115 * @param string $minVersion minimum PHP required version
116 * @param string $curVersion current PHP version (use PHP_VERSION)
117 *
118 * @throws Exception the PHP version is not supported
119 */
120 public static function checkPHPVersion($minVersion, $curVersion)
121 {
122 if (version_compare($curVersion, $minVersion) < 0) {
123 throw new Exception(
124 'Your PHP version is obsolete!'
125 .' Shaarli requires at least PHP '.$minVersion.', and thus cannot run.'
126 .' Your PHP version has known security vulnerabilities and should be'
127 .' updated as soon as possible.'
128 );
129 }
130 }
131
132 /**
133 * Checks Shaarli has the proper access permissions to its resources
134 *
135 * @param ConfigManager $conf Configuration Manager instance.
136 *
137 * @return array A list of the detected configuration issues
138 */
139 public static function checkResourcePermissions($conf)
140 {
141 $errors = array();
142
143 // Check script and template directories are readable
144 foreach (array(
145 'application',
146 'inc',
147 'plugins',
148 $conf->get('resource.raintpl_tpl'),
149 ) as $path) {
150 if (! is_readable(realpath($path))) {
151 $errors[] = '"'.$path.'" directory is not readable';
152 }
153 }
154
155 // Check cache and data directories are readable and writeable
156 foreach (array(
157 $conf->get('resource.thumbnails_cache'),
158 $conf->get('resource.data_dir'),
159 $conf->get('resource.page_cache'),
160 $conf->get('resource.raintpl_tmp'),
161 ) as $path) {
162 if (! is_readable(realpath($path))) {
163 $errors[] = '"'.$path.'" directory is not readable';
164 }
165 if (! is_writable(realpath($path))) {
166 $errors[] = '"'.$path.'" directory is not writable';
167 }
168 }
169
170 // Check configuration files are readable and writeable
171 foreach (array(
172 $conf->getConfigFileExt(),
173 $conf->get('resource.datastore'),
174 $conf->get('resource.ban_file'),
175 $conf->get('resource.log'),
176 $conf->get('resource.update_check'),
177 ) as $path) {
178 if (! is_file(realpath($path))) {
179 # the file may not exist yet
180 continue;
181 }
182
183 if (! is_readable(realpath($path))) {
184 $errors[] = '"'.$path.'" file is not readable';
185 }
186 if (! is_writable(realpath($path))) {
187 $errors[] = '"'.$path.'" file is not writable';
188 }
189 }
190
191 return $errors;
192 }
193 }