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