]>
Commit | Line | Data |
---|---|---|
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_url($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 | * @return mixed the new version code if available and greater, else 'false' | |
54 | */ | |
55 | public static function checkUpdate($currentVersion, | |
56 | $updateFile, | |
57 | $checkInterval, | |
58 | $enableCheck, | |
59 | $isLoggedIn, | |
60 | $branch='stable') | |
61 | { | |
62 | if (! $isLoggedIn) { | |
63 | // Do not check versions for visitors | |
64 | return false; | |
65 | } | |
66 | ||
67 | if (empty($enableCheck)) { | |
68 | // Do not check if the user doesn't want to | |
69 | return false; | |
70 | } | |
71 | ||
72 | if (is_file($updateFile) && (filemtime($updateFile) > time() - $checkInterval)) { | |
73 | // Shaarli has checked for updates recently - skip HTTP query | |
74 | $latestKnownVersion = file_get_contents($updateFile); | |
75 | ||
76 | if (version_compare($latestKnownVersion, $currentVersion) == 1) { | |
77 | return $latestKnownVersion; | |
78 | } | |
79 | return false; | |
80 | } | |
81 | ||
82 | if (! in_array($branch, self::$GIT_BRANCHES)) { | |
83 | throw new Exception( | |
84 | 'Invalid branch selected for updates: "' . $branch . '"' | |
85 | ); | |
86 | } | |
87 | ||
88 | // Late Static Binding allows overriding within tests | |
89 | // See http://php.net/manual/en/language.oop5.late-static-bindings.php | |
90 | $latestVersion = static::getLatestGitVersionCode( | |
91 | self::$GIT_URL . '/' . $branch . '/' . self::$VERSION_FILE | |
92 | ); | |
93 | ||
94 | if (! $latestVersion) { | |
95 | // Only update the file's modification date | |
96 | file_put_contents($updateFile, $currentVersion); | |
97 | return false; | |
98 | } | |
99 | ||
100 | // Update the file's content and modification date | |
101 | file_put_contents($updateFile, $latestVersion); | |
102 | ||
103 | if (version_compare($latestVersion, $currentVersion) == 1) { | |
104 | return $latestVersion; | |
105 | } | |
106 | ||
107 | return false; | |
108 | } | |
109 | ||
110 | /** | |
111 | * Checks the PHP version to ensure Shaarli can run | |
112 | * | |
113 | * @param string $minVersion minimum PHP required version | |
114 | * @param string $curVersion current PHP version (use PHP_VERSION) | |
115 | * | |
116 | * @throws Exception the PHP version is not supported | |
117 | */ | |
118 | public static function checkPHPVersion($minVersion, $curVersion) | |
119 | { | |
120 | if (version_compare($curVersion, $minVersion) < 0) { | |
121 | throw new Exception( | |
122 | 'Your PHP version is obsolete!' | |
123 | .' Shaarli requires at least PHP '.$minVersion.', and thus cannot run.' | |
124 | .' Your PHP version has known security vulnerabilities and should be' | |
125 | .' updated as soon as possible.' | |
126 | ); | |
127 | } | |
128 | } | |
129 | ||
130 | /** | |
131 | * Checks Shaarli has the proper access permissions to its resources | |
132 | * | |
133 | * @param array $globalConfig The $GLOBALS['config'] array | |
134 | * | |
135 | * @return array A list of the detected configuration issues | |
136 | */ | |
137 | public static function checkResourcePermissions($globalConfig) | |
138 | { | |
139 | $errors = array(); | |
140 | ||
141 | // Check script and template directories are readable | |
142 | foreach (array( | |
143 | 'application', | |
144 | 'inc', | |
145 | 'plugins', | |
146 | $globalConfig['RAINTPL_TPL'] | |
147 | ) as $path) { | |
148 | if (! is_readable(realpath($path))) { | |
149 | $errors[] = '"'.$path.'" directory is not readable'; | |
150 | } | |
151 | } | |
152 | ||
153 | // Check cache and data directories are readable and writeable | |
154 | foreach (array( | |
155 | $globalConfig['CACHEDIR'], | |
156 | $globalConfig['DATADIR'], | |
157 | $globalConfig['PAGECACHE'], | |
158 | $globalConfig['RAINTPL_TMP'] | |
159 | ) as $path) { | |
160 | if (! is_readable(realpath($path))) { | |
161 | $errors[] = '"'.$path.'" directory is not readable'; | |
162 | } | |
163 | if (! is_writable(realpath($path))) { | |
164 | $errors[] = '"'.$path.'" directory is not writable'; | |
165 | } | |
166 | } | |
167 | ||
168 | // Check configuration files are readable and writeable | |
169 | foreach (array( | |
170 | $globalConfig['CONFIG_FILE'], | |
171 | $globalConfig['DATASTORE'], | |
172 | $globalConfig['IPBANS_FILENAME'], | |
173 | $globalConfig['LOG_FILE'], | |
174 | $globalConfig['UPDATECHECK_FILENAME'] | |
175 | ) as $path) { | |
176 | if (! is_file(realpath($path))) { | |
177 | # the file may not exist yet | |
178 | continue; | |
179 | } | |
180 | ||
181 | if (! is_readable(realpath($path))) { | |
182 | $errors[] = '"'.$path.'" file is not readable'; | |
183 | } | |
184 | if (! is_writable(realpath($path))) { | |
185 | $errors[] = '"'.$path.'" file is not writable'; | |
186 | } | |
187 | } | |
188 | ||
189 | return $errors; | |
190 | } | |
191 | } |