1 : <?php
2 : /**
3 : * A package to make adding self updating functionality to other
4 : * packages easy.
5 : *
6 : * PHP versions 4 and 5
7 : *
8 : * LICENSE: This source file is subject to version 3.01 of the PHP license
9 : * that is available through the world-wide-web at the following URI:
10 : * http://www.php.net/license/3_01.txt. If you did not receive a copy of
11 : * the PHP License and are unable to obtain it through the web, please
12 : * send a note to license@php.net so we can mail you a copy immediately.
13 : *
14 : * CREDITS: To Ian Eure <ieure@php.net>
15 : * for repackage PEAR_Errors for use with ErrorStack
16 : * see repackagePEARError()
17 : *
18 : * @category PEAR
19 : * @package PEAR_PackageUpdate
20 : * @author Scott Mattocks <scottmattocks@php.net>
21 : * @author Laurent Laville <pear@laurent-laville.org>
22 : * @copyright 2006-2009 Scott Mattocks, Laurent Laville
23 : * @license http://www.php.net/license/3_01.txt PHP License 3.01
24 : * @version CVS: $Id: PackageUpdate.php,v 1.38 2009/02/28 11:32:31 farell Exp $
25 : * @link http://pear.php.net/package/PEAR_PackageUpdate
26 : * @since File available since Release 0.4.0a1
27 : */
28 :
29 2 : require_once 'PEAR/ErrorStack.php';
30 2 : require_once 'PEAR/Config.php';
31 :
32 : // PEAR_PACKAGEUPDATE_PREF_* Constants for preferences.
33 : /**
34 : * Check to see if the user wants to be notified about any updates for
35 : * this package.
36 : */
37 2 : define('PEAR_PACKAGEUPDATE_PREF_NOUPDATES', 0);
38 : /**
39 : * Check to see if the user has requested not to be asked until a new
40 : * version is released.
41 : */
42 2 : define('PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE', 1);
43 : /**
44 : * Check to see if the user only wants to be asked about a certain
45 : * type of release (bug|minor|major).
46 : */
47 2 : define('PEAR_PACKAGEUPDATE_PREF_TYPE', 2);
48 : /**
49 : * Check to see if the user has requested not to be asked about the
50 : * state of the latest release.
51 : */
52 2 : define('PEAR_PACKAGEUPDATE_PREF_STATE', 3);
53 :
54 : // PEAR_PACKAGEUPDATE_STATE_* Constants for states.
55 : /**
56 : * Check to see if the user has requested to be asked when
57 : * the latest release is a snapshot release.
58 : */
59 2 : define('PEAR_PACKAGEUPDATE_STATE_SNAPSHOT', 'snapshot');
60 : /**
61 : * Check to see if the user has requested to be asked when
62 : * the latest release is a devel release.
63 : */
64 2 : define('PEAR_PACKAGEUPDATE_STATE_DEVEL', 'devel');
65 : /**
66 : * Check to see if the user has requested to be asked when
67 : * the latest release is an alpha release.
68 : */
69 2 : define('PEAR_PACKAGEUPDATE_STATE_ALPHA', 'alpha');
70 : /**
71 : * Check to see if the user has requested to be asked when
72 : * the latest release is an beta release.
73 : */
74 2 : define('PEAR_PACKAGEUPDATE_STATE_BETA', 'beta');
75 : /**
76 : * Check to see if the user has requested to be asked when
77 : * the latest release is a stable release.
78 : */
79 2 : define('PEAR_PACKAGEUPDATE_STATE_STABLE', 'stable');
80 :
81 : // PEAR_PACKAGEUPDATE_TYPE_* Constants for release types.
82 : /**
83 : * Check to see if the user only wants to be asked about a bug release
84 : */
85 2 : define('PEAR_PACKAGEUPDATE_TYPE_BUG', 'bug');
86 : /**
87 : * Check to see if the user only wants to be asked about a minor release
88 : */
89 2 : define('PEAR_PACKAGEUPDATE_TYPE_MINOR', 'minor');
90 : /**
91 : * Check to see if the user only wants to be asked about a major release
92 : */
93 2 : define('PEAR_PACKAGEUPDATE_TYPE_MAJOR', 'major');
94 :
95 : // PEAR_PACKAGEUPDATE_ERROR_* Constants for errors.
96 : /**
97 : * No package name provided
98 : */
99 2 : define('PEAR_PACKAGEUPDATE_ERROR_NOPACKAGE', -1);
100 : /**
101 : * No channel name provided
102 : */
103 2 : define('PEAR_PACKAGEUPDATE_ERROR_NOCHANNEL', -2);
104 : /**
105 : * No update information is available for the package
106 : */
107 2 : define('PEAR_PACKAGEUPDATE_ERROR_NOINFO', -3);
108 : /**
109 : * The package is not installed. It cannot be updated.
110 : */
111 2 : define('PEAR_PACKAGEUPDATE_ERROR_NOTINSTALLED', -4);
112 : /**
113 : * Preferences cannot be read from file because of access permission errors
114 : */
115 2 : define('PEAR_PACKAGEUPDATE_ERROR_PREFFILE_READACCESS', -5);
116 : /**
117 : * Preferences cannot be written to file because of access permission errors
118 : */
119 2 : define('PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEACCESS', -6);
120 : /**
121 : * An error occurred while trying to write the preferences to file
122 : */
123 2 : define('PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEERROR', -7);
124 : /**
125 : * Preferences file is corrupted
126 : */
127 2 : define('PEAR_PACKAGEUPDATE_ERROR_PREFFILE_CORRUPTED', -8);
128 : /**
129 : * Invalid release type
130 : */
131 2 : define('PEAR_PACKAGEUPDATE_ERROR_INVALIDTYPE', -9);
132 : /**
133 : * Invalid release state
134 : */
135 2 : define('PEAR_PACKAGEUPDATE_ERROR_INVALIDSTATE', -10);
136 : /**
137 : * Invalid preference identifier
138 : */
139 2 : define('PEAR_PACKAGEUPDATE_ERROR_INVALIDPREF', -11);
140 : /**
141 : * Driver (backend) could not be found.
142 : */
143 2 : define('PEAR_PACKAGEUPDATE_ERROR_NONEXISTENTDRIVER', -12);
144 : /**
145 : * Invalid INI file
146 : */
147 2 : define('PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE', -13);
148 : /**
149 : * Invalid driver structure
150 : */
151 2 : define('PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER', -14);
152 : /**
153 : * Wrong adapter
154 : */
155 2 : define('PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER', -15);
156 :
157 : // Error messages.
158 2 : $GLOBALS['_PEAR_PACKAGEUPDATE_ERRORS'] =
159 : array(
160 2 : PEAR_PACKAGEUPDATE_ERROR_NOPACKAGE =>
161 2 : 'No package name provided',
162 2 : PEAR_PACKAGEUPDATE_ERROR_NOCHANNEL =>
163 2 : 'No channel name provided',
164 2 : PEAR_PACKAGEUPDATE_ERROR_NOINFO =>
165 2 : 'No update information is available for %packagename%.',
166 2 : PEAR_PACKAGEUPDATE_ERROR_NOTINSTALLED =>
167 2 : '%packagename% is not installed. It cannot be updated.',
168 2 : PEAR_PACKAGEUPDATE_ERROR_PREFFILE_READACCESS =>
169 2 : 'Preferences cannot be read from %file%.',
170 2 : PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEACCESS =>
171 : 'Preferences cannot be written to %file% ' .
172 2 : 'because of access permission errors.',
173 2 : PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEERROR =>
174 2 : 'An error occurred while trying to write the preferences to %file%.',
175 2 : PEAR_PACKAGEUPDATE_ERROR_PREFFILE_CORRUPTED =>
176 2 : 'Preferences file is corrupted.',
177 2 : PEAR_PACKAGEUPDATE_ERROR_INVALIDTYPE =>
178 2 : 'Invalid release type: %type%',
179 2 : PEAR_PACKAGEUPDATE_ERROR_INVALIDSTATE =>
180 2 : 'Invalid release state: %state%',
181 2 : PEAR_PACKAGEUPDATE_ERROR_INVALIDPREF =>
182 2 : 'Invalid preference: %preference%',
183 2 : PEAR_PACKAGEUPDATE_ERROR_NONEXISTENTDRIVER =>
184 2 : 'Driver %drivername% could not be found.',
185 2 : PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE =>
186 2 : 'Invalid (%layer%) INI file : %file%',
187 2 : PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER =>
188 : '%function% is an abstract method that must be' .
189 2 : ' overridden in the driver class.',
190 2 : PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER =>
191 : '%adapter% adapter is not supported'
192 2 : );
193 :
194 : /**
195 : * The package allows a developer to add a few lines of code to
196 : * their existing packages and have the ability to update their
197 : * package automatically. This auto-update ability allows users
198 : * to stay up to date much more easily than requiring them to
199 : * update manually.
200 : *
201 : * This package keeps track of user preferences such as "don't
202 : * remind me again".
203 : *
204 : * This package is designed to be a backend to different front
205 : * ends written for this package. For example, this package can
206 : * be used to drive a PHP-GTK 2, CLI or web front end. The API
207 : * for this package should be flexible enough to allow any type
208 : * of front end to be used and also to allow the package to be
209 : * used directly in another package without a front end driver.
210 : *
211 : * The interface for this package must allow for the following
212 : * functionality:
213 : * - check to see if a new version is available for a given
214 : * package on a given channel
215 : * - check minimum state
216 : * - present information regarding the upgrade (version, size)
217 : * - inform user about dependencies
218 : * - allow user to confirm or cancel upgrade
219 : * - download and install the package
220 : * - track preferences on a per package basis
221 : * - don't ask again
222 : * - don't ask until next release
223 : * - only ask for state XXXX or higher
224 : * - bug/minor/major updates only
225 : * - update channel automatically
226 : * - force application to exit when upgrade complete
227 : * - PHP-GTK/CLI apps must exit to allow classes to reload
228 : * - web front end could send headers to reload certain page
229 : *
230 : * This class is simply a wrapper for PEAR classes that actually
231 : * do the work.
232 : *
233 : * EXAMPLE:
234 : * <code>
235 : * <?php
236 : * class Goo {
237 : * function __construct()
238 : * {
239 : * // Check for updates...
240 : * require_once 'PEAR/PackageUpdate.php';
241 : * $ppu =& PEAR_PackageUpdate::factory('Gtk2', 'Goo', 'pear');
242 : * if ($ppu !== false) {
243 : * if ($ppu->checkUpdate()) {
244 : * // Use a dialog window to ask permission to update.
245 : * if ($ppu->presentUpdate()) {
246 : * if ($ppu->update()) {
247 : * // If the update succeeded, the application should
248 : * // be restarted.
249 : * $ppu->forceRestart();
250 : * }
251 : * }
252 : * }
253 : * }
254 : * // ...
255 : * }
256 : * // ...
257 : * }
258 : * ?>
259 : * </code>
260 : *
261 : * @category PEAR
262 : * @package PEAR_PackageUpdate
263 : * @author Scott Mattocks <scottmattocks@php.net>
264 : * @author Laurent Laville <pear@laurent-laville.org>
265 : * @copyright 2006-2009 Scott Mattocks, Laurent Laville
266 : * @license http://www.php.net/license/3_01.txt PHP License 3.01
267 : * @version Release: 1.1.0a1
268 : * @link http://pear.php.net/package/PEAR_PackageUpdate
269 : * @since Class available since Release 0.4.0a1
270 : */
271 :
272 : class PEAR_PackageUpdate
273 2 : {
274 : /**
275 : * The user's update preferences.
276 : *
277 : * @access public
278 : * @var array
279 : * @since 0.4.0a1
280 : */
281 : var $preferences = array();
282 :
283 : /**
284 : * The file to read PPU user-defined options from
285 : *
286 : * @access public
287 : * @var string
288 : * @since 0.7.0
289 : */
290 : var $pref_file;
291 :
292 : /**
293 : * The file to read PEAR user-defined options from
294 : *
295 : * @access public
296 : * @var string
297 : * @since 0.7.0
298 : */
299 : var $user_file;
300 :
301 : /**
302 : * The file to read PEAR system-wide defaults from
303 : *
304 : * @access public
305 : * @var string
306 : * @since 0.7.0
307 : */
308 : var $system_file;
309 :
310 : /**
311 : * The name of the package.
312 : *
313 : * @access public
314 : * @var string
315 : * @since 0.4.0a1
316 : */
317 : var $packageName;
318 :
319 : /**
320 : * The channel the package is hosted on.
321 : *
322 : * @access public
323 : * @var string
324 : * @since 0.4.0a1
325 : */
326 : var $channel;
327 :
328 : /**
329 : * The latest version available for the given package.
330 : *
331 : * @access public
332 : * @var string
333 : * @since 0.4.0a1
334 : */
335 : var $latestVersion;
336 :
337 : /**
338 : * Information about the latest version of the package.
339 : *
340 : * @access public
341 : * @var array
342 : * @since 0.4.0a1
343 : */
344 : var $info = array();
345 :
346 : /**
347 : * The current installed version of the package.
348 : *
349 : * @access public
350 : * @var string
351 : * @since 0.4.0a1
352 : */
353 : var $instVersion;
354 :
355 : /**
356 : * Informations about the current installed version of the package.
357 : *
358 : * @access protected
359 : * @var array
360 : * @since 0.6.0
361 : * @see PEAR_Registry::packageInfo()
362 : */
363 : var $instInfo;
364 :
365 : /**
366 : * A collection of errors that have occurred.
367 : *
368 : * @access public
369 : * @var object
370 : * @since 0.4.0a1
371 : */
372 : var $errors;
373 :
374 : /**
375 : * List of adapters used to communicate with package channels
376 : *
377 : * @access public
378 : * @var array
379 : * @since 1.1.0a1
380 : */
381 : var $adapters = array();
382 :
383 : /**
384 : * PHP 4 style constructor. Calls the PHP 5 style constructor.
385 : *
386 : * @param string $packageName The package to update.
387 : * @param string $channel The channel the package resides on.
388 : * @param string $user_file (optional) file to read PEAR user-defined
389 : * options from
390 : * @param string $system_file (optional) file to read PEAR system-wide
391 : * defaults from
392 : * @param string $pref_file (optional) file to read PPU user-defined
393 : * options from
394 : *
395 : * @access public
396 : * @return void
397 : * @since version 0.4.0a1 (2006-03-28)
398 : */
399 : function PEAR_PackageUpdate($packageName, $channel,
400 : $user_file = '', $system_file = '', $pref_file = '')
401 : {
402 23 : PEAR_PackageUpdate::__construct($packageName, $channel,
403 23 : $user_file, $system_file, $pref_file);
404 23 : }
405 :
406 : /**
407 : * PHP 5 style constructor. Loads the user preferences.
408 : *
409 : * @param string $packageName The package to update.
410 : * @param string $channel The channel the package resides on.
411 : * @param string $user_file (optional) file to read PEAR user-defined
412 : * options from
413 : * @param string $system_file (optional) file to read PEAR system-wide
414 : * defaults from
415 : * @param string $pref_file (optional) file to read PPU user-defined
416 : * options from
417 : *
418 : * @access public
419 : * @return void
420 : * @since version 0.4.0a1 (2006-03-28)
421 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE
422 : */
423 : function __construct($packageName, $channel,
424 : $user_file = '', $system_file = '', $pref_file = '')
425 : {
426 : // Create a pear error stack.
427 25 : $this->errors =& PEAR_ErrorStack::singleton(get_class($this));
428 25 : $this->errors->setContextCallback(array(&$this, '_getBacktrace'));
429 :
430 : // Set the package name and channel.
431 25 : $this->packageName = $packageName;
432 25 : $this->channel = $channel;
433 :
434 25 : if ($user_file && !file_exists($user_file)) {
435 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE,
436 1 : 'warning',
437 1 : array('layer' => 'pear-user', 'file' => $user_file));
438 1 : $user_file = ''; // force to use default user configuration
439 1 : }
440 25 : if ($system_file && !file_exists($system_file)) {
441 2 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE,
442 2 : 'warning',
443 2 : array('layer' => 'pear-system', 'file' => $system_file));
444 2 : $system_file = ''; // force to use default system configuration
445 2 : }
446 :
447 : // Set the file to read PEAR user-defined options from
448 25 : $this->user_file = $user_file;
449 : // Set the file to read PEAR system-wide defaults from
450 25 : $this->system_file = $system_file;
451 : // Set the file to read PPU user-defined options from
452 25 : $this->pref_file = $pref_file;
453 :
454 : // Load the user's preferences.
455 25 : $this->loadPreferences($pref_file);
456 25 : }
457 :
458 : /**
459 : * Callback that generates context information (location of error)
460 : * for the package error stack.
461 : *
462 : * @access private
463 : * @return mixed backtrace context array or false is unavailable
464 : * @since version 0.4.3 (2006-04-25)
465 : */
466 : function _getBacktrace()
467 : {
468 15 : $backtrace = debug_backtrace();
469 15 : $backtrace = $backtrace[count($backtrace)-1];
470 15 : return $backtrace;
471 : }
472 :
473 : /**
474 : * Creates an instance of the given update class.
475 : *
476 : * @param string $driver The type of PPU to create.
477 : * @param string $packageName The package to update.
478 : * @param string $channel The channel the package resides on.
479 : * @param string $user_file (optional) file to read PEAR user-defined
480 : * options from
481 : * @param string $system_file (optional) file to read PEAR system-wide
482 : * defaults from
483 : * @param string $pref_file (optional) file to read PPU user-defined
484 : * options from
485 : *
486 : * @return object An instance of type PEAR_PackageUpdate_$driver
487 : * @static
488 : * @access public
489 : * @since version 0.4.0a1 (2006-03-28)
490 : * @throws PEAR_PACKAGEUPDATE_ERROR_NONEXISTENTDRIVER
491 : */
492 : function &factory($driver, $packageName, $channel,
493 : $user_file = '', $system_file = '', $pref_file = '')
494 : {
495 25 : $class = 'PEAR_PackageUpdate_' . $driver;
496 :
497 : // Attempt to include a custom version of the named class, but don't treat
498 : // a failure as fatal. The caller may have already included their own
499 : // version of the named class.
500 25 : if (!class_exists($class)) {
501 :
502 : // Try to include the driver.
503 4 : $file = str_replace('_', '/', $class) . '.php';
504 :
505 4 : if (!PEAR_PackageUpdate::isIncludable($file)) {
506 1 : PEAR_ErrorStack::staticPush('PEAR_PackageUpdate',
507 1 : PEAR_PACKAGEUPDATE_ERROR_NONEXISTENTDRIVER,
508 1 : null,
509 1 : array('drivername' => $driver),
510 1 : $GLOBALS['_PEAR_PACKAGEUPDATE_ERRORS']
511 1 : [PEAR_PACKAGEUPDATE_ERROR_NONEXISTENTDRIVER]);
512 : // Must assign a variable to avoid notice about references.
513 1 : $false = false;
514 1 : return $false;
515 : }
516 4 : include_once $file;
517 4 : }
518 :
519 : // See if the class exists now.
520 25 : if (!class_exists($class)) {
521 : // Must assign a variable to avoid notice about references.
522 1 : $false = false;
523 1 : return $false;
524 : }
525 :
526 : // Try to instantiate the class.
527 25 : $instance =& new $class($packageName, $channel,
528 25 : $user_file, $system_file, $pref_file);
529 25 : return $instance;
530 : }
531 :
532 : /**
533 : * Returns whether or not a path is in the include path.
534 : *
535 : * @param string $path Path to filename to check if includable
536 : *
537 : * @static
538 : * @access public
539 : * @return boolean true if the path is in the include path.
540 : * @since version 0.4.2 (2006-04-20)
541 : */
542 : function isIncludable($path)
543 : {
544 : // Break up the include path and check to see if the path is readable.
545 7 : foreach (explode(PATH_SEPARATOR, get_include_path()) as $ip) {
546 7 : if (file_exists($ip . DIRECTORY_SEPARATOR . $path)
547 6 : && is_readable($ip . DIRECTORY_SEPARATOR . $path)
548 7 : ) {
549 6 : return true;
550 : }
551 6 : }
552 :
553 : // If we got down here, the path is not readable from the include path.
554 2 : return false;
555 : }
556 :
557 : /**
558 : * Loads the user's preferences from a file.
559 : *
560 : * The preferences are stored in the user's home directory
561 : * as the file .ppurc. The file contains a serialized array
562 : * of preferences for each package that has been checked for
563 : * updates so far.
564 : *
565 : * @param string $pref_file (optional) file to read PPU user-defined options from
566 : *
567 : * @access protected
568 : * @return boolean true on success, false on error
569 : * @since version 0.4.0a1 (2006-03-28)
570 : * @throws PEAR_PACKAGEUPDATE_ERROR_PREFFILE_READACCESS,
571 : * PEAR_PACKAGEUPDATE_ERROR_PREFFILE_CORRUPTED,
572 : * PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE
573 : */
574 : function loadPreferences($pref_file = '')
575 : {
576 25 : if ($pref_file && !file_exists($pref_file)) {
577 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDINIFILE,
578 1 : 'warning',
579 1 : array('layer' => 'ppu-pref', 'file' => $pref_file));
580 1 : $pref_file = ''; // force to use default PPU configuration
581 1 : }
582 :
583 : // Get the preferences file.
584 25 : if (empty($pref_file)) {
585 25 : $prefFile = $this->determinePrefFile();
586 25 : } else {
587 1 : $prefFile = $pref_file;
588 : }
589 :
590 : // Make sure the prefFile exists.
591 25 : if (!@file_exists($prefFile)) {
592 : // Try to create it by saving the current preferences (probably
593 : // just an empty array).
594 14 : $this->savePreferences($prefFile);
595 14 : }
596 :
597 : // Make sure the prefFile is readable.
598 25 : if (!@is_readable($prefFile)) {
599 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_PREFFILE_READACCESS,
600 0 : 'error', array('file' => $prefFile));
601 0 : return false;
602 : }
603 :
604 : // Get the contents of the prefFile.
605 25 : $contents = file_get_contents($prefFile);
606 :
607 : // Unserialize the data.
608 25 : $preferences = @unserialize($contents);
609 :
610 : // Make sure the contents were unserialized properly.
611 : // Borrowed from PEAR_Config.
612 25 : if ($preferences === false) {
613 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_PREFFILE_CORRUPTED);
614 1 : return false;
615 : }
616 :
617 25 : $this->preferences = $preferences;
618 25 : $this->pref_file = $prefFile;
619 :
620 25 : return true;
621 : }
622 :
623 : /**
624 : * Returns the path to the preferences file.
625 : *
626 : * @access protected
627 : * @return string
628 : * @since version 0.4.0a1 (2006-03-28)
629 : */
630 : function determinePrefFile()
631 : {
632 25 : if (OS_WINDOWS) {
633 25 : $cfgName = 'ppurc.ini';
634 25 : } else {
635 0 : $cfgName = '.ppurc';
636 : }
637 :
638 : // PEAR 1.7.0 introduced new feature like configuration directory (cfg_dir)
639 25 : $config =& PEAR_Config::singleton($this->user_file, $this->system_file);
640 25 : $cfgDir = $config->get('cfg_dir');
641 :
642 25 : if (!is_null($cfgDir) && is_dir($cfgDir)) {
643 : // detect PEAR configuration directive (cfg_dir)
644 25 : } else {
645 0 : if (OS_WINDOWS) {
646 0 : $cfgDir = PEAR_CONFIG_SYSCONFDIR;
647 0 : } else {
648 0 : $cfgDir = getenv('HOME');
649 : }
650 : }
651 25 : $prefFile = $cfgDir . DIRECTORY_SEPARATOR . $cfgName;
652 :
653 25 : return $prefFile;
654 : }
655 :
656 : /**
657 : * Checks to see if an update is available.
658 : *
659 : * Respects the user preferences when determining if an
660 : * update is available. Returns true if an update is available
661 : * and the user may want to update the package.
662 : *
663 : * @access public
664 : * @return boolean true if an update is available.
665 : * @since version 0.4.0a1 (2006-03-28)
666 : */
667 : function checkUpdate()
668 : {
669 : // Check to see if an update is available.
670 11 : if (empty($this->latestVersion) || empty ($this->info)) {
671 11 : if (!$this->getInstalledRelease()) {
672 1 : return false;
673 : }
674 10 : }
675 :
676 : // See if the installed version is older than the current version.
677 10 : if (version_compare($this->latestVersion, $this->instVersion, '>')) {
678 : // Check to see if the user's preferences allow an update.
679 9 : if (!$this->preferencesAllowUpdate()) {
680 : // User doesn't want to update to the latest version.
681 3 : return false;
682 : }
683 7 : return true;
684 : } else {
685 1 : return false;
686 : }
687 : }
688 :
689 : /**
690 : * Returns the latest information about the given package.
691 : *
692 : * @access protected
693 : * @return boolean true on success, false on error
694 : * @since version 0.4.0a1 (2006-03-28)
695 : * @throws PEAR_PACKAGEUPDATE_ERROR_NOPACKAGE,
696 : * PEAR_PACKAGEUPDATE_ERROR_NOCHANNEL,
697 : * PEAR_PACKAGEUPDATE_ERROR_NOINFO
698 : * PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER
699 : */
700 : function getPackageInfo()
701 : {
702 : // Only check once.
703 14 : if (isset($this->latestVersion) && isset($this->info)) {
704 1 : return true;
705 : }
706 :
707 : // Make sure the channel and package are set.
708 14 : if (empty($this->packageName)) {
709 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_NOPACKAGE);
710 1 : return false;
711 : }
712 :
713 13 : if (empty($this->channel)) {
714 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_NOCHANNEL);
715 1 : return false;
716 : }
717 :
718 : // If there are no adapters defined, used in following order (priority level)
719 : // - the REST protocol by default,
720 : // - then if not supported by channel, try the XMLRPC protocol
721 12 : if (count($this->adapters) == 0) {
722 10 : $this->addAdapter('REST', 2);
723 10 : $this->addAdapter('XmlRPC', 1);
724 10 : }
725 12 : arsort($this->adapters, SORT_NUMERIC);
726 :
727 : // Create a config object.
728 12 : $config =& PEAR_Config::singleton($this->user_file, $this->system_file);
729 :
730 12 : foreach ($this->adapters as $adapter => $priority) {
731 12 : $class = 'PEAR_PackageUpdate_Adapter_' . $adapter;
732 : // Attempt to include a custom version of the named class, but don't treat
733 : // a failure as fatal. The caller may have already included their own
734 : // version of the named class.
735 12 : if (!class_exists($class)) {
736 : // Try to include the driver.
737 3 : $file = str_replace('_', '/', $class) . '.php';
738 3 : if (PEAR_PackageUpdate::isIncludable($file)) {
739 2 : include_once $file;
740 2 : }
741 3 : }
742 12 : if (!class_exists($class)) {
743 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER,
744 1 : 'warning', array(), $adapter .' adapter is missing');
745 1 : continue;
746 : }
747 12 : $adapter = new $class($config, $this);
748 12 : if ($adapter->supports()) {
749 11 : $info = $adapter->sendRequest('package.info');
750 : // Check to make sure the package was found.
751 11 : if (PEAR::isError($info) || !isset($info['name'])) {
752 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_NOINFO, 'error',
753 0 : array('packagename' => $this->packageName));
754 0 : break;
755 : }
756 :
757 : // Pull out the latest information.
758 11 : $versions = array_keys($info['releases']);
759 11 : $this->latestVersion = reset($versions);
760 :
761 11 : $this->info = reset($info['releases']);
762 11 : $this->info['version'] = $this->latestVersion;
763 11 : $this->info['summary'] = $info['summary'];
764 11 : $this->info['description'] = $info['description'];
765 :
766 11 : return true;
767 : }
768 1 : }
769 :
770 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER,
771 1 : 'error', array(), 'No '.
772 1 : implode(',', array_keys($this->adapters)) . ' supported protocols');
773 1 : return false;
774 : }
775 :
776 : /**
777 : * Returns the preferences associated with the given package.
778 : *
779 : * The preferences returned are an array with the folling values:
780 : * - don't ask again
781 : * - don't ask until next version
782 : * - only ask for state x
783 : * - bug/minor/major updates only
784 : *
785 : * @access public
786 : * @return array
787 : * @since version 0.4.0a1 (2006-03-28)
788 : */
789 : function getPackagePreferences()
790 : {
791 9 : if (isset($this->preferences[$this->channel][$this->packageName])) {
792 4 : return $this->preferences[$this->channel][$this->packageName];
793 : } else {
794 6 : return array();
795 : }
796 : }
797 :
798 : /**
799 : * Saves the current preferences to the RC file.
800 : *
801 : * @param string $pref_file (optional) file to save PPU user-defined options to
802 : *
803 : * @access public
804 : * @return boolean true on success, false on error
805 : * @since version 0.4.0a1 (2006-03-28)
806 : * @throws PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEACCESS,
807 : * PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEERROR
808 : * @see determinePrefFile()
809 : */
810 : function savePreferences($pref_file = '')
811 : {
812 : // Get the file to save the preferences to.
813 14 : if (empty($pref_file)) {
814 0 : $prefFile = $this->determinePrefFile();
815 0 : } else {
816 14 : $prefFile = $pref_file;
817 : }
818 :
819 : // Open the file for writing.
820 14 : $fp = fopen($prefFile, 'w');
821 14 : if ($fp === false) {
822 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEACCESS,
823 0 : 'error', array('file' => $prefFile));
824 0 : return false;
825 : }
826 :
827 : // Serialize the contents.
828 14 : $serialCont = serialize($this->preferences);
829 :
830 : // Write the contents to the file.
831 14 : if (fwrite($fp, $serialCont) === false) {
832 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEERROR,
833 0 : 'error', array('file' => $prefFile));
834 0 : return false;
835 : }
836 :
837 : // Close the file.
838 14 : if (!fclose($fp)) {
839 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_PREFFILE_WRITEERROR,
840 0 : 'error', array('file' => $prefFile));
841 0 : return false;
842 : } else {
843 14 : $this->pref_file = $prefFile;
844 14 : return true;
845 : }
846 : }
847 :
848 : /**
849 : * Returns whether or not the user's preferences will allow an update to
850 : * take place.
851 : *
852 : * The user's preferences may define restrictions such as:
853 : * - don't update
854 : * - don't ask until next version (remembers last version asked)
855 : * - only ask for state XXXX or higher
856 : * - minor or higher (no bug fix)
857 : * - major only
858 : *
859 : * @access public
860 : * @return boolean true if the preferences will allow an update for the
861 : * latest version.
862 : * @since version 0.4.0a1 (2006-03-28)
863 : * @see getPackagePreferences()
864 : */
865 : function preferencesAllowUpdate()
866 : {
867 : // Get the preferences for the package.
868 9 : $prefs = $this->getPackagePreferences();
869 :
870 : // Check to see if the user wants to be notified about any updates for
871 : // this package.
872 9 : if (isset($prefs[PEAR_PACKAGEUPDATE_PREF_NOUPDATES])
873 1 : && $prefs[PEAR_PACKAGEUPDATE_PREF_NOUPDATES]
874 9 : ) {
875 1 : return false;
876 : }
877 :
878 : // Check to see if the user has requested not to be asked until a new
879 : // version is released.
880 8 : if (isset($prefs[PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE])
881 1 : && !version_compare($this->latestVersion,
882 1 : $prefs[PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE],
883 1 : '>')
884 8 : ) {
885 1 : return false;
886 : }
887 :
888 : // Check to see if the user has requested not to be asked about the
889 : // state of the latest release.
890 : // Create an array of states.
891 8 : $states = array(PEAR_PACKAGEUPDATE_STATE_SNAPSHOT => -1,
892 8 : PEAR_PACKAGEUPDATE_STATE_DEVEL => 0,
893 8 : PEAR_PACKAGEUPDATE_STATE_ALPHA => 1,
894 8 : PEAR_PACKAGEUPDATE_STATE_BETA => 2,
895 8 : PEAR_PACKAGEUPDATE_STATE_STABLE => 3
896 8 : );
897 8 : if (isset($prefs[PEAR_PACKAGEUPDATE_PREF_STATE])
898 1 : && $states[$prefs[PEAR_PACKAGEUPDATE_PREF_STATE]] >
899 1 : $states[$this->info['state']]
900 8 : ) {
901 1 : return false;
902 : }
903 :
904 : // Check to see if the user only wants to be asked about a certain
905 : // type of release (bug|minor|major).
906 : // Create an array for the types of releases.
907 7 : $releases = array(PEAR_PACKAGEUPDATE_TYPE_BUG => 0,
908 7 : PEAR_PACKAGEUPDATE_TYPE_MINOR => 1,
909 7 : PEAR_PACKAGEUPDATE_TYPE_MAJOR => 2
910 7 : );
911 7 : if (isset($prefs[PEAR_PACKAGEUPDATE_PREF_TYPE])
912 1 : && $releases[$prefs[PEAR_PACKAGEUPDATE_PREF_TYPE]] >
913 1 : $releases[$this->releaseType()]
914 7 : ) {
915 0 : return false;
916 : }
917 :
918 : // If we got down here, either there are no preferences for this
919 : // package or everything checked out.
920 7 : return true;
921 : }
922 :
923 : /**
924 : * Returns the type of release. (bug|minor|major);
925 : *
926 : * @access protected
927 : * @return string
928 : * @since version 0.4.0a1 (2006-03-28)
929 : */
930 : function releaseType()
931 : {
932 : // Break the two versions into pieces.
933 1 : $latest = explode('.', $this->latestVersion);
934 1 : $current = explode('.', $this->instVersion);
935 :
936 1 : if ($latest[0] > $current[0]) {
937 1 : $type = PEAR_PACKAGEUPDATE_TYPE_MAJOR;
938 1 : } elseif ($latest[1] > $current[1]) {
939 0 : $type = PEAR_PACKAGEUPDATE_TYPE_MINOR;
940 0 : } else {
941 0 : $type = PEAR_PACKAGEUPDATE_TYPE_BUG;
942 : }
943 :
944 1 : return $type;
945 : }
946 :
947 : /**
948 : * Returns informations about current installed version of the package
949 : *
950 : * @author Laurent Laville
951 : * @access public
952 : * @return array|bool false on error, data array otherwise
953 : * @since version 0.6.0 (2007-01-11)
954 : */
955 : function getInstalledRelease()
956 : {
957 11 : if (!$this->getPackageInfo()) {
958 1 : return false;
959 : }
960 :
961 10 : $config =& PEAR_Config::singleton($this->user_file, $this->system_file);
962 10 : $reg =&$config->getRegistry();
963 :
964 : // Get full installed data of the package.
965 10 : $this->instInfo = $reg->packageInfo($this->packageName, null,
966 10 : $this->channel);
967 10 : if (is_null($this->instInfo)) {
968 3 : $this->instVersion = '';
969 3 : } else {
970 7 : if ($this->instInfo['xsdversion'] == '1.0') {
971 6 : $this->instVersion = $this->instInfo['version'];
972 6 : } else {
973 1 : $this->instVersion = $this->instInfo['version']['release'];
974 : }
975 : }
976 :
977 : // If the package is not installed, create a dummy version.
978 10 : if (empty($this->instVersion)) {
979 3 : $this->instVersion = '0.0.0';
980 3 : }
981 :
982 10 : if (is_null($this->instInfo)) {
983 3 : $info = array('version' => $this->instVersion);
984 3 : } else {
985 : // compatibility for package.xml version 2.0
986 7 : if (isset($this->instInfo['old'])) {
987 1 : $instInfo = $this->instInfo['old'];
988 1 : $instInfo['packagerversion']
989 1 : = $this->instInfo['attribs']['packagerversion'];
990 1 : } else {
991 6 : $instInfo = $this->instInfo;
992 6 : if (!isset($instInfo['packagerversion'])) {
993 0 : $instInfo['packagerversion'] = '';
994 0 : }
995 : }
996 : $info = array(
997 7 : 'version' => $this->instVersion,
998 7 : 'license' => $instInfo['release_license'],
999 7 : 'summary' => $this->instInfo['summary'],
1000 7 : 'description' => $this->instInfo['description'],
1001 7 : 'releasedate' => $instInfo['release_date'],
1002 7 : 'releasenotes' => $instInfo['release_notes'],
1003 7 : 'state' => $instInfo['release_state'],
1004 7 : 'deps' => $instInfo['release_deps'],
1005 7 : 'xsdversion' => $this->instInfo['xsdversion'],
1006 7 : 'packagerversion' => $instInfo['packagerversion'],
1007 7 : );
1008 : }
1009 10 : return $info;
1010 : }
1011 :
1012 : /**
1013 : * Returns information on latest version available
1014 : *
1015 : * @author Laurent Laville
1016 : * @access public
1017 : * @return array|bool false on error, data array otherwise
1018 : * @since version 0.6.0 (2007-01-11)
1019 : */
1020 : function getLatestRelease()
1021 : {
1022 4 : if (!$this->getPackageInfo()) {
1023 2 : return false;
1024 : }
1025 2 : $info = $this->info;
1026 2 : unset($info['doneby']);
1027 2 : return $info;
1028 : }
1029 :
1030 : /**
1031 : * Sets the user's preference for asking about all updates for this
1032 : * package.
1033 : *
1034 : * @param boolean $dontAsk User's preference for asking about all updates
1035 : *
1036 : * @access public
1037 : * @return boolean true on success, false on failure
1038 : * @since version 0.4.0a1 (2006-03-28)
1039 : */
1040 : function setDontAskAgain($dontAsk)
1041 : {
1042 : // Make sure the value is a boolean.
1043 1 : settype($dontAsk, 'boolean');
1044 :
1045 : // Set the preference.
1046 1 : return $this->setPreference(PEAR_PACKAGEUPDATE_PREF_NOUPDATES, $dontAsk);
1047 : }
1048 :
1049 : /**
1050 : * Sets the user's preference for asking about updates again until the next
1051 : * release.
1052 : *
1053 : * @param boolean $nextrelease User's preference for asking about updates again
1054 : *
1055 : * @access public
1056 : * @return boolean true on success, false on failure
1057 : * @since version 0.4.0a1 (2006-03-28)
1058 : * @throws PEAR_PACKAGEUPDATE_ERROR_NOINFO
1059 : */
1060 : function setDontAskUntilNextRelease($nextrelease)
1061 : {
1062 : // If nextrelease is true, we have to swap its value out with the
1063 : // latest version.
1064 2 : if ($nextrelease) {
1065 : // Make sure that the package info was found.
1066 2 : if (empty($this->latestVersion)) {
1067 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_NOINFO);
1068 1 : return false;
1069 : }
1070 1 : $nextrelease = $this->latestVersion;
1071 1 : }
1072 :
1073 : // Set the preference.
1074 1 : return $this->setPreference(PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE,
1075 1 : $nextrelease);
1076 : }
1077 :
1078 : /**
1079 : * Sets the user's preference for asking about release types.
1080 : *
1081 : * @param string $minType The minimum release type to allow.
1082 : *
1083 : * @access public
1084 : * @return boolean true on success, false on failure
1085 : * @since version 0.4.0a1 (2006-03-28)
1086 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDTYPE
1087 : */
1088 : function setMinimumReleaseType($minType)
1089 : {
1090 : // Make sure the type is acceptable.
1091 : if ($minType != PEAR_PACKAGEUPDATE_TYPE_BUG
1092 2 : && $minType != PEAR_PACKAGEUPDATE_TYPE_MINOR
1093 2 : && $minType != PEAR_PACKAGEUPDATE_TYPE_MAJOR
1094 2 : ) {
1095 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDTYPE, 'error',
1096 1 : array('type' => $minType));
1097 1 : return false;
1098 : }
1099 :
1100 : // Set the preference.
1101 1 : return $this->setPreference(PEAR_PACKAGEUPDATE_PREF_TYPE, $minType);
1102 : }
1103 :
1104 : /**
1105 : * Sets the user's preference for asking about release states.
1106 : *
1107 : * @param string $minState The minimum release state to allow.
1108 : *
1109 : * @access public
1110 : * @return boolean true on success, false on failure
1111 : * @since version 0.4.0a1 (2006-03-28)
1112 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDSTATE
1113 : */
1114 : function setMinimumState($minState)
1115 : {
1116 : // Make sure the type is acceptable.
1117 : if ($minState != PEAR_PACKAGEUPDATE_STATE_SNAPSHOT
1118 2 : && $minState != PEAR_PACKAGEUPDATE_STATE_DEVEL
1119 2 : && $minState != PEAR_PACKAGEUPDATE_STATE_ALPHA
1120 2 : && $minState != PEAR_PACKAGEUPDATE_STATE_BETA
1121 2 : && $minState != PEAR_PACKAGEUPDATE_STATE_STABLE
1122 2 : ) {
1123 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDSTATE, 'error',
1124 1 : array('state' => $minState));
1125 1 : return false;
1126 : }
1127 :
1128 : // Set the preference.
1129 1 : return $this->setPreference(PEAR_PACKAGEUPDATE_PREF_STATE, $minState);
1130 : }
1131 :
1132 : /**
1133 : * Sets the given preference to the given value.
1134 : *
1135 : * Don't take any chances. Anytime a preference is set, the preferences are
1136 : * saved. We can't rely on the developer to call savePreferences.
1137 : *
1138 : * @param integer $pref One of the preference constants.
1139 : * @param mixed $value The value of the preference.
1140 : *
1141 : * @return boolean true if the preference was set and saved properly.
1142 : * @access protected
1143 : * @since version 0.4.0a1 (2006-03-28)
1144 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDPREF
1145 : */
1146 : function setPreference($pref, $value)
1147 : {
1148 : // Make sure the preference is valid.
1149 : if ($pref != PEAR_PACKAGEUPDATE_PREF_NOUPDATES
1150 4 : && $pref != PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE
1151 3 : && $pref != PEAR_PACKAGEUPDATE_PREF_TYPE
1152 2 : && $pref != PEAR_PACKAGEUPDATE_PREF_STATE
1153 4 : ) {
1154 : // Invalid preference!
1155 0 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDPREF, 'error',
1156 0 : array('preference' => $pref));
1157 0 : return false;
1158 : }
1159 :
1160 : // Make sure the preferences for the channel exist.
1161 4 : if (!isset($this->preferences[$this->channel])) {
1162 4 : $this->preferences[$this->channel] = array();
1163 4 : }
1164 :
1165 : // Make sure the preferences for the package exist.
1166 4 : if (!isset($this->preferences[$this->channel][$this->packageName])) {
1167 4 : $this->preferences[$this->channel][$this->packageName] = array();
1168 4 : }
1169 :
1170 : // Set the preference value.
1171 4 : $this->preferences[$this->channel][$this->packageName][$pref] = $value;
1172 :
1173 : // Save the preferences.
1174 4 : return $this->savePreferences($this->pref_file);
1175 : }
1176 :
1177 : /**
1178 : * Sets all preferences at once.
1179 : *
1180 : * @param array $preferences All user's preferences
1181 : *
1182 : * @return boolean true if the preferences were set and saved.
1183 : * @since version 0.4.0a1 (2006-03-28)
1184 : * @access public
1185 : */
1186 : function setPreferences($preferences)
1187 : {
1188 : // Make sure preferences is an array.
1189 1 : settype($preferences, 'array');
1190 :
1191 : // Make sure there is only valid preference information.
1192 1 : foreach ($preferences as $pref => $value) {
1193 : if ($pref != PEAR_PACKAGEUPDATE_PREF_NOUPDATES
1194 1 : && $pref != PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE
1195 1 : && $pref != PEAR_PACKAGEUPDATE_PREF_TYPE
1196 1 : && $pref != PEAR_PACKAGEUPDATE_PREF_STATE
1197 1 : ) {
1198 0 : unset($preferences[$pref]);
1199 0 : }
1200 1 : }
1201 :
1202 : // Make sure that next release has the latest release.
1203 1 : if ($preferences[PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE]) {
1204 1 : $preferences[PEAR_PACKAGEUPDATE_PREF_NEXTRELEASE] = $this->latestVersion;
1205 1 : }
1206 :
1207 : // Set the preferences.
1208 1 : $this->preferences[$this->channel][$this->packageName] = $preferences;
1209 :
1210 : // Save the preferences.
1211 1 : return $this->savePreferences($this->pref_file);
1212 : }
1213 :
1214 : /**
1215 : * Updates the source for the package.
1216 : *
1217 : * We have to update required dependencies automatically to make sure that
1218 : * everything still works properly.
1219 : *
1220 : * It is the developers responsibility to make sure the user is given the
1221 : * option to update any optional dependencies if needed. This can be done
1222 : * by creating a new instance of PEAR_PackageUpdate for the optional
1223 : * dependency.
1224 : *
1225 : * @access public
1226 : * @return boolean true if the update was successful.
1227 : * @since version 0.4.0a1 (2006-03-28)
1228 : * @throws PEAR_PACKAGEUPDATE_ERROR_NOTINSTALLED
1229 : */
1230 : function update()
1231 : {
1232 : // Create a config object.
1233 1 : $config =& PEAR_Config::singleton($this->user_file, $this->system_file);
1234 :
1235 : // Change the verbosity but keep track of the value to reset it just in
1236 : // case this does something permanent.
1237 1 : $verbose = $config->get('verbose');
1238 1 : $config->set('verbose', 0);
1239 :
1240 : // Create a command object to do the upgrade.
1241 : // If the current version is 0.0.0 don't upgrade. That would be a
1242 : // sneaky way for devs to install packages without the use knowing.
1243 1 : if ($this->instVersion == '0.0.0') {
1244 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_NOTINSTALLED, 'error',
1245 1 : array('packagename' => $this->packageName));
1246 1 : return false;
1247 : }
1248 :
1249 0 : include_once 'PEAR/Command.php';
1250 0 : $upgrade = PEAR_Command::factory('upgrade', $config);
1251 :
1252 : // Try to upgrade the application.
1253 0 : $channelPackage = $this->channel . '/' . $this->packageName;
1254 0 : $result = $upgrade->doInstall('upgrade',
1255 0 : array('onlyreqdeps' => true),
1256 0 : array($channelPackage));
1257 :
1258 : // Reset the verbose level just to be safe.
1259 0 : $config->set('verbose', $verbose);
1260 :
1261 : // Check for errors.
1262 0 : if (PEAR::isError($result)) {
1263 0 : $this->pushError($result);
1264 0 : return false;
1265 : } else {
1266 0 : return true;
1267 : }
1268 : }
1269 :
1270 : /**
1271 : * Redirects or exits to force the user to restart the application.
1272 : *
1273 : * @abstract
1274 : * @access public
1275 : * @return void
1276 : * @since version 0.4.0a1 (2006-03-28)
1277 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER
1278 : */
1279 : function forceRestart()
1280 : {
1281 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER,
1282 1 : 'exception',
1283 1 : array('function' => 'forceRestart'));
1284 1 : }
1285 :
1286 : /**
1287 : * Presents the user with the option to update.
1288 : *
1289 : * @abstract
1290 : * @access public
1291 : * @return boolean true if the user wants to update
1292 : * @since version 0.4.0a1 (2006-03-28)
1293 : * @throws PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER
1294 : */
1295 : function presentUpdate()
1296 : {
1297 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_INVALIDDRIVER,
1298 1 : 'exception',
1299 1 : array('function' => 'presentUpdate'));
1300 :
1301 : // Return false just in case something odd has happened.
1302 1 : return false;
1303 : }
1304 :
1305 : /**
1306 : * Pushes an error onto an error stack.
1307 : *
1308 : * This method is just for collecting errors that occur while checking for
1309 : * updates and updating a package. The child class is responsible for
1310 : * displaying all errors and handling them properly. This is because the
1311 : * way errors are handled varies greatly depending on the driver used.
1312 : *
1313 : * @param int $code Package-specific error code
1314 : * @param string $level Error level. This is NOT spell-checked
1315 : * @param array $params associative array of error parameters
1316 : * @param string $msg Error message, or a portion of it if the
1317 : * message is to be generated
1318 : * @param array $repackage If this error re-packages an error pushed by
1319 : * another package, place the array returned from
1320 : * {@link pop()} in this parameter
1321 : * @param array $backtrace Protected parameter: use this to pass in the
1322 : * {@link debug_backtrace()} that should be used
1323 : * to find error context
1324 : *
1325 : * @return PEAR_Error|array|Exception
1326 : * if compatibility mode is on, a PEAR_Error is
1327 : * also thrown. If the class Exception exists,
1328 : * then one is returned.
1329 : * @since version 0.4.0a1 (2006-03-28)
1330 : * @access public
1331 : */
1332 : function pushError($code, $level = 'error', $params = array(),
1333 : $msg = false, $repackage = false, $backtrace = false)
1334 : {
1335 : // Check to see if a PEAR_Error was pushed.
1336 15 : if (PEAR::isError($code)) {
1337 0 : return $this->repackagePEARError($code);
1338 : }
1339 :
1340 : // Check the arguments to see if just a code was submitted.
1341 15 : if (is_int($code)
1342 0 : && !(bool) $msg
1343 15 : && isset($GLOBALS['_PEAR_PACKAGEUPDATE_ERRORS'][$code])
1344 15 : ) {
1345 11 : $msg = $GLOBALS['_PEAR_PACKAGEUPDATE_ERRORS'][$code];
1346 11 : }
1347 :
1348 : // Append the error onto the stack.
1349 15 : return $this->errors->push($code, $level, $params, $msg,
1350 15 : $repackage, $backtrace);
1351 : }
1352 :
1353 : /**
1354 : * Repackages PEAR_Errors for use with ErrorStack.
1355 : *
1356 : * @param object &$error A PEAR_Error
1357 : *
1358 : * @return mixed The return from PEAR::ErrorStack::push()
1359 : * @since version 0.4.0a1 (2006-03-28)
1360 : * @access public
1361 : * @author Ian Eure <ieure@php.net>
1362 : */
1363 : function repackagePEARError(&$error)
1364 : {
1365 0 : static $map;
1366 0 : if (!isset($map)) {
1367 : $map = array(
1368 0 : E_ERROR => 'error',
1369 0 : E_WARNING => 'warning',
1370 0 : E_PARSE => 'exception',
1371 0 : E_NOTICE => 'notice',
1372 0 : E_CORE_ERROR => 'error',
1373 0 : E_CORE_WARNING => 'warning',
1374 0 : E_COMPILE_ERROR => 'exception',
1375 0 : E_COMPILE_WARNING => 'warning',
1376 0 : E_USER_ERROR => 'error',
1377 0 : E_USER_WARNING => 'warning',
1378 0 : E_USER_NOTICE => 'notice'
1379 0 : );
1380 0 : }
1381 :
1382 : // Strip this function from the trace
1383 0 : if (is_array($error->backtrace)) {
1384 0 : array_shift($error->backtrace);
1385 0 : $error->userinfo['backtrace'] =& $error->backtrace;
1386 0 : }
1387 :
1388 0 : return $this->errors->push($error->code, $map[$error->level],
1389 0 : $error->userinfo, $error->message, false,
1390 0 : $error->backtrace);
1391 : }
1392 :
1393 : /**
1394 : * Pops an error off the error stack.
1395 : *
1396 : * This method is just for collecting errors that occur while checking for
1397 : * updates and updating a package. The child class is responsible for
1398 : * displaying all errors and handling them properly. This is because the
1399 : * way errors are handled varies greatly depending on the driver used.
1400 : *
1401 : * @access public
1402 : * @return mixed details of an error (array) or false if no errors exist.
1403 : * @since version 0.4.0a1 (2006-03-28)
1404 : * @see hasErrors()
1405 : */
1406 : function popError()
1407 : {
1408 13 : return $this->errors->pop();
1409 : }
1410 :
1411 : /**
1412 : * Returns whether or not errors have occurred (and been captured).
1413 : *
1414 : * @param string|array $level Level name. Use to determine if any errors
1415 : * of level (string), or levels (array)
1416 : * have been pushed
1417 : *
1418 : * @access public
1419 : * @return boolean
1420 : * @since version 0.4.0a1 (2006-03-28)
1421 : * @see popError()
1422 : */
1423 : function hasErrors($level = false)
1424 : {
1425 14 : return $this->errors->hasErrors($level);
1426 : }
1427 :
1428 : /**
1429 : * Add an interface adapter
1430 : *
1431 : * Add an interface adapter to communicate with remote server.
1432 : * API 1.0.x did not support adapters yet
1433 : * API 1.1.0 support only 3 adapters (REST, XmlRPC and Soap)
1434 : * IMPORTANT: Soap adapter is not provided
1435 : *
1436 : * @param string $adapter Name of the adapter to use for remote access
1437 : * @param int $priority Priority level of usage to this adapter
1438 : * (the hightest level is used first)
1439 : *
1440 : * @access public
1441 : * @return bool
1442 : * @since version 1.1.0a1 (2009-02-28)
1443 : * @throws PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER
1444 : */
1445 : function addAdapter($adapter, $priority)
1446 : {
1447 15 : if (!is_string($adapter)) {
1448 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER,
1449 1 : 'exception', array(), 'adapter parameter #1 is not string');
1450 1 : return false;
1451 : }
1452 14 : if (!is_int($priority)) {
1453 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER,
1454 1 : 'exception', array(), 'priority parameter #2 is not integer');
1455 1 : return false;
1456 : }
1457 :
1458 13 : $adapters = array('REST' => 20, 'XmlRPC' => 10, 'Soap' => 1);
1459 13 : $add = array_key_exists($adapter, $adapters);
1460 :
1461 13 : if ($add) {
1462 12 : $this->adapters[$adapter] = $priority;
1463 12 : } else {
1464 1 : $this->pushError(PEAR_PACKAGEUPDATE_ERROR_WRONGADAPTER,
1465 1 : 'error', array('adapter' => $adapter));
1466 : }
1467 13 : }
1468 : }
|