Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
232624b1 | 4 | | CiviCRM version 4.4 | |
6a488035 TO |
5 | +--------------------------------------------------------------------+ |
6 | | Copyright CiviCRM LLC (c) 2004-2013 | | |
7 | +--------------------------------------------------------------------+ | |
8 | | This file is a part of CiviCRM. | | |
9 | | | | |
10 | | CiviCRM is free software; you can copy, modify, and distribute it | | |
11 | | under the terms of the GNU Affero General Public License | | |
12 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | | |
13 | | | | |
14 | | CiviCRM is distributed in the hope that it will be useful, but | | |
15 | | WITHOUT ANY WARRANTY; without even the implied warranty of | | |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | |
17 | | See the GNU Affero General Public License for more details. | | |
18 | | | | |
19 | | You should have received a copy of the GNU Affero General Public | | |
20 | | License and the CiviCRM Licensing Exception along | | |
21 | | with this program; if not, contact CiviCRM LLC | | |
22 | | at info[AT]civicrm[DOT]org. If you have questions about the | | |
23 | | GNU Affero General Public License or the licensing of CiviCRM, | | |
24 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | | |
25 | +--------------------------------------------------------------------+ | |
26 | */ | |
27 | ||
28 | /** | |
29 | * | |
30 | * @package CRM | |
31 | * @copyright CiviCRM LLC (c) 2004-2013 | |
32 | * $Id: $ | |
33 | * | |
34 | */ | |
35 | class CRM_Utils_VersionCheck { | |
36 | CONST | |
37 | LATEST_VERSION_AT = 'http://latest.civicrm.org/stable.php', | |
38 | // timeout for when the connection or the server is slow | |
39 | CHECK_TIMEOUT = 5, | |
40 | // relative to $civicrm_root | |
41 | LOCALFILE_NAME = 'civicrm-version.php', | |
42 | // relative to $config->uploadDir | |
43 | CACHEFILE_NAME = 'latest-version-cache.txt', | |
42f366d7 CW |
44 | // cachefile expiry time (in seconds) - one day |
45 | CACHEFILE_EXPIRE = 86400; | |
6a488035 TO |
46 | |
47 | /** | |
48 | * We only need one instance of this object, so we use the | |
49 | * singleton pattern and cache the instance in this variable | |
50 | * | |
51 | * @var object | |
52 | * @static | |
53 | */ | |
54 | static private $_singleton = NULL; | |
55 | ||
56 | /** | |
57 | * The version of the current (local) installation | |
58 | * | |
59 | * @var string | |
60 | */ | |
61 | public $localVersion = NULL; | |
62 | ||
63 | /** | |
64 | * The latest version of CiviCRM | |
65 | * | |
66 | * @var string | |
67 | */ | |
68 | public $latestVersion = NULL; | |
69 | ||
70 | /** | |
71 | * Pingback params | |
72 | * | |
73 | * @var string | |
74 | */ | |
75 | protected $stats = array(); | |
76 | ||
77 | /** | |
78 | * Class constructor | |
79 | * | |
80 | * @access private | |
81 | */ | |
82 | function __construct() { | |
83 | global $civicrm_root; | |
84 | $config = CRM_Core_Config::singleton(); | |
85 | ||
86 | $localfile = $civicrm_root . DIRECTORY_SEPARATOR . self::LOCALFILE_NAME; | |
87 | $cachefile = $config->uploadDir . self::CACHEFILE_NAME; | |
88 | ||
89 | if (file_exists($localfile)) { | |
90 | require_once ($localfile); | |
91 | if (function_exists('civicrmVersion')) { | |
92 | $info = civicrmVersion(); | |
8edbc7e6 | 93 | $this->localVersion = trim($info['version']); |
6a488035 TO |
94 | } |
95 | } | |
96 | if ($config->versionCheck) { | |
97 | $expiryTime = time() - self::CACHEFILE_EXPIRE; | |
98 | ||
99 | // if there's a cachefile and it's not stale use it to | |
100 | // read the latestVersion, else read it from the Internet | |
101 | if (file_exists($cachefile) && (filemtime($cachefile) > $expiryTime)) { | |
8edbc7e6 | 102 | $this->latestVersion = trim(file_get_contents($cachefile)); |
6a488035 TO |
103 | } |
104 | else { | |
105 | $siteKey = md5(defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : ''); | |
106 | ||
107 | $this->stats = array( | |
108 | 'hash' => md5($siteKey . $config->userFrameworkBaseURL), | |
109 | 'version' => $this->localVersion, | |
110 | 'uf' => $config->userFramework, | |
111 | 'lang' => $config->lcMessages, | |
112 | 'co' => $config->defaultContactCountry, | |
113 | 'ufv' => $config->userFrameworkVersion, | |
114 | 'PHP' => phpversion(), | |
115 | 'MySQL' => CRM_CORE_DAO::singleValueQuery('SELECT VERSION()'), | |
187e57d9 | 116 | 'communityMessagesUrl' => CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'communityMessagesUrl', NULL, '*default*'), |
6a488035 TO |
117 | ); |
118 | ||
119 | // Add usage stats | |
120 | $this->payProcStats(); | |
121 | $this->entityStats(); | |
122 | $this->extensionStats(); | |
123 | ||
124 | // Get the latest version and send site info | |
125 | $this->pingBack(); | |
126 | ||
127 | // Update cache file | |
128 | if ($this->latestVersion) { | |
129 | $fp = @fopen($cachefile, 'w'); | |
130 | if (!$fp) { | |
131 | if (CRM_Core_Permission::check('administer CiviCRM')) { | |
132 | CRM_Core_Session::setStatus( | |
c7692a87 | 133 | ts('Unable to write file') . ":$cachefile<br />" . ts('Please check your system file permissions.'), |
6a488035 TO |
134 | ts('File Error'), 'error'); |
135 | } | |
136 | return; | |
137 | } | |
138 | fwrite($fp, $this->latestVersion); | |
139 | fclose($fp); | |
140 | } | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | /** | |
146 | * Static instance provider | |
147 | * | |
148 | * Method providing static instance of CRM_Utils_VersionCheck, | |
149 | * as in Singleton pattern | |
150 | * | |
151 | * @return CRM_Utils_VersionCheck | |
152 | */ | |
153 | static function &singleton() { | |
154 | if (!isset(self::$_singleton)) { | |
155 | self::$_singleton = new CRM_Utils_VersionCheck(); | |
156 | } | |
157 | return self::$_singleton; | |
158 | } | |
159 | ||
160 | /** | |
161 | * Get the latest version number if it's newer than the local one | |
162 | * | |
163 | * @return string|null | |
2be1e4fc | 164 | * Returns the newer version's number, or null if the versions are equal |
6a488035 TO |
165 | */ |
166 | public function newerVersion() { | |
167 | if ($this->latestVersion) { | |
09cdd1cd | 168 | if ((version_compare($this->localVersion, $this->latestVersion) < 0) |
169 | && CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'versionAlert', NULL, TRUE)) { | |
2be1e4fc | 170 | return $this->latestVersion; |
6a488035 TO |
171 | } |
172 | } | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | /** | |
177 | * Alert the site admin of new versions of CiviCRM | |
178 | * Show the message once a day | |
179 | */ | |
180 | public function versionAlert() { | |
b7aba061 CW |
181 | if (CRM_Core_Permission::check('administer CiviCRM') && $this->newerVersion() |
182 | && CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'versionAlert', NULL, TRUE)) { | |
6a488035 TO |
183 | $session = CRM_Core_Session::singleton(); |
184 | if ($session->timer('version_alert', 24 * 60 * 60)) { | |
185 | $msg = ts('A newer version of CiviCRM is available: %1', array(1 => $this->latestVersion)) | |
186 | . '<br />' . ts('<a href="%1">Download Now</a>', array(1 => 'http://civicrm.org/download')); | |
187 | $session->setStatus($msg, ts('Update Available')); | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
192 | /** | |
193 | * Get active payment processor types | |
194 | */ | |
195 | private function payProcStats() { | |
196 | $dao = new CRM_Financial_DAO_PaymentProcessor; | |
197 | $dao->is_active = 1; | |
198 | $dao->find(); | |
199 | $ppTypes = array(); | |
200 | ||
201 | // Get title and id for all processor types | |
202 | $ppTypeNames = CRM_Core_PseudoConstant::paymentProcessorType(); | |
203 | ||
204 | while ($dao->fetch()) { | |
205 | $ppTypes[] = $ppTypeNames[$dao->payment_processor_type_id]; | |
206 | } | |
207 | // add the .-separated list of the processor types | |
208 | $this->stats['PPTypes'] = implode(',', array_unique($ppTypes)); | |
209 | ||
210 | } | |
211 | ||
212 | /** | |
213 | * Fetch counts from entity tables | |
214 | * Add info to the 'entities' array | |
215 | */ | |
216 | private function entityStats() { | |
217 | $tables = array( | |
218 | 'CRM_Activity_DAO_Activity' => 'is_test = 0', | |
219 | 'CRM_Case_DAO_Case' => 'is_deleted = 0', | |
220 | 'CRM_Contact_DAO_Contact' => 'is_deleted = 0', | |
221 | 'CRM_Contact_DAO_Relationship' => NULL, | |
222 | 'CRM_Campaign_DAO_Campaign' => NULL, | |
223 | 'CRM_Contribute_DAO_Contribution' => 'is_test = 0', | |
224 | 'CRM_Contribute_DAO_ContributionPage' => 'is_active = 1', | |
225 | 'CRM_Contribute_DAO_ContributionProduct' => NULL, | |
226 | 'CRM_Contribute_DAO_Widget' => 'is_active = 1', | |
227 | 'CRM_Core_DAO_Discount' => NULL, | |
9da8dc8c | 228 | 'CRM_Price_DAO_PriceSetEntity' => NULL, |
6a488035 TO |
229 | 'CRM_Core_DAO_UFGroup' => 'is_active = 1', |
230 | 'CRM_Event_DAO_Event' => 'is_active = 1', | |
231 | 'CRM_Event_DAO_Participant' => 'is_test = 0', | |
232 | 'CRM_Friend_DAO_Friend' => 'is_active = 1', | |
233 | 'CRM_Grant_DAO_Grant' => NULL, | |
234 | 'CRM_Mailing_DAO_Mailing' => 'is_completed = 1', | |
235 | 'CRM_Member_DAO_Membership' => 'is_test = 0', | |
236 | 'CRM_Member_DAO_MembershipBlock' => 'is_active = 1', | |
237 | 'CRM_Pledge_DAO_Pledge' => 'is_test = 0', | |
238 | 'CRM_Pledge_DAO_PledgeBlock' => NULL, | |
239 | ); | |
240 | foreach ($tables as $daoName => $where) { | |
241 | $dao = new $daoName; | |
242 | if ($where) { | |
243 | $dao->whereAdd($where); | |
244 | } | |
245 | $short_name = substr($daoName, strrpos($daoName, '_') + 1); | |
246 | $this->stats['entities'][] = array( | |
247 | 'name' => $short_name, | |
248 | 'size' => $dao->count(), | |
249 | ); | |
250 | } | |
251 | } | |
252 | ||
253 | /** | |
254 | * Fetch stats about enabled components/extensions | |
255 | * Add info to the 'extensions' array | |
256 | */ | |
257 | private function extensionStats() { | |
258 | // Core components | |
259 | $config = CRM_Core_Config::singleton(); | |
260 | foreach ($config->enableComponents as $comp) { | |
261 | $this->stats['extensions'][] = array( | |
262 | 'name' => 'org.civicrm.component.' . strtolower($comp), | |
263 | 'enabled' => 1, | |
264 | 'version' => $this->stats['version'], | |
265 | ); | |
266 | } | |
267 | // Contrib extensions | |
268 | $mapper = CRM_Extension_System::singleton()->getMapper(); | |
269 | $dao = new CRM_Core_DAO_Extension(); | |
270 | $dao->find(); | |
271 | while ($dao->fetch()) { | |
272 | $info = $mapper->keyToInfo($dao->full_name); | |
273 | $this->stats['extensions'][] = array( | |
274 | 'name' => $dao->full_name, | |
275 | 'enabled' => $dao->is_active, | |
276 | 'version' => isset($info->version) ? $info->version : NULL, | |
277 | ); | |
278 | } | |
279 | } | |
280 | ||
281 | /** | |
282 | * Send the request to civicrm.org | |
283 | * Set timeout and suppress errors | |
284 | */ | |
285 | private function pingBack() { | |
286 | ini_set('default_socket_timeout', self::CHECK_TIMEOUT); | |
287 | $params = array( | |
288 | 'http' => array( | |
289 | 'method' => 'POST', | |
290 | 'header' => 'Content-type: application/x-www-form-urlencoded', | |
291 | 'content' => http_build_query($this->stats), | |
292 | ), | |
293 | ); | |
294 | $ctx = stream_context_create($params); | |
295 | $this->latestVersion = @file_get_contents(self::LATEST_VERSION_AT, FALSE, $ctx); | |
296 | if (!preg_match('/^\d+\.\d+\.\d+$/', $this->latestVersion)) { | |
297 | $this->latestVersion = NULL; | |
298 | } | |
2be1e4fc CW |
299 | else { |
300 | $this->latestVersion = trim($this->latestVersion); | |
301 | } | |
6a488035 TO |
302 | ini_restore('default_socket_timeout'); |
303 | } | |
304 | ||
305 | } |