1 <?php
2 3 4 5 6 7
8
9
10 defined('FOF_INCLUDED') or die;
11
12 13 14 15
16 class FOFUtilsUpdateJoomla extends FOFUtilsUpdateExtension
17 {
18 19 20 21 22
23 protected static $lts_url = 'http://update.joomla.org/core/list.xml';
24
25 26 27 28 29
30 protected static $sts_url = 'http://update.joomla.org/core/sts/list_sts.xml';
31
32 33 34 35 36
37 protected static $test_url = 'http://update.joomla.org/core/test/list_test.xml';
38
39 40 41 42 43 44 45 46 47 48 49 50 51
52 public function getUpdatesFromExtension($url)
53 {
54
55 $ret = array();
56
57
58 $downloader = new FOFDownload();
59 $xmlSource = $downloader->getFromURL($url);
60
61 try
62 {
63 $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET);
64 }
65 catch (Exception $e)
66 {
67 return $ret;
68 }
69
70
71 if (($xml->getName() != 'updates'))
72 {
73 unset($xml);
74
75 return $ret;
76 }
77
78
79
80 foreach ($xml->children() as $update)
81 {
82
83 if ($update->getName() != 'update')
84 {
85 continue;
86 }
87
88 $entry = array(
89 'infourl' => array('title' => '', 'url' => ''),
90 'downloads' => array(),
91 'tags' => array(),
92 'targetplatform' => array(),
93 );
94
95 $properties = get_object_vars($update);
96
97 foreach ($properties as $nodeName => $nodeContent)
98 {
99 switch ($nodeName)
100 {
101 default:
102 $entry[ $nodeName ] = $nodeContent;
103 break;
104
105 case 'infourl':
106 case 'downloads':
107 case 'tags':
108 case 'targetplatform':
109 break;
110 }
111 }
112
113 $infourlNode = $update->xpath('infourl');
114 $entry['infourl']['title'] = (string) $infourlNode[0]['title'];
115 $entry['infourl']['url'] = (string) $infourlNode[0];
116
117 $downloadNodes = $update->xpath('downloads/downloadurl');
118 foreach ($downloadNodes as $downloadNode)
119 {
120 $entry['downloads'][] = array(
121 'type' => (string) $downloadNode['type'],
122 'format' => (string) $downloadNode['format'],
123 'url' => (string) $downloadNode,
124 );
125 }
126
127 $tagNodes = $update->xpath('tags/tag');
128 foreach ($tagNodes as $tagNode)
129 {
130 $entry['tags'][] = (string) $tagNode;
131 }
132
133
134 $targetPlatformNode = $update->xpath('targetplatform');
135
136 $entry['targetplatform']['name'] = (string) $targetPlatformNode[0]['name'];
137 $entry['targetplatform']['version'] = (string) $targetPlatformNode[0]['version'];
138 $client = $targetPlatformNode[0]->xpath('client');
139 $entry['targetplatform']['client'] = (is_array($client) && count($client)) ? (string) $client[0] : '';
140 $folder = $targetPlatformNode[0]->xpath('folder');
141 $entry['targetplatform']['folder'] = is_array($folder) && count($folder) ? (string) $folder[0] : '';
142
143 $ret[] = $entry;
144 }
145
146 unset($xml);
147
148 return $ret;
149 }
150
151 152 153 154 155 156 157 158 159
160 public function getUpdateSourceFromCollection($url, $jVersion = null)
161 {
162 $provider = new FOFUtilsUpdateCollection();
163
164 return $provider->getExtensionUpdateSource($url, 'file', 'joomla', $jVersion);
165 }
166
167 168 169 170 171 172 173 174
175 public function getVersionProperties($jVersion, $currentVersion = null)
176 {
177
178 $ret = array(
179 'lts' => true,
180
181 'current' => false,
182
183 'upgrade' => 'none',
184
185 'testing' => false,
186
187 );
188
189
190 if (is_null($currentVersion))
191 {
192 $currentVersion = JVERSION;
193 }
194
195
196 $sameVersion = $jVersion == $currentVersion;
197 $jVersion = $this->sanitiseVersion($jVersion);
198 $currentVersion = $this->sanitiseVersion($currentVersion);
199 $sameVersion = $sameVersion || ($jVersion == $currentVersion);
200
201
202 $baseVersion = substr($jVersion, 0, 3);
203
204
205 $current_minimum = substr($currentVersion, 0, 3);
206 $current_maximum = $current_minimum . '.9999';
207
208
209 $sts_minimum = false;
210 $sts_maximum = false;
211 $lts_minimum = false;
212
213
214 switch ($baseVersion)
215 {
216 case '1.5':
217 $ret['lts'] = true;
218 break;
219
220 case '1.6':
221 $ret['lts'] = false;
222 $sts_minimum = '1.7';
223 $sts_maximum = '1.7.999';
224 $lts_minimum = '2.5';
225 break;
226
227 case '1.7':
228 $ret['lts'] = false;
229 $sts_minimum = false;
230 $lts_minimum = '2.5';
231 break;
232
233 case '2.5':
234 $ret['lts'] = true;
235 $sts_minimum = false;
236 $lts_minimum = '2.5';
237 break;
238
239 default:
240 $majorVersion = (int) substr($jVersion, 0, 1);
241
242
243 $ret['lts'] = true;
244 $sts_minimum = false;
245 $lts_minimum = $majorVersion . '.0';
246 break;
247 }
248
249
250 if (version_compare($jVersion, $current_minimum, 'ge') && version_compare($jVersion, $current_maximum, 'le'))
251 {
252 $ret['current'] = true;
253 }
254
255
256 $versionParts = explode('.', $jVersion);
257 $lastVersionPart = array_pop($versionParts);
258
259 if (in_array(substr($lastVersionPart, 0, 1), array('a', 'b')))
260 {
261 $ret['testing'] = true;
262 }
263 elseif (substr($lastVersionPart, 0, 2) == 'rc')
264 {
265 $ret['testing'] = true;
266 }
267 elseif (substr($lastVersionPart, 0, 3) == 'dev')
268 {
269 $ret['testing'] = true;
270 }
271
272
273 if (version_compare($jVersion, $currentVersion, 'eq'))
274 {
275 $ret['upgrade'] = 'current';
276 }
277 elseif (($sts_minimum !== false) && version_compare($jVersion, $sts_minimum, 'ge') && version_compare($jVersion, $sts_maximum, 'le'))
278 {
279 $ret['upgrade'] = 'sts';
280 }
281 elseif (($lts_minimum !== false) && version_compare($jVersion, $lts_minimum, 'ge'))
282 {
283 $ret['upgrade'] = 'lts';
284 }
285 elseif ($baseVersion == $current_minimum)
286 {
287 $ret['upgrade'] = $ret['lts'] ? 'lts' : 'sts';
288 }
289 else
290 {
291 $ret['upgrade'] = 'none';
292 }
293
294 if ($sameVersion)
295 {
296 $ret['upgrade'] = 'none';
297 }
298
299 return $ret;
300 }
301
302
303 304 305 306 307 308 309 310 311
312 public function filterApplicableUpdates($updates, $jVersion = null)
313 {
314 if (empty($jVersion))
315 {
316 $jVersion = JVERSION;
317 }
318
319 $versionParts = explode('.', $jVersion, 4);
320 $platformVersionMajor = $versionParts[0];
321 $platformVersionMinor = $platformVersionMajor . '.' . $versionParts[1];
322 $platformVersionNormal = $platformVersionMinor . '.' . $versionParts[2];
323
324
325 $ret = array();
326
327 foreach ($updates as $update)
328 {
329
330 if (strtolower($update['targetplatform']['name']) != 'joomla')
331 {
332 continue;
333 }
334
335 $targetPlatformVersion = $update['targetplatform']['version'];
336
337 if (!preg_match('/' . $targetPlatformVersion . '/', $platformVersionMinor))
338 {
339 continue;
340 }
341
342
343 $updateVersion = $update['version'];
344 $versionProperties = $this->getVersionProperties($updateVersion, $jVersion);
345
346 if ($versionProperties['upgrade'] == 'none')
347 {
348 continue;
349 }
350
351
352 if (!array_key_exists($updateVersion, $ret))
353 {
354 $ret[ $updateVersion ] = array_merge($update, $versionProperties);
355 }
356 }
357
358 return $ret;
359 }
360
361 362 363 364 365 366 367 368 369 370 371
372 public function sanitiseVersion($version)
373 {
374 $test = strtolower($version);
375 $alphaQualifierPosition = strpos($test, 'alpha-');
376 $betaQualifierPosition = strpos($test, 'beta-');
377 $betaQualifierPosition2 = strpos($test, '-beta');
378 $rcQualifierPosition = strpos($test, 'rc-');
379 $rcQualifierPosition2 = strpos($test, '-rc');
380 $rcQualifierPosition3 = strpos($test, 'rc');
381 $devQualifiedPosition = strpos($test, 'dev');
382
383 if ($alphaQualifierPosition !== false)
384 {
385 $betaRevision = substr($test, $alphaQualifierPosition + 6);
386 if (!$betaRevision)
387 {
388 $betaRevision = 1;
389 }
390 $test = substr($test, 0, $alphaQualifierPosition) . '.a' . $betaRevision;
391 }
392 elseif ($betaQualifierPosition !== false)
393 {
394 $betaRevision = substr($test, $betaQualifierPosition + 5);
395 if (!$betaRevision)
396 {
397 $betaRevision = 1;
398 }
399 $test = substr($test, 0, $betaQualifierPosition) . '.b' . $betaRevision;
400 }
401 elseif ($betaQualifierPosition2 !== false)
402 {
403 $betaRevision = substr($test, $betaQualifierPosition2 + 5);
404
405 if (!$betaRevision)
406 {
407 $betaRevision = 1;
408 }
409
410 $test = substr($test, 0, $betaQualifierPosition2) . '.b' . $betaRevision;
411 }
412 elseif ($rcQualifierPosition !== false)
413 {
414 $betaRevision = substr($test, $rcQualifierPosition + 5);
415 if (!$betaRevision)
416 {
417 $betaRevision = 1;
418 }
419 $test = substr($test, 0, $rcQualifierPosition) . '.rc' . $betaRevision;
420 }
421 elseif ($rcQualifierPosition2 !== false)
422 {
423 $betaRevision = substr($test, $rcQualifierPosition2 + 3);
424
425 if (!$betaRevision)
426 {
427 $betaRevision = 1;
428 }
429
430 $test = substr($test, 0, $rcQualifierPosition2) . '.rc' . $betaRevision;
431 }
432 elseif ($rcQualifierPosition3 !== false)
433 {
434 $betaRevision = substr($test, $rcQualifierPosition3 + 5);
435
436 if (!$betaRevision)
437 {
438 $betaRevision = 1;
439 }
440
441 $test = substr($test, 0, $rcQualifierPosition3) . '.rc' . $betaRevision;
442 }
443 elseif ($devQualifiedPosition !== false)
444 {
445 $betaRevision = substr($test, $devQualifiedPosition + 6);
446 if (!$betaRevision)
447 {
448 $betaRevision = '';
449 }
450 $test = substr($test, 0, $devQualifiedPosition) . '.dev' . $betaRevision;
451 }
452
453 return $test;
454 }
455
456 457 458 459 460 461 462 463 464
465 public function getUpdates($sources = array(), $jVersion = null)
466 {
467
468 if (empty($sources) || !is_array($sources))
469 {
470 $sources = array();
471 }
472
473 $defaultSources = array('lts' => true, 'sts' => true, 'test' => true, 'custom' => '');
474
475 $sources = array_merge($defaultSources, $sources);
476
477
478 if (empty($jVersion))
479 {
480 $jVersion = JVERSION;
481 }
482
483
484 $versionParts = explode('.', $jVersion, 4);
485 $currentMinVersion = $versionParts[0] . '.' . $versionParts[1];
486 $currentMaxVersion = $versionParts[0] . '.' . $versionParts[1] . '.9999';
487
488
489
490 $allUpdates = array();
491
492 foreach ($sources as $source => $value)
493 {
494 if (($value === false) || empty($value))
495 {
496 continue;
497 }
498
499 switch ($source)
500 {
501 case 'lts':
502 $url = self::$lts_url;
503 break;
504
505 case 'sts':
506 $url = self::$sts_url;
507 break;
508
509 case 'test':
510 $url = self::$test_url;
511 break;
512
513 default:
514 case 'custom':
515 $url = $value;
516 break;
517 }
518
519 $url = $this->getUpdateSourceFromCollection($url, $jVersion);
520
521 if (!empty($url))
522 {
523 $updates = $this->getUpdatesFromExtension($url);
524
525 if (!empty($updates))
526 {
527 $applicableUpdates = $this->filterApplicableUpdates($updates, $jVersion);
528
529 if (!empty($applicableUpdates))
530 {
531 $allUpdates = array_merge($allUpdates, $applicableUpdates);
532 }
533 }
534 }
535 }
536
537 $ret = array(
538
539 'installed' => array(
540 'version' => '',
541 'package' => '',
542 'infourl' => '',
543 ),
544
545 'current' => array(
546 'version' => '',
547 'package' => '',
548 'infourl' => '',
549 ),
550
551 'sts' => array(
552 'version' => '',
553 'package' => '',
554 'infourl' => '',
555 ),
556
557 'lts' => array(
558 'version' => '',
559 'package' => '',
560 'infourl' => '',
561 ),
562
563 'test' => array(
564 'version' => '',
565 'package' => '',
566 'infourl' => '',
567 ),
568 );
569
570 foreach ($allUpdates as $update)
571 {
572 $sections = array();
573
574 if ($update['upgrade'] == 'current')
575 {
576 $sections[0] = 'installed';
577 }
578 elseif (version_compare($update['version'], $currentMinVersion, 'ge') && version_compare($update['version'], $currentMaxVersion, 'le'))
579 {
580 $sections[0] = 'current';
581 }
582 else
583 {
584 $sections[0] = '';
585 }
586
587 $sections[1] = $update['lts'] ? 'lts' : 'sts';
588
589 if ($update['testing'])
590 {
591 $sections = array('test');
592 }
593
594 foreach ($sections as $section)
595 {
596 if (empty($section))
597 {
598 continue;
599 }
600
601 $existingVersionForSection = $ret[ $section ]['version'];
602
603 if (empty($existingVersionForSection))
604 {
605 $existingVersionForSection = '0.0.0';
606 }
607
608 if (version_compare($update['version'], $existingVersionForSection, 'ge'))
609 {
610 $ret[ $section ]['version'] = $update['version'];
611 $ret[ $section ]['package'] = $update['downloads'][0]['url'];
612 $ret[ $section ]['infourl'] = $update['infourl']['url'];
613 }
614 }
615 }
616
617
618 if (empty($ret['current']['version']) && !empty($ret['installed']['version']))
619 {
620 $ret['current'] = $ret['installed'];
621 }
622
623 return $ret;
624 }
625 }