Updated PEAR and PEAR packages.
[timetracker.git] / WEB-INF / lib / pear / PEAR / REST / 13.php
1 <?php
2 /**
3  * PEAR_REST_13
4  *
5  * PHP versions 4 and 5
6  *
7  * @category   pear
8  * @package    PEAR
9  * @author     Greg Beaver <cellog@php.net>
10  * @copyright  1997-2009 The Authors
11  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
12  * @link       http://pear.php.net/package/PEAR
13  * @since      File available since Release 1.4.0a12
14  */
15
16 /**
17  * For downloading REST xml/txt files
18  */
19 require_once 'PEAR/REST.php';
20 require_once 'PEAR/REST/10.php';
21
22 /**
23  * Implement REST 1.3
24  *
25  * @category   pear
26  * @package    PEAR
27  * @author     Greg Beaver <cellog@php.net>
28  * @copyright  1997-2009 The Authors
29  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
30  * @version    Release: 1.10.1
31  * @link       http://pear.php.net/package/PEAR
32  * @since      Class available since Release 1.4.0a12
33  */
34 class PEAR_REST_13 extends PEAR_REST_10
35 {
36     /**
37      * Retrieve information about a remote package to be downloaded from a REST server
38      *
39      * This is smart enough to resolve the minimum PHP version dependency prior to download
40      * @param string $base The uri to prepend to all REST calls
41      * @param array $packageinfo an array of format:
42      * <pre>
43      *  array(
44      *   'package' => 'packagename',
45      *   'channel' => 'channelname',
46      *  ['state' => 'alpha' (or valid state),]
47      *  -or-
48      *  ['version' => '1.whatever']
49      * </pre>
50      * @param string $prefstate Current preferred_state config variable value
51      * @param bool $installed the installed version of this package to compare against
52      * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
53      */
54     function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
55     {
56         $states = $this->betterStates($prefstate, true);
57         if (!$states) {
58             return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
59         }
60
61         $channel  = $packageinfo['channel'];
62         $package  = $packageinfo['package'];
63         $state    = isset($packageinfo['state'])   ? $packageinfo['state']   : null;
64         $version  = isset($packageinfo['version']) ? $packageinfo['version'] : null;
65         $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml';
66
67         $info = $this->_rest->retrieveData($restFile, false, false, $channel);
68         if (PEAR::isError($info)) {
69             return PEAR::raiseError('No releases available for package "' .
70                 $channel . '/' . $package . '"');
71         }
72
73         if (!isset($info['r'])) {
74             return false;
75         }
76
77         $release = $found = false;
78         if (!is_array($info['r']) || !isset($info['r'][0])) {
79             $info['r'] = array($info['r']);
80         }
81
82         $skippedphp = false;
83         foreach ($info['r'] as $release) {
84             if (!isset($this->_rest->_options['force']) && ($installed &&
85                   version_compare($release['v'], $installed, '<'))) {
86                 continue;
87             }
88
89             if (isset($state)) {
90                 // try our preferred state first
91                 if ($release['s'] == $state) {
92                     if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
93                         // skip releases that require a PHP version newer than our PHP version
94                         $skippedphp = $release;
95                         continue;
96                     }
97                     $found = true;
98                     break;
99                 }
100
101                 // see if there is something newer and more stable
102                 // bug #7221
103                 if (in_array($release['s'], $this->betterStates($state), true)) {
104                     if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
105                         // skip releases that require a PHP version newer than our PHP version
106                         $skippedphp = $release;
107                         continue;
108                     }
109                     $found = true;
110                     break;
111                 }
112             } elseif (isset($version)) {
113                 if ($release['v'] == $version) {
114                     if (!isset($this->_rest->_options['force']) &&
115                           !isset($version) &&
116                           version_compare($release['m'], phpversion(), '>')) {
117                         // skip releases that require a PHP version newer than our PHP version
118                         $skippedphp = $release;
119                         continue;
120                     }
121                     $found = true;
122                     break;
123                 }
124             } else {
125                 if (in_array($release['s'], $states)) {
126                     if (version_compare($release['m'], phpversion(), '>')) {
127                         // skip releases that require a PHP version newer than our PHP version
128                         $skippedphp = $release;
129                         continue;
130                     }
131                     $found = true;
132                     break;
133                 }
134             }
135         }
136
137         if (!$found && $skippedphp) {
138             $found = null;
139         }
140
141         return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
142     }
143
144     function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
145                                $prefstate = 'stable', $installed = false, $channel = false)
146     {
147         $states = $this->betterStates($prefstate, true);
148         if (!$states) {
149             return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
150         }
151
152         $channel  = $dependency['channel'];
153         $package  = $dependency['name'];
154         $state    = isset($dependency['state'])   ? $dependency['state']   : null;
155         $version  = isset($dependency['version']) ? $dependency['version'] : null;
156         $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml';
157
158         $info = $this->_rest->retrieveData($restFile, false, false, $channel);
159         if (PEAR::isError($info)) {
160             return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
161                 . '" dependency "' . $channel . '/' . $package . '" has no releases');
162         }
163
164         if (!is_array($info) || !isset($info['r'])) {
165             return false;
166         }
167
168         $exclude = array();
169         $min = $max = $recommended = false;
170         if ($xsdversion == '1.0') {
171             $pinfo['package'] = $dependency['name'];
172             $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this
173             switch ($dependency['rel']) {
174                 case 'ge' :
175                     $min = $dependency['version'];
176                 break;
177                 case 'gt' :
178                     $min = $dependency['version'];
179                     $exclude = array($dependency['version']);
180                 break;
181                 case 'eq' :
182                     $recommended = $dependency['version'];
183                 break;
184                 case 'lt' :
185                     $max = $dependency['version'];
186                     $exclude = array($dependency['version']);
187                 break;
188                 case 'le' :
189                     $max = $dependency['version'];
190                 break;
191                 case 'ne' :
192                     $exclude = array($dependency['version']);
193                 break;
194             }
195         } else {
196             $pinfo['package'] = $dependency['name'];
197             $min = isset($dependency['min']) ? $dependency['min'] : false;
198             $max = isset($dependency['max']) ? $dependency['max'] : false;
199             $recommended = isset($dependency['recommended']) ?
200                 $dependency['recommended'] : false;
201             if (isset($dependency['exclude'])) {
202                 if (!isset($dependency['exclude'][0])) {
203                     $exclude = array($dependency['exclude']);
204                 }
205             }
206         }
207
208         $skippedphp = $found = $release = false;
209         if (!is_array($info['r']) || !isset($info['r'][0])) {
210             $info['r'] = array($info['r']);
211         }
212
213         foreach ($info['r'] as $release) {
214             if (!isset($this->_rest->_options['force']) && ($installed &&
215                   version_compare($release['v'], $installed, '<'))) {
216                 continue;
217             }
218
219             if (in_array($release['v'], $exclude)) { // skip excluded versions
220                 continue;
221             }
222
223             // allow newer releases to say "I'm OK with the dependent package"
224             if ($xsdversion == '2.0' && isset($release['co'])) {
225                 if (!is_array($release['co']) || !isset($release['co'][0])) {
226                     $release['co'] = array($release['co']);
227                 }
228
229                 foreach ($release['co'] as $entry) {
230                     if (isset($entry['x']) && !is_array($entry['x'])) {
231                         $entry['x'] = array($entry['x']);
232                     } elseif (!isset($entry['x'])) {
233                         $entry['x'] = array();
234                     }
235
236                     if ($entry['c'] == $deppackage['channel'] &&
237                           strtolower($entry['p']) == strtolower($deppackage['package']) &&
238                           version_compare($deppackage['version'], $entry['min'], '>=') &&
239                           version_compare($deppackage['version'], $entry['max'], '<=') &&
240                           !in_array($release['v'], $entry['x'])) {
241                         if (version_compare($release['m'], phpversion(), '>')) {
242                             // skip dependency releases that require a PHP version
243                             // newer than our PHP version
244                             $skippedphp = $release;
245                             continue;
246                         }
247
248                         $recommended = $release['v'];
249                         break;
250                     }
251                 }
252             }
253
254             if ($recommended) {
255                 if ($release['v'] != $recommended) { // if we want a specific
256                     // version, then skip all others
257                     continue;
258                 }
259
260                 if (!in_array($release['s'], $states)) {
261                     // the stability is too low, but we must return the
262                     // recommended version if possible
263                     return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
264                 }
265             }
266
267             if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
268                 continue;
269             }
270
271             if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
272                 continue;
273             }
274
275             if ($installed && version_compare($release['v'], $installed, '<')) {
276                 continue;
277             }
278
279             if (in_array($release['s'], $states)) { // if in the preferred state...
280                 if (version_compare($release['m'], phpversion(), '>')) {
281                     // skip dependency releases that require a PHP version
282                     // newer than our PHP version
283                     $skippedphp = $release;
284                     continue;
285                 }
286
287                 $found = true; // ... then use it
288                 break;
289             }
290         }
291
292         if (!$found && $skippedphp) {
293             $found = null;
294         }
295
296         return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
297     }
298
299     /**
300      * List package upgrades but take the PHP version into account.
301      */
302     function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
303     {
304         $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
305         if (PEAR::isError($packagelist)) {
306             return $packagelist;
307         }
308
309         $ret = array();
310         if (!is_array($packagelist) || !isset($packagelist['p'])) {
311             return $ret;
312         }
313
314         if (!is_array($packagelist['p'])) {
315             $packagelist['p'] = array($packagelist['p']);
316         }
317
318         foreach ($packagelist['p'] as $package) {
319             if (!isset($installed[strtolower($package)])) {
320                 continue;
321             }
322
323             $inst_version = $reg->packageInfo($package, 'version', $channel);
324             $inst_state   = $reg->packageInfo($package, 'release_state', $channel);
325             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
326             $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
327                 '/allreleases2.xml', false, false, $channel);
328             PEAR::popErrorHandling();
329             if (PEAR::isError($info)) {
330                 continue; // no remote releases
331             }
332
333             if (!isset($info['r'])) {
334                 continue;
335             }
336
337             $release = $found = false;
338             if (!is_array($info['r']) || !isset($info['r'][0])) {
339                 $info['r'] = array($info['r']);
340             }
341
342             // $info['r'] is sorted by version number
343             usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
344             foreach ($info['r'] as $release) {
345                 if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
346                     // not newer than the one installed
347                     break;
348                 }
349                 if (version_compare($release['m'], phpversion(), '>')) {
350                     // skip dependency releases that require a PHP version
351                     // newer than our PHP version
352                     continue;
353                 }
354
355                 // new version > installed version
356                 if (!$pref_state) {
357                     // every state is a good state
358                     $found = true;
359                     break;
360                 } else {
361                     $new_state = $release['s'];
362                     // if new state >= installed state: go
363                     if (in_array($new_state, $this->betterStates($inst_state, true))) {
364                         $found = true;
365                         break;
366                     } else {
367                         // only allow to lower the state of package,
368                         // if new state >= preferred state: go
369                         if (in_array($new_state, $this->betterStates($pref_state, true))) {
370                             $found = true;
371                             break;
372                         }
373                     }
374                 }
375             }
376
377             if (!$found) {
378                 continue;
379             }
380
381             $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
382                 $release['v'] . '.xml', false, false, $channel);
383             if (PEAR::isError($relinfo)) {
384                 return $relinfo;
385             }
386
387             $ret[$package] = array(
388                 'version'  => $release['v'],
389                 'state'    => $release['s'],
390                 'filesize' => $relinfo['f'],
391             );
392         }
393
394         return $ret;
395     }
396 }