├── README.rst ├── composer.json └── src ├── OS └── Guess.php ├── PEAR.php ├── PEAR └── ErrorStack.php └── System.php /README.rst: -------------------------------------------------------------------------------- 1 | ****************************** 2 | Minimal set of PEAR core files 3 | ****************************** 4 | 5 | This repository provides a set of files from ``pear-core`` 6 | that are often used in PEAR packages. 7 | 8 | It follows the `pear-core`__ repository and gets updated whenever a new 9 | PEAR version is released. 10 | 11 | It's meant to be used as dependency for composer packages. 12 | 13 | __ https://github.com/pear/pear-core 14 | 15 | ============== 16 | Included files 17 | ============== 18 | - ``OS/Guess.php`` 19 | - ``PEAR.php`` 20 | - ``PEAR/ErrorStack.php`` 21 | - ``System.php`` 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pear/pear-core-minimal", 3 | "description": "Minimal set of PEAR core files to be used as composer dependency", 4 | "license": "BSD-3-Clause", 5 | "authors": [ 6 | { 7 | "email": "cweiske@php.net", 8 | "name": "Christian Weiske", 9 | "role": "Lead" 10 | } 11 | ], 12 | "autoload": { 13 | "classmap": [ 14 | "src/" 15 | ] 16 | }, 17 | "include-path": [ 18 | "src/" 19 | ], 20 | "support": { 21 | "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", 22 | "source": "https://github.com/pear/pear-core-minimal" 23 | }, 24 | "type": "library", 25 | "require": { 26 | "php": ">=5.4", 27 | "pear/console_getopt": "~1.4", 28 | "pear/pear_exception": "~1.0" 29 | }, 30 | "replace": { 31 | "rsky/pear-core-min": "self.version" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/OS/Guess.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Gregory Beaver 11 | * @copyright 1997-2009 The Authors 12 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 13 | * @link http://pear.php.net/package/PEAR 14 | * @since File available since PEAR 0.1 15 | */ 16 | 17 | // {{{ uname examples 18 | 19 | // php_uname() without args returns the same as 'uname -a', or a PHP-custom 20 | // string for Windows. 21 | // PHP versions prior to 4.3 return the uname of the host where PHP was built, 22 | // as of 4.3 it returns the uname of the host running the PHP code. 23 | // 24 | // PC RedHat Linux 7.1: 25 | // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown 26 | // 27 | // PC Debian Potato: 28 | // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown 29 | // 30 | // PC FreeBSD 3.3: 31 | // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 32 | // 33 | // PC FreeBSD 4.3: 34 | // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 35 | // 36 | // PC FreeBSD 4.5: 37 | // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 38 | // 39 | // PC FreeBSD 4.5 w/uname from GNU shellutils: 40 | // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown 41 | // 42 | // HP 9000/712 HP-UX 10: 43 | // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license 44 | // 45 | // HP 9000/712 HP-UX 10 w/uname from GNU shellutils: 46 | // HP-UX host B.10.10 A 9000/712 unknown 47 | // 48 | // IBM RS6000/550 AIX 4.3: 49 | // AIX host 3 4 000003531C00 50 | // 51 | // AIX 4.3 w/uname from GNU shellutils: 52 | // AIX host 3 4 000003531C00 unknown 53 | // 54 | // SGI Onyx IRIX 6.5 w/uname from GNU shellutils: 55 | // IRIX64 host 6.5 01091820 IP19 mips 56 | // 57 | // SGI Onyx IRIX 6.5: 58 | // IRIX64 host 6.5 01091820 IP19 59 | // 60 | // SparcStation 20 Solaris 8 w/uname from GNU shellutils: 61 | // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc 62 | // 63 | // SparcStation 20 Solaris 8: 64 | // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 65 | // 66 | // Mac OS X (Darwin) 67 | // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh 68 | // 69 | // Mac OS X early versions 70 | // 71 | 72 | // }}} 73 | 74 | /* TODO: 75 | * - define endianness, to allow matchSignature("bigend") etc. 76 | */ 77 | 78 | /** 79 | * Retrieves information about the current operating system 80 | * 81 | * This class uses php_uname() to grok information about the current OS 82 | * 83 | * @category pear 84 | * @package PEAR 85 | * @author Stig Bakken 86 | * @author Gregory Beaver 87 | * @copyright 1997-2020 The Authors 88 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 89 | * @version Release: @package_version@ 90 | * @link http://pear.php.net/package/PEAR 91 | * @since Class available since Release 0.1 92 | */ 93 | class OS_Guess 94 | { 95 | var $sysname; 96 | var $nodename; 97 | var $cpu; 98 | var $release; 99 | var $extra; 100 | 101 | function __construct($uname = null) 102 | { 103 | list($this->sysname, 104 | $this->release, 105 | $this->cpu, 106 | $this->extra, 107 | $this->nodename) = $this->parseSignature($uname); 108 | } 109 | 110 | function parseSignature($uname = null) 111 | { 112 | static $sysmap = array( 113 | 'HP-UX' => 'hpux', 114 | 'IRIX64' => 'irix', 115 | ); 116 | static $cpumap = array( 117 | 'i586' => 'i386', 118 | 'i686' => 'i386', 119 | 'ppc' => 'powerpc', 120 | ); 121 | if ($uname === null) { 122 | $uname = php_uname(); 123 | } 124 | $parts = preg_split('/\s+/', trim($uname)); 125 | $n = count($parts); 126 | 127 | $release = $machine = $cpu = ''; 128 | $sysname = $parts[0]; 129 | $nodename = $parts[1]; 130 | $cpu = $parts[$n-1]; 131 | $extra = ''; 132 | if ($cpu == 'unknown') { 133 | $cpu = $parts[$n - 2]; 134 | } 135 | 136 | switch ($sysname) { 137 | case 'AIX' : 138 | $release = "$parts[3].$parts[2]"; 139 | break; 140 | case 'Windows' : 141 | $release = $parts[1]; 142 | if ($release == '95/98') { 143 | $release = '9x'; 144 | } 145 | $cpu = 'i386'; 146 | break; 147 | case 'Linux' : 148 | $extra = $this->_detectGlibcVersion(); 149 | // use only the first two digits from the kernel version 150 | $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); 151 | break; 152 | case 'Mac' : 153 | $sysname = 'darwin'; 154 | $nodename = $parts[2]; 155 | $release = $parts[3]; 156 | $cpu = $this->_determineIfPowerpc($cpu, $parts); 157 | break; 158 | case 'Darwin' : 159 | $cpu = $this->_determineIfPowerpc($cpu, $parts); 160 | $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); 161 | break; 162 | default: 163 | $release = preg_replace('/-.*/', '', $parts[2]); 164 | break; 165 | } 166 | 167 | if (isset($sysmap[$sysname])) { 168 | $sysname = $sysmap[$sysname]; 169 | } else { 170 | $sysname = strtolower($sysname); 171 | } 172 | if (isset($cpumap[$cpu])) { 173 | $cpu = $cpumap[$cpu]; 174 | } 175 | return array($sysname, $release, $cpu, $extra, $nodename); 176 | } 177 | 178 | function _determineIfPowerpc($cpu, $parts) 179 | { 180 | $n = count($parts); 181 | if ($cpu == 'Macintosh' && $parts[$n - 2] == 'Power') { 182 | $cpu = 'powerpc'; 183 | } 184 | return $cpu; 185 | } 186 | 187 | function _detectGlibcVersion() 188 | { 189 | static $glibc = false; 190 | if ($glibc !== false) { 191 | return $glibc; // no need to run this multiple times 192 | } 193 | $major = $minor = 0; 194 | include_once "System.php"; 195 | 196 | // Let's try reading possible libc.so.6 symlinks 197 | $libcs = array( 198 | '/lib64/libc.so.6', 199 | '/lib/libc.so.6', 200 | '/lib/i386-linux-gnu/libc.so.6' 201 | ); 202 | $versions = array(); 203 | foreach ($libcs as $file) { 204 | $versions = $this->_readGlibCVersionFromSymlink($file); 205 | if ($versions != []) { 206 | list($major, $minor) = $versions; 207 | break; 208 | } 209 | } 210 | 211 | // Use glibc's header file to 212 | // get major and minor version number: 213 | if (!($major && $minor)) { 214 | $versions = $this->_readGlibCVersionFromFeaturesHeaderFile(); 215 | } 216 | if (is_array($versions) && $versions != []) { 217 | list($major, $minor) = $versions; 218 | } 219 | 220 | if (!($major && $minor)) { 221 | return $glibc = ''; 222 | } 223 | 224 | return $glibc = "glibc{$major}.{$minor}"; 225 | } 226 | 227 | function _readGlibCVersionFromSymlink($file) 228 | { 229 | $versions = array(); 230 | if (@is_link($file) 231 | && (preg_match('/^libc-(.*)\.so$/', basename(readlink($file)), $matches)) 232 | ) { 233 | $versions = explode('.', $matches[1]); 234 | } 235 | return $versions; 236 | } 237 | 238 | 239 | function _readGlibCVersionFromFeaturesHeaderFile() 240 | { 241 | $features_header_file = '/usr/include/features.h'; 242 | if (!(@file_exists($features_header_file) 243 | && @is_readable($features_header_file)) 244 | ) { 245 | return array(); 246 | } 247 | if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { 248 | return $this->_parseFeaturesHeaderFile($features_header_file); 249 | } // no cpp 250 | 251 | return $this->_fromGlibCTest(); 252 | } 253 | 254 | function _parseFeaturesHeaderFile($features_header_file) 255 | { 256 | $features_file = fopen($features_header_file, 'rb'); 257 | while (!feof($features_file)) { 258 | $line = fgets($features_file, 8192); 259 | if (!$this->_IsADefinition($line)) { 260 | continue; 261 | } 262 | if (strpos($line, '__GLIBC__')) { 263 | // major version number #define __GLIBC__ version 264 | $line = preg_split('/\s+/', $line); 265 | $glibc_major = trim($line[2]); 266 | if (isset($glibc_minor)) { 267 | break; 268 | } 269 | continue; 270 | } 271 | 272 | if (strpos($line, '__GLIBC_MINOR__')) { 273 | // got the minor version number 274 | // #define __GLIBC_MINOR__ version 275 | $line = preg_split('/\s+/', $line); 276 | $glibc_minor = trim($line[2]); 277 | if (isset($glibc_major)) { 278 | break; 279 | } 280 | } 281 | } 282 | fclose($features_file); 283 | if (!isset($glibc_major) || !isset($glibc_minor)) { 284 | return array(); 285 | } 286 | return array(trim($glibc_major), trim($glibc_minor)); 287 | } 288 | 289 | function _IsADefinition($line) 290 | { 291 | if ($line === false) { 292 | return false; 293 | } 294 | return strpos(trim($line), '#define') !== false; 295 | } 296 | 297 | function _fromGlibCTest() 298 | { 299 | $major = null; 300 | $minor = null; 301 | 302 | $tmpfile = System::mktemp("glibctest"); 303 | $fp = fopen($tmpfile, "w"); 304 | fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); 305 | fclose($fp); 306 | $cpp = popen("/usr/bin/cpp $tmpfile", "r"); 307 | while ($line = fgets($cpp, 1024)) { 308 | if ($line[0] == '#' || trim($line) == '') { 309 | continue; 310 | } 311 | 312 | if (list($major, $minor) = explode(' ', trim($line))) { 313 | break; 314 | } 315 | } 316 | pclose($cpp); 317 | unlink($tmpfile); 318 | if ($major !== null && $minor !== null) { 319 | return [$major, $minor]; 320 | } 321 | } 322 | 323 | function getSignature() 324 | { 325 | if (empty($this->extra)) { 326 | return "{$this->sysname}-{$this->release}-{$this->cpu}"; 327 | } 328 | return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; 329 | } 330 | 331 | function getSysname() 332 | { 333 | return $this->sysname; 334 | } 335 | 336 | function getNodename() 337 | { 338 | return $this->nodename; 339 | } 340 | 341 | function getCpu() 342 | { 343 | return $this->cpu; 344 | } 345 | 346 | function getRelease() 347 | { 348 | return $this->release; 349 | } 350 | 351 | function getExtra() 352 | { 353 | return $this->extra; 354 | } 355 | 356 | function matchSignature($match) 357 | { 358 | $fragments = is_array($match) ? $match : explode('-', $match); 359 | $n = count($fragments); 360 | $matches = 0; 361 | if ($n > 0) { 362 | $matches += $this->_matchFragment($fragments[0], $this->sysname); 363 | } 364 | if ($n > 1) { 365 | $matches += $this->_matchFragment($fragments[1], $this->release); 366 | } 367 | if ($n > 2) { 368 | $matches += $this->_matchFragment($fragments[2], $this->cpu); 369 | } 370 | if ($n > 3) { 371 | $matches += $this->_matchFragment($fragments[3], $this->extra); 372 | } 373 | return ($matches == $n); 374 | } 375 | 376 | function _matchFragment($fragment, $value) 377 | { 378 | if (strcspn($fragment, '*?') < strlen($fragment)) { 379 | $expression = str_replace( 380 | array('*', '?', '/'), 381 | array('.*', '.', '\\/'), 382 | $fragment 383 | ); 384 | $reg = '/^' . $expression . '\\z/'; 385 | return preg_match($reg, $value); 386 | } 387 | return ($fragment == '*' || !strcasecmp($fragment, $value)); 388 | } 389 | } 390 | /* 391 | * Local Variables: 392 | * indent-tabs-mode: nil 393 | * c-basic-offset: 4 394 | * End: 395 | */ 396 | -------------------------------------------------------------------------------- /src/PEAR.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Stig Bakken 13 | * @author Tomas V.V.Cox 14 | * @author Greg Beaver 15 | * @copyright 1997-2010 The Authors 16 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 17 | * @link http://pear.php.net/package/PEAR 18 | * @since File available since Release 0.1 19 | */ 20 | 21 | /**#@+ 22 | * ERROR constants 23 | */ 24 | define('PEAR_ERROR_RETURN', 1); 25 | define('PEAR_ERROR_PRINT', 2); 26 | define('PEAR_ERROR_TRIGGER', 4); 27 | define('PEAR_ERROR_DIE', 8); 28 | define('PEAR_ERROR_CALLBACK', 16); 29 | /** 30 | * WARNING: obsolete 31 | * @deprecated 32 | */ 33 | define('PEAR_ERROR_EXCEPTION', 32); 34 | /**#@-*/ 35 | 36 | if (substr(PHP_OS, 0, 3) == 'WIN') { 37 | define('OS_WINDOWS', true); 38 | define('OS_UNIX', false); 39 | define('PEAR_OS', 'Windows'); 40 | } else { 41 | define('OS_WINDOWS', false); 42 | define('OS_UNIX', true); 43 | define('PEAR_OS', 'Unix'); // blatant assumption 44 | } 45 | 46 | $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; 47 | $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; 48 | $GLOBALS['_PEAR_destructor_object_list'] = array(); 49 | $GLOBALS['_PEAR_shutdown_funcs'] = array(); 50 | $GLOBALS['_PEAR_error_handler_stack'] = array(); 51 | 52 | if(function_exists('ini_set')) { 53 | @ini_set('track_errors', true); 54 | } 55 | 56 | /** 57 | * Base class for other PEAR classes. Provides rudimentary 58 | * emulation of destructors. 59 | * 60 | * If you want a destructor in your class, inherit PEAR and make a 61 | * destructor method called _yourclassname (same name as the 62 | * constructor, but with a "_" prefix). Also, in your constructor you 63 | * have to call the PEAR constructor: $this->PEAR();. 64 | * The destructor method will be called without parameters. Note that 65 | * at in some SAPI implementations (such as Apache), any output during 66 | * the request shutdown (in which destructors are called) seems to be 67 | * discarded. If you need to get any debug information from your 68 | * destructor, use error_log(), syslog() or something similar. 69 | * 70 | * IMPORTANT! To use the emulated destructors you need to create the 71 | * objects by reference: $obj =& new PEAR_child; 72 | * 73 | * @category pear 74 | * @package PEAR 75 | * @author Stig Bakken 76 | * @author Tomas V.V. Cox 77 | * @author Greg Beaver 78 | * @copyright 1997-2006 The PHP Group 79 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 80 | * @version Release: @package_version@ 81 | * @link http://pear.php.net/package/PEAR 82 | * @see PEAR_Error 83 | * @since Class available since PHP 4.0.2 84 | * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear 85 | */ 86 | class PEAR 87 | { 88 | /** 89 | * Whether to enable internal debug messages. 90 | * 91 | * @var bool 92 | * @access private 93 | */ 94 | var $_debug = false; 95 | 96 | /** 97 | * Default error mode for this object. 98 | * 99 | * @var int 100 | * @access private 101 | */ 102 | var $_default_error_mode = null; 103 | 104 | /** 105 | * Default error options used for this object when error mode 106 | * is PEAR_ERROR_TRIGGER. 107 | * 108 | * @var int 109 | * @access private 110 | */ 111 | var $_default_error_options = null; 112 | 113 | /** 114 | * Default error handler (callback) for this object, if error mode is 115 | * PEAR_ERROR_CALLBACK. 116 | * 117 | * @var string 118 | * @access private 119 | */ 120 | var $_default_error_handler = ''; 121 | 122 | /** 123 | * Which class to use for error objects. 124 | * 125 | * @var string 126 | * @access private 127 | */ 128 | var $_error_class = 'PEAR_Error'; 129 | 130 | /** 131 | * An array of expected errors. 132 | * 133 | * @var array 134 | * @access private 135 | */ 136 | var $_expected_errors = array(); 137 | 138 | /** 139 | * List of methods that can be called both statically and non-statically. 140 | * @var array 141 | */ 142 | protected static $bivalentMethods = array( 143 | 'setErrorHandling' => true, 144 | 'raiseError' => true, 145 | 'throwError' => true, 146 | 'pushErrorHandling' => true, 147 | 'popErrorHandling' => true, 148 | ); 149 | 150 | /** 151 | * Constructor. Registers this object in 152 | * $_PEAR_destructor_object_list for destructor emulation if a 153 | * destructor object exists. 154 | * 155 | * @param string $error_class (optional) which class to use for 156 | * error objects, defaults to PEAR_Error. 157 | * @access public 158 | * @return void 159 | */ 160 | function __construct($error_class = null) 161 | { 162 | $classname = strtolower(get_class($this)); 163 | if ($this->_debug) { 164 | print "PEAR constructor called, class=$classname\n"; 165 | } 166 | 167 | if ($error_class !== null) { 168 | $this->_error_class = $error_class; 169 | } 170 | 171 | while ($classname && strcasecmp($classname, "pear")) { 172 | $destructor = "_$classname"; 173 | if (method_exists($this, $destructor)) { 174 | global $_PEAR_destructor_object_list; 175 | $_PEAR_destructor_object_list[] = $this; 176 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { 177 | register_shutdown_function("_PEAR_call_destructors"); 178 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; 179 | } 180 | break; 181 | } else { 182 | $classname = get_parent_class($classname); 183 | } 184 | } 185 | } 186 | 187 | /** 188 | * Only here for backwards compatibility. 189 | * E.g. Archive_Tar calls $this->PEAR() in its constructor. 190 | * 191 | * @param string $error_class Which class to use for error objects, 192 | * defaults to PEAR_Error. 193 | */ 194 | public function PEAR($error_class = null) 195 | { 196 | self::__construct($error_class); 197 | } 198 | 199 | /** 200 | * Destructor (the emulated type of...). Does nothing right now, 201 | * but is included for forward compatibility, so subclass 202 | * destructors should always call it. 203 | * 204 | * See the note in the class desciption about output from 205 | * destructors. 206 | * 207 | * @access public 208 | * @return void 209 | */ 210 | function _PEAR() { 211 | if ($this->_debug) { 212 | printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); 213 | } 214 | } 215 | 216 | public function __call($method, $arguments) 217 | { 218 | if (!isset(self::$bivalentMethods[$method])) { 219 | trigger_error( 220 | 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR 221 | ); 222 | } 223 | return call_user_func_array( 224 | array(__CLASS__, '_' . $method), 225 | array_merge(array($this), $arguments) 226 | ); 227 | } 228 | 229 | public static function __callStatic($method, $arguments) 230 | { 231 | if (!isset(self::$bivalentMethods[$method])) { 232 | trigger_error( 233 | 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR 234 | ); 235 | } 236 | return call_user_func_array( 237 | array(__CLASS__, '_' . $method), 238 | array_merge(array(null), $arguments) 239 | ); 240 | } 241 | 242 | /** 243 | * If you have a class that's mostly/entirely static, and you need static 244 | * properties, you can use this method to simulate them. Eg. in your method(s) 245 | * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); 246 | * You MUST use a reference, or they will not persist! 247 | * 248 | * @param string $class The calling classname, to prevent clashes 249 | * @param string $var The variable to retrieve. 250 | * @return mixed A reference to the variable. If not set it will be 251 | * auto initialised to NULL. 252 | */ 253 | public static function &getStaticProperty($class, $var) 254 | { 255 | static $properties; 256 | if (!isset($properties[$class])) { 257 | $properties[$class] = array(); 258 | } 259 | 260 | if (!array_key_exists($var, $properties[$class])) { 261 | $properties[$class][$var] = null; 262 | } 263 | 264 | return $properties[$class][$var]; 265 | } 266 | 267 | /** 268 | * Use this function to register a shutdown method for static 269 | * classes. 270 | * 271 | * @param mixed $func The function name (or array of class/method) to call 272 | * @param mixed $args The arguments to pass to the function 273 | * 274 | * @return void 275 | */ 276 | public static function registerShutdownFunc($func, $args = array()) 277 | { 278 | // if we are called statically, there is a potential 279 | // that no shutdown func is registered. Bug #6445 280 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { 281 | register_shutdown_function("_PEAR_call_destructors"); 282 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; 283 | } 284 | $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); 285 | } 286 | 287 | /** 288 | * Tell whether a value is a PEAR error. 289 | * 290 | * @param mixed $data the value to test 291 | * @param int $code if $data is an error object, return true 292 | * only if $code is a string and 293 | * $obj->getMessage() == $code or 294 | * $code is an integer and $obj->getCode() == $code 295 | * 296 | * @return bool true if parameter is an error 297 | */ 298 | public static function isError($data, $code = null) 299 | { 300 | if (!is_a($data, 'PEAR_Error')) { 301 | return false; 302 | } 303 | 304 | if (is_null($code)) { 305 | return true; 306 | } elseif (is_string($code)) { 307 | return $data->getMessage() == $code; 308 | } 309 | 310 | return $data->getCode() == $code; 311 | } 312 | 313 | /** 314 | * Sets how errors generated by this object should be handled. 315 | * Can be invoked both in objects and statically. If called 316 | * statically, setErrorHandling sets the default behaviour for all 317 | * PEAR objects. If called in an object, setErrorHandling sets 318 | * the default behaviour for that object. 319 | * 320 | * @param object $object 321 | * Object the method was called on (non-static mode) 322 | * 323 | * @param int $mode 324 | * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 325 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 326 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. 327 | * 328 | * @param mixed $options 329 | * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one 330 | * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 331 | * 332 | * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected 333 | * to be the callback function or method. A callback 334 | * function is a string with the name of the function, a 335 | * callback method is an array of two elements: the element 336 | * at index 0 is the object, and the element at index 1 is 337 | * the name of the method to call in the object. 338 | * 339 | * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is 340 | * a printf format string used when printing the error 341 | * message. 342 | * 343 | * @access public 344 | * @return void 345 | * @see PEAR_ERROR_RETURN 346 | * @see PEAR_ERROR_PRINT 347 | * @see PEAR_ERROR_TRIGGER 348 | * @see PEAR_ERROR_DIE 349 | * @see PEAR_ERROR_CALLBACK 350 | * @see PEAR_ERROR_EXCEPTION 351 | * 352 | * @since PHP 4.0.5 353 | */ 354 | protected static function _setErrorHandling( 355 | $object, $mode = null, $options = null 356 | ) { 357 | if ($object !== null) { 358 | $setmode = &$object->_default_error_mode; 359 | $setoptions = &$object->_default_error_options; 360 | } else { 361 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 362 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 363 | } 364 | 365 | switch ($mode) { 366 | case PEAR_ERROR_EXCEPTION: 367 | case PEAR_ERROR_RETURN: 368 | case PEAR_ERROR_PRINT: 369 | case PEAR_ERROR_TRIGGER: 370 | case PEAR_ERROR_DIE: 371 | case null: 372 | $setmode = $mode; 373 | $setoptions = $options; 374 | break; 375 | 376 | case PEAR_ERROR_CALLBACK: 377 | $setmode = $mode; 378 | // class/object method callback 379 | if (is_callable($options)) { 380 | $setoptions = $options; 381 | } else { 382 | trigger_error("invalid error callback", E_USER_WARNING); 383 | } 384 | break; 385 | 386 | default: 387 | trigger_error("invalid error mode", E_USER_WARNING); 388 | break; 389 | } 390 | } 391 | 392 | /** 393 | * This method is used to tell which errors you expect to get. 394 | * Expected errors are always returned with error mode 395 | * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, 396 | * and this method pushes a new element onto it. The list of 397 | * expected errors are in effect until they are popped off the 398 | * stack with the popExpect() method. 399 | * 400 | * Note that this method can not be called statically 401 | * 402 | * @param mixed $code a single error code or an array of error codes to expect 403 | * 404 | * @return int the new depth of the "expected errors" stack 405 | * @access public 406 | */ 407 | function expectError($code = '*') 408 | { 409 | if (is_array($code)) { 410 | array_push($this->_expected_errors, $code); 411 | } else { 412 | array_push($this->_expected_errors, array($code)); 413 | } 414 | return count($this->_expected_errors); 415 | } 416 | 417 | /** 418 | * This method pops one element off the expected error codes 419 | * stack. 420 | * 421 | * @return array the list of error codes that were popped 422 | */ 423 | function popExpect() 424 | { 425 | return array_pop($this->_expected_errors); 426 | } 427 | 428 | /** 429 | * This method checks unsets an error code if available 430 | * 431 | * @param mixed error code 432 | * @return bool true if the error code was unset, false otherwise 433 | * @access private 434 | * @since PHP 4.3.0 435 | */ 436 | function _checkDelExpect($error_code) 437 | { 438 | $deleted = false; 439 | foreach ($this->_expected_errors as $key => $error_array) { 440 | if (in_array($error_code, $error_array)) { 441 | unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); 442 | $deleted = true; 443 | } 444 | 445 | // clean up empty arrays 446 | if (0 == count($this->_expected_errors[$key])) { 447 | unset($this->_expected_errors[$key]); 448 | } 449 | } 450 | 451 | return $deleted; 452 | } 453 | 454 | /** 455 | * This method deletes all occurrences of the specified element from 456 | * the expected error codes stack. 457 | * 458 | * @param mixed $error_code error code that should be deleted 459 | * @return mixed list of error codes that were deleted or error 460 | * @access public 461 | * @since PHP 4.3.0 462 | */ 463 | function delExpect($error_code) 464 | { 465 | $deleted = false; 466 | if ((is_array($error_code) && (0 != count($error_code)))) { 467 | // $error_code is a non-empty array here; we walk through it trying 468 | // to unset all values 469 | foreach ($error_code as $key => $error) { 470 | $deleted = $this->_checkDelExpect($error) ? true : false; 471 | } 472 | 473 | return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 474 | } elseif (!empty($error_code)) { 475 | // $error_code comes alone, trying to unset it 476 | if ($this->_checkDelExpect($error_code)) { 477 | return true; 478 | } 479 | 480 | return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME 481 | } 482 | 483 | // $error_code is empty 484 | return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME 485 | } 486 | 487 | /** 488 | * This method is a wrapper that returns an instance of the 489 | * configured error class with this object's default error 490 | * handling applied. If the $mode and $options parameters are not 491 | * specified, the object's defaults are used. 492 | * 493 | * @param mixed $message a text error message or a PEAR error object 494 | * 495 | * @param int $code a numeric error code (it is up to your class 496 | * to define these if you want to use codes) 497 | * 498 | * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, 499 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, 500 | * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. 501 | * 502 | * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter 503 | * specifies the PHP-internal error level (one of 504 | * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). 505 | * If $mode is PEAR_ERROR_CALLBACK, this 506 | * parameter specifies the callback function or 507 | * method. In other error modes this parameter 508 | * is ignored. 509 | * 510 | * @param string $userinfo If you need to pass along for example debug 511 | * information, this parameter is meant for that. 512 | * 513 | * @param string $error_class The returned error object will be 514 | * instantiated from this class, if specified. 515 | * 516 | * @param bool $skipmsg If true, raiseError will only pass error codes, 517 | * the error message parameter will be dropped. 518 | * 519 | * @return object a PEAR error object 520 | * @see PEAR::setErrorHandling 521 | * @since PHP 4.0.5 522 | */ 523 | protected static function _raiseError($object, 524 | $message = null, 525 | $code = null, 526 | $mode = null, 527 | $options = null, 528 | $userinfo = null, 529 | $error_class = null, 530 | $skipmsg = false) 531 | { 532 | // The error is yet a PEAR error object 533 | if (is_object($message)) { 534 | $code = $message->getCode(); 535 | $userinfo = $message->getUserInfo(); 536 | $error_class = $message->getType(); 537 | $message->error_message_prefix = ''; 538 | $message = $message->getMessage(); 539 | } 540 | 541 | if ( 542 | $object !== null && 543 | isset($object->_expected_errors) && 544 | count($object->_expected_errors) > 0 && 545 | count($exp = end($object->_expected_errors)) 546 | ) { 547 | if ($exp[0] === "*" || 548 | (is_int(reset($exp)) && in_array($code, $exp)) || 549 | (is_string(reset($exp)) && in_array($message, $exp)) 550 | ) { 551 | $mode = PEAR_ERROR_RETURN; 552 | } 553 | } 554 | 555 | // No mode given, try global ones 556 | if ($mode === null) { 557 | // Class error handler 558 | if ($object !== null && isset($object->_default_error_mode)) { 559 | $mode = $object->_default_error_mode; 560 | $options = $object->_default_error_options; 561 | // Global error handler 562 | } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { 563 | $mode = $GLOBALS['_PEAR_default_error_mode']; 564 | $options = $GLOBALS['_PEAR_default_error_options']; 565 | } 566 | } 567 | 568 | if ($error_class !== null) { 569 | $ec = $error_class; 570 | } elseif ($object !== null && isset($object->_error_class)) { 571 | $ec = $object->_error_class; 572 | } else { 573 | $ec = 'PEAR_Error'; 574 | } 575 | 576 | if ($skipmsg) { 577 | $a = new $ec($code, $mode, $options, $userinfo); 578 | } else { 579 | $a = new $ec($message, $code, $mode, $options, $userinfo); 580 | } 581 | 582 | return $a; 583 | } 584 | 585 | /** 586 | * Simpler form of raiseError with fewer options. In most cases 587 | * message, code and userinfo are enough. 588 | * 589 | * @param mixed $message a text error message or a PEAR error object 590 | * 591 | * @param int $code a numeric error code (it is up to your class 592 | * to define these if you want to use codes) 593 | * 594 | * @param string $userinfo If you need to pass along for example debug 595 | * information, this parameter is meant for that. 596 | * 597 | * @return object a PEAR error object 598 | * @see PEAR::raiseError 599 | */ 600 | protected static function _throwError($object, $message = null, $code = null, $userinfo = null) 601 | { 602 | if ($object !== null) { 603 | $a = $object->raiseError($message, $code, null, null, $userinfo); 604 | return $a; 605 | } 606 | 607 | $a = PEAR::raiseError($message, $code, null, null, $userinfo); 608 | return $a; 609 | } 610 | 611 | public static function staticPushErrorHandling($mode, $options = null) 612 | { 613 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 614 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 615 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 616 | $stack[] = array($def_mode, $def_options); 617 | switch ($mode) { 618 | case PEAR_ERROR_EXCEPTION: 619 | case PEAR_ERROR_RETURN: 620 | case PEAR_ERROR_PRINT: 621 | case PEAR_ERROR_TRIGGER: 622 | case PEAR_ERROR_DIE: 623 | case null: 624 | $def_mode = $mode; 625 | $def_options = $options; 626 | break; 627 | 628 | case PEAR_ERROR_CALLBACK: 629 | $def_mode = $mode; 630 | // class/object method callback 631 | if (is_callable($options)) { 632 | $def_options = $options; 633 | } else { 634 | trigger_error("invalid error callback", E_USER_WARNING); 635 | } 636 | break; 637 | 638 | default: 639 | trigger_error("invalid error mode", E_USER_WARNING); 640 | break; 641 | } 642 | $stack[] = array($mode, $options); 643 | return true; 644 | } 645 | 646 | public static function staticPopErrorHandling() 647 | { 648 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 649 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; 650 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; 651 | array_pop($stack); 652 | list($mode, $options) = $stack[sizeof($stack) - 1]; 653 | array_pop($stack); 654 | switch ($mode) { 655 | case PEAR_ERROR_EXCEPTION: 656 | case PEAR_ERROR_RETURN: 657 | case PEAR_ERROR_PRINT: 658 | case PEAR_ERROR_TRIGGER: 659 | case PEAR_ERROR_DIE: 660 | case null: 661 | $setmode = $mode; 662 | $setoptions = $options; 663 | break; 664 | 665 | case PEAR_ERROR_CALLBACK: 666 | $setmode = $mode; 667 | // class/object method callback 668 | if (is_callable($options)) { 669 | $setoptions = $options; 670 | } else { 671 | trigger_error("invalid error callback", E_USER_WARNING); 672 | } 673 | break; 674 | 675 | default: 676 | trigger_error("invalid error mode", E_USER_WARNING); 677 | break; 678 | } 679 | return true; 680 | } 681 | 682 | /** 683 | * Push a new error handler on top of the error handler options stack. With this 684 | * you can easily override the actual error handler for some code and restore 685 | * it later with popErrorHandling. 686 | * 687 | * @param mixed $mode (same as setErrorHandling) 688 | * @param mixed $options (same as setErrorHandling) 689 | * 690 | * @return bool Always true 691 | * 692 | * @see PEAR::setErrorHandling 693 | */ 694 | protected static function _pushErrorHandling($object, $mode, $options = null) 695 | { 696 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 697 | if ($object !== null) { 698 | $def_mode = &$object->_default_error_mode; 699 | $def_options = &$object->_default_error_options; 700 | } else { 701 | $def_mode = &$GLOBALS['_PEAR_default_error_mode']; 702 | $def_options = &$GLOBALS['_PEAR_default_error_options']; 703 | } 704 | $stack[] = array($def_mode, $def_options); 705 | 706 | if ($object !== null) { 707 | $object->setErrorHandling($mode, $options); 708 | } else { 709 | PEAR::setErrorHandling($mode, $options); 710 | } 711 | $stack[] = array($mode, $options); 712 | return true; 713 | } 714 | 715 | /** 716 | * Pop the last error handler used 717 | * 718 | * @return bool Always true 719 | * 720 | * @see PEAR::pushErrorHandling 721 | */ 722 | protected static function _popErrorHandling($object) 723 | { 724 | $stack = &$GLOBALS['_PEAR_error_handler_stack']; 725 | array_pop($stack); 726 | list($mode, $options) = $stack[sizeof($stack) - 1]; 727 | array_pop($stack); 728 | if ($object !== null) { 729 | $object->setErrorHandling($mode, $options); 730 | } else { 731 | PEAR::setErrorHandling($mode, $options); 732 | } 733 | return true; 734 | } 735 | 736 | /** 737 | * OS independent PHP extension load. Remember to take care 738 | * on the correct extension name for case sensitive OSes. 739 | * 740 | * @param string $ext The extension name 741 | * @return bool Success or not on the dl() call 742 | */ 743 | public static function loadExtension($ext) 744 | { 745 | if (extension_loaded($ext)) { 746 | return true; 747 | } 748 | 749 | // if either returns true dl() will produce a FATAL error, stop that 750 | if ( 751 | function_exists('dl') === false || 752 | ini_get('enable_dl') != 1 753 | ) { 754 | return false; 755 | } 756 | 757 | if (OS_WINDOWS) { 758 | $suffix = '.dll'; 759 | } elseif (PHP_OS == 'HP-UX') { 760 | $suffix = '.sl'; 761 | } elseif (PHP_OS == 'AIX') { 762 | $suffix = '.a'; 763 | } elseif (PHP_OS == 'OSX') { 764 | $suffix = '.bundle'; 765 | } else { 766 | $suffix = '.so'; 767 | } 768 | 769 | return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); 770 | } 771 | 772 | /** 773 | * Get SOURCE_DATE_EPOCH environment variable 774 | * See https://reproducible-builds.org/specs/source-date-epoch/ 775 | * 776 | * @return int 777 | * @access public 778 | */ 779 | static function getSourceDateEpoch() 780 | { 781 | if ($source_date_epoch = getenv('SOURCE_DATE_EPOCH')) { 782 | if (preg_match('/^\d+$/', $source_date_epoch)) { 783 | return (int) $source_date_epoch; 784 | } else { 785 | // "If the value is malformed, the build process SHOULD exit with a non-zero error code." 786 | self::raiseError("Invalid SOURCE_DATE_EPOCH: $source_date_epoch"); 787 | exit(1); 788 | } 789 | } else { 790 | return time(); 791 | } 792 | } 793 | } 794 | 795 | function _PEAR_call_destructors() 796 | { 797 | global $_PEAR_destructor_object_list; 798 | if (is_array($_PEAR_destructor_object_list) && 799 | sizeof($_PEAR_destructor_object_list)) 800 | { 801 | reset($_PEAR_destructor_object_list); 802 | 803 | $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); 804 | 805 | if ($destructLifoExists) { 806 | $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); 807 | } 808 | 809 | foreach ($_PEAR_destructor_object_list as $k => $objref) { 810 | $classname = get_class($objref); 811 | while ($classname) { 812 | $destructor = "_$classname"; 813 | if (method_exists($objref, $destructor)) { 814 | $objref->$destructor(); 815 | break; 816 | } else { 817 | $classname = get_parent_class($classname); 818 | } 819 | } 820 | } 821 | // Empty the object list to ensure that destructors are 822 | // not called more than once. 823 | $_PEAR_destructor_object_list = array(); 824 | } 825 | 826 | // Now call the shutdown functions 827 | if ( 828 | isset($GLOBALS['_PEAR_shutdown_funcs']) && 829 | is_array($GLOBALS['_PEAR_shutdown_funcs']) && 830 | !empty($GLOBALS['_PEAR_shutdown_funcs']) 831 | ) { 832 | foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { 833 | call_user_func_array($value[0], $value[1]); 834 | } 835 | } 836 | } 837 | 838 | /** 839 | * Standard PEAR error class for PHP 4 840 | * 841 | * This class is supserseded by {@link PEAR_Exception} in PHP 5 842 | * 843 | * @category pear 844 | * @package PEAR 845 | * @author Stig Bakken 846 | * @author Tomas V.V. Cox 847 | * @author Gregory Beaver 848 | * @copyright 1997-2006 The PHP Group 849 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 850 | * @version Release: @package_version@ 851 | * @link http://pear.php.net/manual/en/core.pear.pear-error.php 852 | * @see PEAR::raiseError(), PEAR::throwError() 853 | * @since Class available since PHP 4.0.2 854 | */ 855 | class PEAR_Error 856 | { 857 | var $error_message_prefix = ''; 858 | var $mode = PEAR_ERROR_RETURN; 859 | var $level = E_USER_NOTICE; 860 | var $code = -1; 861 | var $message = ''; 862 | var $userinfo = ''; 863 | var $backtrace = null; 864 | var $callback = null; 865 | 866 | /** 867 | * PEAR_Error constructor 868 | * 869 | * @param string $message message 870 | * 871 | * @param int $code (optional) error code 872 | * 873 | * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, 874 | * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, 875 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION 876 | * 877 | * @param mixed $options (optional) error level, _OR_ in the case of 878 | * PEAR_ERROR_CALLBACK, the callback function or object/method 879 | * tuple. 880 | * 881 | * @param string $userinfo (optional) additional user/debug info 882 | * 883 | * @access public 884 | * 885 | */ 886 | function __construct($message = 'unknown error', $code = null, 887 | $mode = null, $options = null, $userinfo = null) 888 | { 889 | if ($mode === null) { 890 | $mode = PEAR_ERROR_RETURN; 891 | } 892 | $this->message = $message; 893 | $this->code = $code; 894 | $this->mode = $mode; 895 | $this->userinfo = $userinfo; 896 | 897 | $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); 898 | 899 | if (!$skiptrace) { 900 | $this->backtrace = debug_backtrace(); 901 | if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { 902 | unset($this->backtrace[0]['object']); 903 | } 904 | } 905 | 906 | if ($mode & PEAR_ERROR_CALLBACK) { 907 | $this->level = E_USER_NOTICE; 908 | $this->callback = $options; 909 | } else { 910 | if ($options === null) { 911 | $options = E_USER_NOTICE; 912 | } 913 | 914 | $this->level = $options; 915 | $this->callback = null; 916 | } 917 | 918 | if ($this->mode & PEAR_ERROR_PRINT) { 919 | if (is_null($options) || is_int($options)) { 920 | $format = "%s"; 921 | } else { 922 | $format = $options; 923 | } 924 | 925 | printf($format, $this->getMessage()); 926 | } 927 | 928 | if ($this->mode & PEAR_ERROR_TRIGGER) { 929 | trigger_error($this->getMessage(), $this->level); 930 | } 931 | 932 | if ($this->mode & PEAR_ERROR_DIE) { 933 | $msg = $this->getMessage(); 934 | if (is_null($options) || is_int($options)) { 935 | $format = "%s"; 936 | if (substr($msg, -1) != "\n") { 937 | $msg .= "\n"; 938 | } 939 | } else { 940 | $format = $options; 941 | } 942 | printf($format, $msg); 943 | exit($code); 944 | } 945 | 946 | if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) { 947 | call_user_func($this->callback, $this); 948 | } 949 | 950 | if ($this->mode & PEAR_ERROR_EXCEPTION) { 951 | trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); 952 | eval('$e = new Exception($this->message, $this->code);throw($e);'); 953 | } 954 | } 955 | 956 | /** 957 | * Only here for backwards compatibility. 958 | * 959 | * Class "Cache_Error" still uses it, among others. 960 | * 961 | * @param string $message Message 962 | * @param int $code Error code 963 | * @param int $mode Error mode 964 | * @param mixed $options See __construct() 965 | * @param string $userinfo Additional user/debug info 966 | */ 967 | public function PEAR_Error( 968 | $message = 'unknown error', $code = null, $mode = null, 969 | $options = null, $userinfo = null 970 | ) { 971 | self::__construct($message, $code, $mode, $options, $userinfo); 972 | } 973 | 974 | /** 975 | * Get the error mode from an error object. 976 | * 977 | * @return int error mode 978 | * @access public 979 | */ 980 | function getMode() 981 | { 982 | return $this->mode; 983 | } 984 | 985 | /** 986 | * Get the callback function/method from an error object. 987 | * 988 | * @return mixed callback function or object/method array 989 | * @access public 990 | */ 991 | function getCallback() 992 | { 993 | return $this->callback; 994 | } 995 | 996 | /** 997 | * Get the error message from an error object. 998 | * 999 | * @return string full error message 1000 | * @access public 1001 | */ 1002 | function getMessage() 1003 | { 1004 | return ($this->error_message_prefix . $this->message); 1005 | } 1006 | 1007 | /** 1008 | * Get error code from an error object 1009 | * 1010 | * @return int error code 1011 | * @access public 1012 | */ 1013 | function getCode() 1014 | { 1015 | return $this->code; 1016 | } 1017 | 1018 | /** 1019 | * Get the name of this error/exception. 1020 | * 1021 | * @return string error/exception name (type) 1022 | * @access public 1023 | */ 1024 | function getType() 1025 | { 1026 | return get_class($this); 1027 | } 1028 | 1029 | /** 1030 | * Get additional user-supplied information. 1031 | * 1032 | * @return string user-supplied information 1033 | * @access public 1034 | */ 1035 | function getUserInfo() 1036 | { 1037 | return $this->userinfo; 1038 | } 1039 | 1040 | /** 1041 | * Get additional debug information supplied by the application. 1042 | * 1043 | * @return string debug information 1044 | * @access public 1045 | */ 1046 | function getDebugInfo() 1047 | { 1048 | return $this->getUserInfo(); 1049 | } 1050 | 1051 | /** 1052 | * Get the call backtrace from where the error was generated. 1053 | * Supported with PHP 4.3.0 or newer. 1054 | * 1055 | * @param int $frame (optional) what frame to fetch 1056 | * @return array Backtrace, or NULL if not available. 1057 | * @access public 1058 | */ 1059 | function getBacktrace($frame = null) 1060 | { 1061 | if (defined('PEAR_IGNORE_BACKTRACE')) { 1062 | return null; 1063 | } 1064 | if ($frame === null) { 1065 | return $this->backtrace; 1066 | } 1067 | return $this->backtrace[$frame]; 1068 | } 1069 | 1070 | function addUserInfo($info) 1071 | { 1072 | if (empty($this->userinfo)) { 1073 | $this->userinfo = $info; 1074 | } else { 1075 | $this->userinfo .= " ** $info"; 1076 | } 1077 | } 1078 | 1079 | function __toString() 1080 | { 1081 | return $this->getMessage(); 1082 | } 1083 | 1084 | /** 1085 | * Make a string representation of this object. 1086 | * 1087 | * @return string a string with an object summary 1088 | * @access public 1089 | */ 1090 | function toString() 1091 | { 1092 | $modes = array(); 1093 | $levels = array(E_USER_NOTICE => 'notice', 1094 | E_USER_WARNING => 'warning', 1095 | E_USER_ERROR => 'error'); 1096 | if ($this->mode & PEAR_ERROR_CALLBACK) { 1097 | if (is_array($this->callback)) { 1098 | $callback = (is_object($this->callback[0]) ? 1099 | strtolower(get_class($this->callback[0])) : 1100 | $this->callback[0]) . '::' . 1101 | $this->callback[1]; 1102 | } else { 1103 | $callback = $this->callback; 1104 | } 1105 | return sprintf('[%s: message="%s" code=%d mode=callback '. 1106 | 'callback=%s prefix="%s" info="%s"]', 1107 | strtolower(get_class($this)), $this->message, $this->code, 1108 | $callback, $this->error_message_prefix, 1109 | $this->userinfo); 1110 | } 1111 | if ($this->mode & PEAR_ERROR_PRINT) { 1112 | $modes[] = 'print'; 1113 | } 1114 | if ($this->mode & PEAR_ERROR_TRIGGER) { 1115 | $modes[] = 'trigger'; 1116 | } 1117 | if ($this->mode & PEAR_ERROR_DIE) { 1118 | $modes[] = 'die'; 1119 | } 1120 | if ($this->mode & PEAR_ERROR_RETURN) { 1121 | $modes[] = 'return'; 1122 | } 1123 | return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. 1124 | 'prefix="%s" info="%s"]', 1125 | strtolower(get_class($this)), $this->message, $this->code, 1126 | implode("|", $modes), $levels[$this->level], 1127 | $this->error_message_prefix, 1128 | $this->userinfo); 1129 | } 1130 | } 1131 | 1132 | /* 1133 | * Local Variables: 1134 | * mode: php 1135 | * tab-width: 4 1136 | * c-basic-offset: 4 1137 | * End: 1138 | */ 1139 | -------------------------------------------------------------------------------- /src/PEAR/ErrorStack.php: -------------------------------------------------------------------------------- 1 | 24 | * @copyright 2004-2008 Greg Beaver 25 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 26 | * @link http://pear.php.net/package/PEAR_ErrorStack 27 | */ 28 | 29 | /** 30 | * Singleton storage 31 | * 32 | * Format: 33 | *
 34 |  * array(
 35 |  *  'package1' => PEAR_ErrorStack object,
 36 |  *  'package2' => PEAR_ErrorStack object,
 37 |  *  ...
 38 |  * )
 39 |  * 
40 | * @access private 41 | * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] 42 | */ 43 | $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); 44 | 45 | /** 46 | * Global error callback (default) 47 | * 48 | * This is only used if set to non-false. * is the default callback for 49 | * all packages, whereas specific packages may set a default callback 50 | * for all instances, regardless of whether they are a singleton or not. 51 | * 52 | * To exclude non-singletons, only set the local callback for the singleton 53 | * @see PEAR_ErrorStack::setDefaultCallback() 54 | * @access private 55 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] 56 | */ 57 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( 58 | '*' => false, 59 | ); 60 | 61 | /** 62 | * Global Log object (default) 63 | * 64 | * This is only used if set to non-false. Use to set a default log object for 65 | * all stacks, regardless of instantiation order or location 66 | * @see PEAR_ErrorStack::setDefaultLogger() 67 | * @access private 68 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] 69 | */ 70 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; 71 | 72 | /** 73 | * Global Overriding Callback 74 | * 75 | * This callback will override any error callbacks that specific loggers have set. 76 | * Use with EXTREME caution 77 | * @see PEAR_ErrorStack::staticPushCallback() 78 | * @access private 79 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] 80 | */ 81 | $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); 82 | 83 | /**#@+ 84 | * One of four possible return values from the error Callback 85 | * @see PEAR_ErrorStack::_errorCallback() 86 | */ 87 | /** 88 | * If this is returned, then the error will be both pushed onto the stack 89 | * and logged. 90 | */ 91 | define('PEAR_ERRORSTACK_PUSHANDLOG', 1); 92 | /** 93 | * If this is returned, then the error will only be pushed onto the stack, 94 | * and not logged. 95 | */ 96 | define('PEAR_ERRORSTACK_PUSH', 2); 97 | /** 98 | * If this is returned, then the error will only be logged, but not pushed 99 | * onto the error stack. 100 | */ 101 | define('PEAR_ERRORSTACK_LOG', 3); 102 | /** 103 | * If this is returned, then the error is completely ignored. 104 | */ 105 | define('PEAR_ERRORSTACK_IGNORE', 4); 106 | /** 107 | * If this is returned, then the error is logged and die() is called. 108 | */ 109 | define('PEAR_ERRORSTACK_DIE', 5); 110 | /**#@-*/ 111 | 112 | /** 113 | * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in 114 | * the singleton method. 115 | */ 116 | define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); 117 | 118 | /** 119 | * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} 120 | * that has no __toString() method 121 | */ 122 | define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); 123 | /** 124 | * Error Stack Implementation 125 | * 126 | * Usage: 127 | * 128 | * // global error stack 129 | * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); 130 | * // local error stack 131 | * $local_stack = new PEAR_ErrorStack('MyPackage'); 132 | * 133 | * @author Greg Beaver 134 | * @version @package_version@ 135 | * @package PEAR_ErrorStack 136 | * @category Debugging 137 | * @copyright 2004-2008 Greg Beaver 138 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 139 | * @link http://pear.php.net/package/PEAR_ErrorStack 140 | */ 141 | class PEAR_ErrorStack { 142 | /** 143 | * Errors are stored in the order that they are pushed on the stack. 144 | * @since 0.4alpha Errors are no longer organized by error level. 145 | * This renders pop() nearly unusable, and levels could be more easily 146 | * handled in a callback anyway 147 | * @var array 148 | * @access private 149 | */ 150 | var $_errors = array(); 151 | 152 | /** 153 | * Storage of errors by level. 154 | * 155 | * Allows easy retrieval and deletion of only errors from a particular level 156 | * @since PEAR 1.4.0dev 157 | * @var array 158 | * @access private 159 | */ 160 | var $_errorsByLevel = array(); 161 | 162 | /** 163 | * Package name this error stack represents 164 | * @var string 165 | * @access protected 166 | */ 167 | var $_package; 168 | 169 | /** 170 | * Determines whether a PEAR_Error is thrown upon every error addition 171 | * @var boolean 172 | * @access private 173 | */ 174 | var $_compat = false; 175 | 176 | /** 177 | * If set to a valid callback, this will be used to generate the error 178 | * message from the error code, otherwise the message passed in will be 179 | * used 180 | * @var false|string|array 181 | * @access private 182 | */ 183 | var $_msgCallback = false; 184 | 185 | /** 186 | * If set to a valid callback, this will be used to generate the error 187 | * context for an error. For PHP-related errors, this will be a file 188 | * and line number as retrieved from debug_backtrace(), but can be 189 | * customized for other purposes. The error might actually be in a separate 190 | * configuration file, or in a database query. 191 | * @var false|string|array 192 | * @access protected 193 | */ 194 | var $_contextCallback = false; 195 | 196 | /** 197 | * If set to a valid callback, this will be called every time an error 198 | * is pushed onto the stack. The return value will be used to determine 199 | * whether to allow an error to be pushed or logged. 200 | * 201 | * The return value must be one an PEAR_ERRORSTACK_* constant 202 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG 203 | * @var false|string|array 204 | * @access protected 205 | */ 206 | var $_errorCallback = array(); 207 | 208 | /** 209 | * PEAR::Log object for logging errors 210 | * @var false|Log 211 | * @access protected 212 | */ 213 | var $_logger = false; 214 | 215 | /** 216 | * Error messages - designed to be overridden 217 | * @var array 218 | * @abstract 219 | */ 220 | var $_errorMsgs = array(); 221 | 222 | /** 223 | * Set up a new error stack 224 | * 225 | * @param string $package name of the package this error stack represents 226 | * @param callback $msgCallback callback used for error message generation 227 | * @param callback $contextCallback callback used for context generation, 228 | * defaults to {@link getFileLine()} 229 | * @param boolean $throwPEAR_Error 230 | */ 231 | function __construct($package, $msgCallback = false, $contextCallback = false, 232 | $throwPEAR_Error = false) 233 | { 234 | $this->_package = $package; 235 | $this->setMessageCallback($msgCallback); 236 | $this->setContextCallback($contextCallback); 237 | $this->_compat = $throwPEAR_Error; 238 | } 239 | 240 | /** 241 | * Return a single error stack for this package. 242 | * 243 | * Note that all parameters are ignored if the stack for package $package 244 | * has already been instantiated 245 | * @param string $package name of the package this error stack represents 246 | * @param callback $msgCallback callback used for error message generation 247 | * @param callback $contextCallback callback used for context generation, 248 | * defaults to {@link getFileLine()} 249 | * @param boolean $throwPEAR_Error 250 | * @param string $stackClass class to instantiate 251 | * 252 | * @return PEAR_ErrorStack 253 | */ 254 | public static function &singleton( 255 | $package, $msgCallback = false, $contextCallback = false, 256 | $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack' 257 | ) { 258 | if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { 259 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; 260 | } 261 | if (!class_exists($stackClass)) { 262 | if (function_exists('debug_backtrace')) { 263 | $trace = debug_backtrace(); 264 | } 265 | PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, 266 | 'exception', array('stackclass' => $stackClass), 267 | 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', 268 | false, $trace); 269 | } 270 | $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = 271 | new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); 272 | 273 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; 274 | } 275 | 276 | /** 277 | * Internal error handler for PEAR_ErrorStack class 278 | * 279 | * Dies if the error is an exception (and would have died anyway) 280 | * @access private 281 | */ 282 | function _handleError($err) 283 | { 284 | if ($err['level'] == 'exception') { 285 | $message = $err['message']; 286 | if (isset($_SERVER['REQUEST_URI'])) { 287 | echo '
'; 288 | } else { 289 | echo "\n"; 290 | } 291 | var_dump($err['context']); 292 | die($message); 293 | } 294 | } 295 | 296 | /** 297 | * Set up a PEAR::Log object for all error stacks that don't have one 298 | * @param Log $log 299 | */ 300 | public static function setDefaultLogger(&$log) 301 | { 302 | if (is_object($log) && method_exists($log, 'log') ) { 303 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; 304 | } elseif (is_callable($log)) { 305 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; 306 | } 307 | } 308 | 309 | /** 310 | * Set up a PEAR::Log object for this error stack 311 | * @param Log $log 312 | */ 313 | function setLogger(&$log) 314 | { 315 | if (is_object($log) && method_exists($log, 'log') ) { 316 | $this->_logger = &$log; 317 | } elseif (is_callable($log)) { 318 | $this->_logger = &$log; 319 | } 320 | } 321 | 322 | /** 323 | * Set an error code => error message mapping callback 324 | * 325 | * This method sets the callback that can be used to generate error 326 | * messages for any instance 327 | * @param array|string Callback function/method 328 | */ 329 | function setMessageCallback($msgCallback) 330 | { 331 | if (!$msgCallback) { 332 | $this->_msgCallback = array(&$this, 'getErrorMessage'); 333 | } else { 334 | if (is_callable($msgCallback)) { 335 | $this->_msgCallback = $msgCallback; 336 | } 337 | } 338 | } 339 | 340 | /** 341 | * Get an error code => error message mapping callback 342 | * 343 | * This method returns the current callback that can be used to generate error 344 | * messages 345 | * @return array|string|false Callback function/method or false if none 346 | */ 347 | function getMessageCallback() 348 | { 349 | return $this->_msgCallback; 350 | } 351 | 352 | /** 353 | * Sets a default callback to be used by all error stacks 354 | * 355 | * This method sets the callback that can be used to generate error 356 | * messages for a singleton 357 | * @param array|string Callback function/method 358 | * @param string Package name, or false for all packages 359 | */ 360 | public static function setDefaultCallback($callback = false, $package = false) 361 | { 362 | if (!is_callable($callback)) { 363 | $callback = false; 364 | } 365 | $package = $package ? $package : '*'; 366 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; 367 | } 368 | 369 | /** 370 | * Set a callback that generates context information (location of error) for an error stack 371 | * 372 | * This method sets the callback that can be used to generate context 373 | * information for an error. Passing in NULL will disable context generation 374 | * and remove the expensive call to debug_backtrace() 375 | * @param array|string|null Callback function/method 376 | */ 377 | function setContextCallback($contextCallback) 378 | { 379 | if ($contextCallback === null) { 380 | return $this->_contextCallback = false; 381 | } 382 | if (!$contextCallback) { 383 | $this->_contextCallback = array(&$this, 'getFileLine'); 384 | } else { 385 | if (is_callable($contextCallback)) { 386 | $this->_contextCallback = $contextCallback; 387 | } 388 | } 389 | } 390 | 391 | /** 392 | * Set an error Callback 393 | * If set to a valid callback, this will be called every time an error 394 | * is pushed onto the stack. The return value will be used to determine 395 | * whether to allow an error to be pushed or logged. 396 | * 397 | * The return value must be one of the ERRORSTACK_* constants. 398 | * 399 | * This functionality can be used to emulate PEAR's pushErrorHandling, and 400 | * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of 401 | * the error stack or logging 402 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG 403 | * @see popCallback() 404 | * @param string|array $cb 405 | */ 406 | function pushCallback($cb) 407 | { 408 | array_push($this->_errorCallback, $cb); 409 | } 410 | 411 | /** 412 | * Remove a callback from the error callback stack 413 | * @see pushCallback() 414 | * @return array|string|false 415 | */ 416 | function popCallback() 417 | { 418 | if (!count($this->_errorCallback)) { 419 | return false; 420 | } 421 | return array_pop($this->_errorCallback); 422 | } 423 | 424 | /** 425 | * Set a temporary overriding error callback for every package error stack 426 | * 427 | * Use this to temporarily disable all existing callbacks (can be used 428 | * to emulate the @ operator, for instance) 429 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG 430 | * @see staticPopCallback(), pushCallback() 431 | * @param string|array $cb 432 | */ 433 | public static function staticPushCallback($cb) 434 | { 435 | array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); 436 | } 437 | 438 | /** 439 | * Remove a temporary overriding error callback 440 | * @see staticPushCallback() 441 | * @return array|string|false 442 | */ 443 | public static function staticPopCallback() 444 | { 445 | $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); 446 | if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { 447 | $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); 448 | } 449 | return $ret; 450 | } 451 | 452 | /** 453 | * Add an error to the stack 454 | * 455 | * If the message generator exists, it is called with 2 parameters. 456 | * - the current Error Stack object 457 | * - an array that is in the same format as an error. Available indices 458 | * are 'code', 'package', 'time', 'params', 'level', and 'context' 459 | * 460 | * Next, if the error should contain context information, this is 461 | * handled by the context grabbing method. 462 | * Finally, the error is pushed onto the proper error stack 463 | * @param int $code Package-specific error code 464 | * @param string $level Error level. This is NOT spell-checked 465 | * @param array $params associative array of error parameters 466 | * @param string $msg Error message, or a portion of it if the message 467 | * is to be generated 468 | * @param array $repackage If this error re-packages an error pushed by 469 | * another package, place the array returned from 470 | * {@link pop()} in this parameter 471 | * @param array $backtrace Protected parameter: use this to pass in the 472 | * {@link debug_backtrace()} that should be used 473 | * to find error context 474 | * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also 475 | * thrown. If a PEAR_Error is returned, the userinfo 476 | * property is set to the following array: 477 | * 478 | * 479 | * array( 480 | * 'code' => $code, 481 | * 'params' => $params, 482 | * 'package' => $this->_package, 483 | * 'level' => $level, 484 | * 'time' => time(), 485 | * 'context' => $context, 486 | * 'message' => $msg, 487 | * //['repackage' => $err] repackaged error array/Exception class 488 | * ); 489 | * 490 | * 491 | * Normally, the previous array is returned. 492 | */ 493 | function push($code, $level = 'error', $params = array(), $msg = false, 494 | $repackage = false, $backtrace = false) 495 | { 496 | $context = false; 497 | // grab error context 498 | if ($this->_contextCallback) { 499 | if (!$backtrace) { 500 | $backtrace = debug_backtrace(); 501 | } 502 | $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); 503 | } 504 | 505 | // save error 506 | $time = explode(' ', microtime()); 507 | $time = $time[1] + $time[0]; 508 | $err = array( 509 | 'code' => $code, 510 | 'params' => $params, 511 | 'package' => $this->_package, 512 | 'level' => $level, 513 | 'time' => $time, 514 | 'context' => $context, 515 | 'message' => $msg, 516 | ); 517 | 518 | if ($repackage) { 519 | $err['repackage'] = $repackage; 520 | } 521 | 522 | // set up the error message, if necessary 523 | if ($this->_msgCallback) { 524 | $msg = call_user_func_array($this->_msgCallback, 525 | array(&$this, $err)); 526 | $err['message'] = $msg; 527 | } 528 | $push = $log = true; 529 | $die = false; 530 | // try the overriding callback first 531 | $callback = $this->staticPopCallback(); 532 | if ($callback) { 533 | $this->staticPushCallback($callback); 534 | } 535 | if (!is_callable($callback)) { 536 | // try the local callback next 537 | $callback = $this->popCallback(); 538 | if (is_callable($callback)) { 539 | $this->pushCallback($callback); 540 | } else { 541 | // try the default callback 542 | $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? 543 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : 544 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; 545 | } 546 | } 547 | if (is_callable($callback)) { 548 | switch(call_user_func($callback, $err)){ 549 | case PEAR_ERRORSTACK_IGNORE: 550 | return $err; 551 | break; 552 | case PEAR_ERRORSTACK_PUSH: 553 | $log = false; 554 | break; 555 | case PEAR_ERRORSTACK_LOG: 556 | $push = false; 557 | break; 558 | case PEAR_ERRORSTACK_DIE: 559 | $die = true; 560 | break; 561 | // anything else returned has the same effect as pushandlog 562 | } 563 | } 564 | if ($push) { 565 | array_unshift($this->_errors, $err); 566 | if (!isset($this->_errorsByLevel[$err['level']])) { 567 | $this->_errorsByLevel[$err['level']] = array(); 568 | } 569 | $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; 570 | } 571 | if ($log) { 572 | if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { 573 | $this->_log($err); 574 | } 575 | } 576 | if ($die) { 577 | die(); 578 | } 579 | if ($this->_compat && $push) { 580 | return $this->raiseError($msg, $code, null, null, $err); 581 | } 582 | return $err; 583 | } 584 | 585 | /** 586 | * Static version of {@link push()} 587 | * 588 | * @param string $package Package name this error belongs to 589 | * @param int $code Package-specific error code 590 | * @param string $level Error level. This is NOT spell-checked 591 | * @param array $params associative array of error parameters 592 | * @param string $msg Error message, or a portion of it if the message 593 | * is to be generated 594 | * @param array $repackage If this error re-packages an error pushed by 595 | * another package, place the array returned from 596 | * {@link pop()} in this parameter 597 | * @param array $backtrace Protected parameter: use this to pass in the 598 | * {@link debug_backtrace()} that should be used 599 | * to find error context 600 | * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also 601 | * thrown. see docs for {@link push()} 602 | */ 603 | public static function staticPush( 604 | $package, $code, $level = 'error', $params = array(), 605 | $msg = false, $repackage = false, $backtrace = false 606 | ) { 607 | $s = &PEAR_ErrorStack::singleton($package); 608 | if ($s->_contextCallback) { 609 | if (!$backtrace) { 610 | if (function_exists('debug_backtrace')) { 611 | $backtrace = debug_backtrace(); 612 | } 613 | } 614 | } 615 | return $s->push($code, $level, $params, $msg, $repackage, $backtrace); 616 | } 617 | 618 | /** 619 | * Log an error using PEAR::Log 620 | * @param array $err Error array 621 | * @param array $levels Error level => Log constant map 622 | * @access protected 623 | */ 624 | function _log($err) 625 | { 626 | if ($this->_logger) { 627 | $logger = &$this->_logger; 628 | } else { 629 | $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; 630 | } 631 | if (is_a($logger, 'Log')) { 632 | $levels = array( 633 | 'exception' => PEAR_LOG_CRIT, 634 | 'alert' => PEAR_LOG_ALERT, 635 | 'critical' => PEAR_LOG_CRIT, 636 | 'error' => PEAR_LOG_ERR, 637 | 'warning' => PEAR_LOG_WARNING, 638 | 'notice' => PEAR_LOG_NOTICE, 639 | 'info' => PEAR_LOG_INFO, 640 | 'debug' => PEAR_LOG_DEBUG); 641 | if (isset($levels[$err['level']])) { 642 | $level = $levels[$err['level']]; 643 | } else { 644 | $level = PEAR_LOG_INFO; 645 | } 646 | $logger->log($err['message'], $level, $err); 647 | } else { // support non-standard logs 648 | call_user_func($logger, $err); 649 | } 650 | } 651 | 652 | 653 | /** 654 | * Pop an error off of the error stack 655 | * 656 | * @return false|array 657 | * @since 0.4alpha it is no longer possible to specify a specific error 658 | * level to return - the last error pushed will be returned, instead 659 | */ 660 | function pop() 661 | { 662 | $err = @array_shift($this->_errors); 663 | if (!is_null($err)) { 664 | @array_pop($this->_errorsByLevel[$err['level']]); 665 | if (!count($this->_errorsByLevel[$err['level']])) { 666 | unset($this->_errorsByLevel[$err['level']]); 667 | } 668 | } 669 | return $err; 670 | } 671 | 672 | /** 673 | * Pop an error off of the error stack, static method 674 | * 675 | * @param string package name 676 | * @return boolean 677 | * @since PEAR1.5.0a1 678 | */ 679 | static function staticPop($package) 680 | { 681 | if ($package) { 682 | if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { 683 | return false; 684 | } 685 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); 686 | } 687 | } 688 | 689 | /** 690 | * Determine whether there are any errors on the stack 691 | * @param string|array Level name. Use to determine if any errors 692 | * of level (string), or levels (array) have been pushed 693 | * @return boolean 694 | */ 695 | function hasErrors($level = false) 696 | { 697 | if ($level) { 698 | return isset($this->_errorsByLevel[$level]); 699 | } 700 | return count($this->_errors); 701 | } 702 | 703 | /** 704 | * Retrieve all errors since last purge 705 | * 706 | * @param boolean set in order to empty the error stack 707 | * @param string level name, to return only errors of a particular severity 708 | * @return array 709 | */ 710 | function getErrors($purge = false, $level = false) 711 | { 712 | if (!$purge) { 713 | if ($level) { 714 | if (!isset($this->_errorsByLevel[$level])) { 715 | return array(); 716 | } else { 717 | return $this->_errorsByLevel[$level]; 718 | } 719 | } else { 720 | return $this->_errors; 721 | } 722 | } 723 | if ($level) { 724 | $ret = $this->_errorsByLevel[$level]; 725 | foreach ($this->_errorsByLevel[$level] as $i => $unused) { 726 | // entries are references to the $_errors array 727 | $this->_errorsByLevel[$level][$i] = false; 728 | } 729 | // array_filter removes all entries === false 730 | $this->_errors = array_filter($this->_errors); 731 | unset($this->_errorsByLevel[$level]); 732 | return $ret; 733 | } 734 | $ret = $this->_errors; 735 | $this->_errors = array(); 736 | $this->_errorsByLevel = array(); 737 | return $ret; 738 | } 739 | 740 | /** 741 | * Determine whether there are any errors on a single error stack, or on any error stack 742 | * 743 | * The optional parameter can be used to test the existence of any errors without the need of 744 | * singleton instantiation 745 | * @param string|false Package name to check for errors 746 | * @param string Level name to check for a particular severity 747 | * @return boolean 748 | */ 749 | public static function staticHasErrors($package = false, $level = false) 750 | { 751 | if ($package) { 752 | if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { 753 | return false; 754 | } 755 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); 756 | } 757 | foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { 758 | if ($obj->hasErrors($level)) { 759 | return true; 760 | } 761 | } 762 | return false; 763 | } 764 | 765 | /** 766 | * Get a list of all errors since last purge, organized by package 767 | * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be 768 | * @param boolean $purge Set to purge the error stack of existing errors 769 | * @param string $level Set to a level name in order to retrieve only errors of a particular level 770 | * @param boolean $merge Set to return a flat array, not organized by package 771 | * @param array $sortfunc Function used to sort a merged array - default 772 | * sorts by time, and should be good for most cases 773 | * 774 | * @return array 775 | */ 776 | public static function staticGetErrors( 777 | $purge = false, $level = false, $merge = false, 778 | $sortfunc = array('PEAR_ErrorStack', '_sortErrors') 779 | ) { 780 | $ret = array(); 781 | if (!is_callable($sortfunc)) { 782 | $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); 783 | } 784 | foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { 785 | $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); 786 | if ($test) { 787 | if ($merge) { 788 | $ret = array_merge($ret, $test); 789 | } else { 790 | $ret[$package] = $test; 791 | } 792 | } 793 | } 794 | if ($merge) { 795 | usort($ret, $sortfunc); 796 | } 797 | return $ret; 798 | } 799 | 800 | /** 801 | * Error sorting function, sorts by time 802 | * @access private 803 | */ 804 | public static function _sortErrors($a, $b) 805 | { 806 | if ($a['time'] == $b['time']) { 807 | return 0; 808 | } 809 | if ($a['time'] < $b['time']) { 810 | return 1; 811 | } 812 | return -1; 813 | } 814 | 815 | /** 816 | * Standard file/line number/function/class context callback 817 | * 818 | * This function uses a backtrace generated from {@link debug_backtrace()} 819 | * and so will not work at all in PHP < 4.3.0. The frame should 820 | * reference the frame that contains the source of the error. 821 | * @return array|false either array('file' => file, 'line' => line, 822 | * 'function' => function name, 'class' => class name) or 823 | * if this doesn't work, then false 824 | * @param unused 825 | * @param integer backtrace frame. 826 | * @param array Results of debug_backtrace() 827 | */ 828 | public static function getFileLine($code, $params, $backtrace = null) 829 | { 830 | if ($backtrace === null) { 831 | return false; 832 | } 833 | $frame = 0; 834 | $functionframe = 1; 835 | if (!isset($backtrace[1])) { 836 | $functionframe = 0; 837 | } else { 838 | while (isset($backtrace[$functionframe]['function']) && 839 | $backtrace[$functionframe]['function'] == 'eval' && 840 | isset($backtrace[$functionframe + 1])) { 841 | $functionframe++; 842 | } 843 | } 844 | if (isset($backtrace[$frame])) { 845 | if (!isset($backtrace[$frame]['file'])) { 846 | $frame++; 847 | } 848 | $funcbacktrace = $backtrace[$functionframe]; 849 | $filebacktrace = $backtrace[$frame]; 850 | $ret = array('file' => $filebacktrace['file'], 851 | 'line' => $filebacktrace['line']); 852 | // rearrange for eval'd code or create function errors 853 | if (strpos($filebacktrace['file'], '(') && 854 | preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], 855 | $matches)) { 856 | $ret['file'] = $matches[1]; 857 | $ret['line'] = $matches[2] + 0; 858 | } 859 | if (isset($funcbacktrace['function']) && isset($backtrace[1])) { 860 | if ($funcbacktrace['function'] != 'eval') { 861 | if ($funcbacktrace['function'] == '__lambda_func') { 862 | $ret['function'] = 'create_function() code'; 863 | } else { 864 | $ret['function'] = $funcbacktrace['function']; 865 | } 866 | } 867 | } 868 | if (isset($funcbacktrace['class']) && isset($backtrace[1])) { 869 | $ret['class'] = $funcbacktrace['class']; 870 | } 871 | return $ret; 872 | } 873 | return false; 874 | } 875 | 876 | /** 877 | * Standard error message generation callback 878 | * 879 | * This method may also be called by a custom error message generator 880 | * to fill in template values from the params array, simply 881 | * set the third parameter to the error message template string to use 882 | * 883 | * The special variable %__msg% is reserved: use it only to specify 884 | * where a message passed in by the user should be placed in the template, 885 | * like so: 886 | * 887 | * Error message: %msg% - internal error 888 | * 889 | * If the message passed like so: 890 | * 891 | * 892 | * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); 893 | * 894 | * 895 | * The returned error message will be "Error message: server error 500 - 896 | * internal error" 897 | * @param PEAR_ErrorStack 898 | * @param array 899 | * @param string|false Pre-generated error message template 900 | * 901 | * @return string 902 | */ 903 | public static function getErrorMessage(&$stack, $err, $template = false) 904 | { 905 | if ($template) { 906 | $mainmsg = $template; 907 | } else { 908 | $mainmsg = $stack->getErrorMessageTemplate($err['code']); 909 | } 910 | $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); 911 | if (is_array($err['params']) && count($err['params'])) { 912 | foreach ($err['params'] as $name => $val) { 913 | if (is_array($val)) { 914 | // @ is needed in case $val is a multi-dimensional array 915 | $val = @implode(', ', $val); 916 | } 917 | if (is_object($val)) { 918 | if (method_exists($val, '__toString')) { 919 | $val = $val->__toString(); 920 | } else { 921 | PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, 922 | 'warning', array('obj' => get_class($val)), 923 | 'object %obj% passed into getErrorMessage, but has no __toString() method'); 924 | $val = 'Object'; 925 | } 926 | } 927 | $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); 928 | } 929 | } 930 | return $mainmsg; 931 | } 932 | 933 | /** 934 | * Standard Error Message Template generator from code 935 | * @return string 936 | */ 937 | function getErrorMessageTemplate($code) 938 | { 939 | if (!isset($this->_errorMsgs[$code])) { 940 | return '%__msg%'; 941 | } 942 | return $this->_errorMsgs[$code]; 943 | } 944 | 945 | /** 946 | * Set the Error Message Template array 947 | * 948 | * The array format must be: 949 | *
950 |      * array(error code => 'message template',...)
951 |      * 
952 | * 953 | * Error message parameters passed into {@link push()} will be used as input 954 | * for the error message. If the template is 'message %foo% was %bar%', and the 955 | * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will 956 | * be 'message one was six' 957 | * @return string 958 | */ 959 | function setErrorMessageTemplate($template) 960 | { 961 | $this->_errorMsgs = $template; 962 | } 963 | 964 | 965 | /** 966 | * emulate PEAR::raiseError() 967 | * 968 | * @return PEAR_Error 969 | */ 970 | function raiseError() 971 | { 972 | require_once 'PEAR.php'; 973 | $args = func_get_args(); 974 | return call_user_func_array(array('PEAR', 'raiseError'), $args); 975 | } 976 | } 977 | $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); 978 | $stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); 979 | ?> 980 | -------------------------------------------------------------------------------- /src/System.php: -------------------------------------------------------------------------------- 1 | 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 0.1 14 | */ 15 | 16 | /** 17 | * base class 18 | */ 19 | require_once 'PEAR.php'; 20 | require_once 'Console/Getopt.php'; 21 | 22 | $GLOBALS['_System_temp_files'] = array(); 23 | 24 | /** 25 | * System offers cross platform compatible system functions 26 | * 27 | * Static functions for different operations. Should work under 28 | * Unix and Windows. The names and usage has been taken from its respectively 29 | * GNU commands. The functions will return (bool) false on error and will 30 | * trigger the error with the PHP trigger_error() function (you can silence 31 | * the error by prefixing a '@' sign after the function call, but this 32 | * is not recommended practice. Instead use an error handler with 33 | * {@link set_error_handler()}). 34 | * 35 | * Documentation on this class you can find in: 36 | * http://pear.php.net/manual/ 37 | * 38 | * Example usage: 39 | * if (!@System::rm('-r file1 dir1')) { 40 | * print "could not delete file1 or dir1"; 41 | * } 42 | * 43 | * In case you need to to pass file names with spaces, 44 | * pass the params as an array: 45 | * 46 | * System::rm(array('-r', $file1, $dir1)); 47 | * 48 | * @category pear 49 | * @package System 50 | * @author Tomas V.V. Cox 51 | * @copyright 1997-2006 The PHP Group 52 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 53 | * @version Release: @package_version@ 54 | * @link http://pear.php.net/package/PEAR 55 | * @since Class available since Release 0.1 56 | * @static 57 | */ 58 | class System 59 | { 60 | /** 61 | * returns the commandline arguments of a function 62 | * 63 | * @param string $argv the commandline 64 | * @param string $short_options the allowed option short-tags 65 | * @param string $long_options the allowed option long-tags 66 | * @return array the given options and there values 67 | */ 68 | public static function _parseArgs($argv, $short_options, $long_options = null) 69 | { 70 | if (!is_array($argv) && $argv !== null) { 71 | /* 72 | // Quote all items that are a short option 73 | $av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((? $a) { 92 | if (empty($a)) { 93 | continue; 94 | } 95 | $argv[$k] = trim($a) ; 96 | } 97 | } 98 | 99 | return Console_Getopt::getopt2($argv, $short_options, $long_options); 100 | } 101 | 102 | /** 103 | * Output errors with PHP trigger_error(). You can silence the errors 104 | * with prefixing a "@" sign to the function call: @System::mkdir(..); 105 | * 106 | * @param mixed $error a PEAR error or a string with the error message 107 | * @return bool false 108 | */ 109 | protected static function raiseError($error) 110 | { 111 | if (PEAR::isError($error)) { 112 | $error = $error->getMessage(); 113 | } 114 | trigger_error($error, E_USER_WARNING); 115 | return false; 116 | } 117 | 118 | /** 119 | * Creates a nested array representing the structure of a directory 120 | * 121 | * System::_dirToStruct('dir1', 0) => 122 | * Array 123 | * ( 124 | * [dirs] => Array 125 | * ( 126 | * [0] => dir1 127 | * ) 128 | * 129 | * [files] => Array 130 | * ( 131 | * [0] => dir1/file2 132 | * [1] => dir1/file3 133 | * ) 134 | * ) 135 | * @param string $sPath Name of the directory 136 | * @param integer $maxinst max. deep of the lookup 137 | * @param integer $aktinst starting deep of the lookup 138 | * @param bool $silent if true, do not emit errors. 139 | * @return array the structure of the dir 140 | */ 141 | protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) 142 | { 143 | $struct = array('dirs' => array(), 'files' => array()); 144 | if (($dir = @opendir($sPath)) === false) { 145 | if (!$silent) { 146 | System::raiseError("Could not open dir $sPath"); 147 | } 148 | return $struct; // XXX could not open error 149 | } 150 | 151 | $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? 152 | $list = array(); 153 | while (false !== ($file = readdir($dir))) { 154 | if ($file != '.' && $file != '..') { 155 | $list[] = $file; 156 | } 157 | } 158 | 159 | closedir($dir); 160 | natsort($list); 161 | if ($aktinst < $maxinst || $maxinst == 0) { 162 | foreach ($list as $val) { 163 | $path = $sPath . DIRECTORY_SEPARATOR . $val; 164 | if (is_dir($path) && !is_link($path)) { 165 | $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); 166 | $struct = array_merge_recursive($struct, $tmp); 167 | } else { 168 | $struct['files'][] = $path; 169 | } 170 | } 171 | } 172 | 173 | return $struct; 174 | } 175 | 176 | /** 177 | * Creates a nested array representing the structure of a directory and files 178 | * 179 | * @param array $files Array listing files and dirs 180 | * @return array 181 | * @static 182 | * @see System::_dirToStruct() 183 | */ 184 | protected static function _multipleToStruct($files) 185 | { 186 | $struct = array('dirs' => array(), 'files' => array()); 187 | settype($files, 'array'); 188 | foreach ($files as $file) { 189 | if (is_dir($file) && !is_link($file)) { 190 | $tmp = System::_dirToStruct($file, 0); 191 | $struct = array_merge_recursive($tmp, $struct); 192 | } else { 193 | if (!in_array($file, $struct['files'])) { 194 | $struct['files'][] = $file; 195 | } 196 | } 197 | } 198 | return $struct; 199 | } 200 | 201 | /** 202 | * The rm command for removing files. 203 | * Supports multiple files and dirs and also recursive deletes 204 | * 205 | * @param string $args the arguments for rm 206 | * @return mixed PEAR_Error or true for success 207 | * @static 208 | * @access public 209 | */ 210 | public static function rm($args) 211 | { 212 | $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) 213 | if (PEAR::isError($opts)) { 214 | return System::raiseError($opts); 215 | } 216 | foreach ($opts[0] as $opt) { 217 | if ($opt[0] == 'r') { 218 | $do_recursive = true; 219 | } 220 | } 221 | $ret = true; 222 | if (isset($do_recursive)) { 223 | $struct = System::_multipleToStruct($opts[1]); 224 | foreach ($struct['files'] as $file) { 225 | if (!@unlink($file)) { 226 | $ret = false; 227 | } 228 | } 229 | 230 | rsort($struct['dirs']); 231 | foreach ($struct['dirs'] as $dir) { 232 | if (!@rmdir($dir)) { 233 | $ret = false; 234 | } 235 | } 236 | } else { 237 | foreach ($opts[1] as $file) { 238 | $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; 239 | if (!@$delete($file)) { 240 | $ret = false; 241 | } 242 | } 243 | } 244 | return $ret; 245 | } 246 | 247 | /** 248 | * Make directories. 249 | * 250 | * The -p option will create parent directories 251 | * @param string $args the name of the director(y|ies) to create 252 | * @return bool True for success 253 | */ 254 | public static function mkDir($args) 255 | { 256 | $opts = System::_parseArgs($args, 'pm:'); 257 | if (PEAR::isError($opts)) { 258 | return System::raiseError($opts); 259 | } 260 | 261 | $mode = 0777; // default mode 262 | foreach ($opts[0] as $opt) { 263 | if ($opt[0] == 'p') { 264 | $create_parents = true; 265 | } elseif ($opt[0] == 'm') { 266 | // if the mode is clearly an octal number (starts with 0) 267 | // convert it to decimal 268 | if (strlen($opt[1]) && $opt[1][0] == '0') { 269 | $opt[1] = octdec($opt[1]); 270 | } else { 271 | // convert to int 272 | $opt[1] += 0; 273 | } 274 | $mode = $opt[1]; 275 | } 276 | } 277 | 278 | $ret = true; 279 | if (isset($create_parents)) { 280 | foreach ($opts[1] as $dir) { 281 | $dirstack = array(); 282 | while ((!file_exists($dir) || !is_dir($dir)) && 283 | $dir != DIRECTORY_SEPARATOR) { 284 | array_unshift($dirstack, $dir); 285 | $dir = dirname($dir); 286 | } 287 | 288 | while ($newdir = array_shift($dirstack)) { 289 | if (!is_writeable(dirname($newdir))) { 290 | $ret = false; 291 | break; 292 | } 293 | 294 | if (!mkdir($newdir, $mode)) { 295 | $ret = false; 296 | } 297 | } 298 | } 299 | } else { 300 | foreach($opts[1] as $dir) { 301 | if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { 302 | $ret = false; 303 | } 304 | } 305 | } 306 | 307 | return $ret; 308 | } 309 | 310 | /** 311 | * Concatenate files 312 | * 313 | * Usage: 314 | * 1) $var = System::cat('sample.txt test.txt'); 315 | * 2) System::cat('sample.txt test.txt > final.txt'); 316 | * 3) System::cat('sample.txt test.txt >> final.txt'); 317 | * 318 | * Note: as the class use fopen, urls should work also 319 | * 320 | * @param string $args the arguments 321 | * @return boolean true on success 322 | */ 323 | public static function &cat($args) 324 | { 325 | $ret = null; 326 | $files = array(); 327 | if (!is_array($args)) { 328 | $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); 329 | } 330 | 331 | $count_args = count($args); 332 | for ($i = 0; $i < $count_args; $i++) { 333 | if ($args[$i] == '>') { 334 | $mode = 'wb'; 335 | $outputfile = $args[$i+1]; 336 | break; 337 | } elseif ($args[$i] == '>>') { 338 | $mode = 'ab+'; 339 | $outputfile = $args[$i+1]; 340 | break; 341 | } else { 342 | $files[] = $args[$i]; 343 | } 344 | } 345 | $outputfd = false; 346 | if (isset($mode)) { 347 | if (!$outputfd = fopen($outputfile, $mode)) { 348 | $err = System::raiseError("Could not open $outputfile"); 349 | return $err; 350 | } 351 | $ret = true; 352 | } 353 | foreach ($files as $file) { 354 | if (!$fd = fopen($file, 'r')) { 355 | System::raiseError("Could not open $file"); 356 | continue; 357 | } 358 | while ($cont = fread($fd, 2048)) { 359 | if (is_resource($outputfd)) { 360 | fwrite($outputfd, $cont); 361 | } else { 362 | $ret .= $cont; 363 | } 364 | } 365 | fclose($fd); 366 | } 367 | if (is_resource($outputfd)) { 368 | fclose($outputfd); 369 | } 370 | return $ret; 371 | } 372 | 373 | /** 374 | * Creates temporary files or directories. This function will remove 375 | * the created files when the scripts finish its execution. 376 | * 377 | * Usage: 378 | * 1) $tempfile = System::mktemp("prefix"); 379 | * 2) $tempdir = System::mktemp("-d prefix"); 380 | * 3) $tempfile = System::mktemp(); 381 | * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); 382 | * 383 | * prefix -> The string that will be prepended to the temp name 384 | * (defaults to "tmp"). 385 | * -d -> A temporary dir will be created instead of a file. 386 | * -t -> The target dir where the temporary (file|dir) will be created. If 387 | * this param is missing by default the env vars TMP on Windows or 388 | * TMPDIR in Unix will be used. If these vars are also missing 389 | * c:\windows\temp or /tmp will be used. 390 | * 391 | * @param string $args The arguments 392 | * @return mixed the full path of the created (file|dir) or false 393 | * @see System::tmpdir() 394 | */ 395 | public static function mktemp($args = null) 396 | { 397 | static $first_time = true; 398 | $opts = System::_parseArgs($args, 't:d'); 399 | if (PEAR::isError($opts)) { 400 | return System::raiseError($opts); 401 | } 402 | 403 | foreach ($opts[0] as $opt) { 404 | if ($opt[0] == 'd') { 405 | $tmp_is_dir = true; 406 | } elseif ($opt[0] == 't') { 407 | $tmpdir = $opt[1]; 408 | } 409 | } 410 | 411 | $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; 412 | if (!isset($tmpdir)) { 413 | $tmpdir = System::tmpdir(); 414 | } 415 | 416 | if (!System::mkDir(array('-p', $tmpdir))) { 417 | return false; 418 | } 419 | 420 | $tmp = tempnam($tmpdir, $prefix); 421 | if (isset($tmp_is_dir)) { 422 | unlink($tmp); // be careful possible race condition here 423 | if (!mkdir($tmp, 0700)) { 424 | return System::raiseError("Unable to create temporary directory $tmpdir"); 425 | } 426 | } 427 | 428 | $GLOBALS['_System_temp_files'][] = $tmp; 429 | if (isset($tmp_is_dir)) { 430 | //$GLOBALS['_System_temp_files'][] = dirname($tmp); 431 | } 432 | 433 | if ($first_time) { 434 | PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); 435 | $first_time = false; 436 | } 437 | 438 | return $tmp; 439 | } 440 | 441 | /** 442 | * Remove temporary files created my mkTemp. This function is executed 443 | * at script shutdown time 444 | */ 445 | public static function _removeTmpFiles() 446 | { 447 | if (count($GLOBALS['_System_temp_files'])) { 448 | $delete = $GLOBALS['_System_temp_files']; 449 | array_unshift($delete, '-r'); 450 | System::rm($delete); 451 | $GLOBALS['_System_temp_files'] = array(); 452 | } 453 | } 454 | 455 | /** 456 | * Get the path of the temporal directory set in the system 457 | * by looking in its environments variables. 458 | * Note: php.ini-recommended removes the "E" from the variables_order setting, 459 | * making unavaible the $_ENV array, that s why we do tests with _ENV 460 | * 461 | * @return string The temporary directory on the system 462 | */ 463 | public static function tmpdir() 464 | { 465 | if (OS_WINDOWS) { 466 | if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { 467 | return $var; 468 | } 469 | if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { 470 | return $var; 471 | } 472 | if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { 473 | return $var; 474 | } 475 | if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { 476 | return $var; 477 | } 478 | return getenv('SystemRoot') . '\temp'; 479 | } 480 | if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { 481 | return $var; 482 | } 483 | return realpath(function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '/tmp'); 484 | } 485 | 486 | /** 487 | * The "which" command (show the full path of a command) 488 | * 489 | * @param string $program The command to search for 490 | * @param mixed $fallback Value to return if $program is not found 491 | * 492 | * @return mixed A string with the full path or false if not found 493 | * @author Stig Bakken 494 | */ 495 | public static function which($program, $fallback = false) 496 | { 497 | // enforce API 498 | if (!is_string($program) || '' == $program) { 499 | return $fallback; 500 | } 501 | 502 | // full path given 503 | if (basename($program) != $program) { 504 | $path_elements[] = dirname($program); 505 | $program = basename($program); 506 | } else { 507 | $path = getenv('PATH'); 508 | if (!$path) { 509 | $path = getenv('Path'); // some OSes are just stupid enough to do this 510 | } 511 | 512 | $path_elements = explode(PATH_SEPARATOR, $path); 513 | } 514 | 515 | if (OS_WINDOWS) { 516 | $exe_suffixes = getenv('PATHEXT') 517 | ? explode(PATH_SEPARATOR, getenv('PATHEXT')) 518 | : array('.exe','.bat','.cmd','.com'); 519 | // allow passing a command.exe param 520 | if (strpos($program, '.') !== false) { 521 | array_unshift($exe_suffixes, ''); 522 | } 523 | } else { 524 | $exe_suffixes = array(''); 525 | } 526 | 527 | foreach ($exe_suffixes as $suff) { 528 | foreach ($path_elements as $dir) { 529 | $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; 530 | // It's possible to run a .bat on Windows that is_executable 531 | // would return false for. The is_executable check is meaningless... 532 | if (OS_WINDOWS) { 533 | if (file_exists($file)) { 534 | return $file; 535 | } 536 | } else { 537 | if (is_executable($file)) { 538 | return $file; 539 | } 540 | } 541 | } 542 | } 543 | return $fallback; 544 | } 545 | 546 | /** 547 | * The "find" command 548 | * 549 | * Usage: 550 | * 551 | * System::find($dir); 552 | * System::find("$dir -type d"); 553 | * System::find("$dir -type f"); 554 | * System::find("$dir -name *.php"); 555 | * System::find("$dir -name *.php -name *.htm*"); 556 | * System::find("$dir -maxdepth 1"); 557 | * 558 | * Params implemented: 559 | * $dir -> Start the search at this directory 560 | * -type d -> return only directories 561 | * -type f -> return only files 562 | * -maxdepth -> max depth of recursion 563 | * -name -> search pattern (bash style). Multiple -name param allowed 564 | * 565 | * @param mixed Either array or string with the command line 566 | * @return array Array of found files 567 | */ 568 | public static function find($args) 569 | { 570 | if (!is_array($args)) { 571 | $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); 572 | } 573 | $dir = realpath(array_shift($args)); 574 | if (!$dir) { 575 | return array(); 576 | } 577 | $patterns = array(); 578 | $depth = 0; 579 | $do_files = $do_dirs = true; 580 | $args_count = count($args); 581 | for ($i = 0; $i < $args_count; $i++) { 582 | switch ($args[$i]) { 583 | case '-type': 584 | if (in_array($args[$i+1], array('d', 'f'))) { 585 | if ($args[$i+1] == 'd') { 586 | $do_files = false; 587 | } else { 588 | $do_dirs = false; 589 | } 590 | } 591 | $i++; 592 | break; 593 | case '-name': 594 | $name = preg_quote($args[$i+1], '#'); 595 | // our magic characters ? and * have just been escaped, 596 | // so now we change the escaped versions to PCRE operators 597 | $name = strtr($name, array('\?' => '.', '\*' => '.*')); 598 | $patterns[] = '('.$name.')'; 599 | $i++; 600 | break; 601 | case '-maxdepth': 602 | $depth = $args[$i+1]; 603 | break; 604 | } 605 | } 606 | $path = System::_dirToStruct($dir, $depth, 0, true); 607 | if ($do_files && $do_dirs) { 608 | $files = array_merge($path['files'], $path['dirs']); 609 | } elseif ($do_dirs) { 610 | $files = $path['dirs']; 611 | } else { 612 | $files = $path['files']; 613 | } 614 | if (count($patterns)) { 615 | $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); 616 | $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; 617 | $ret = array(); 618 | $files_count = count($files); 619 | for ($i = 0; $i < $files_count; $i++) { 620 | // only search in the part of the file below the current directory 621 | $filepart = basename($files[$i]); 622 | if (preg_match($pattern, $filepart)) { 623 | $ret[] = $files[$i]; 624 | } 625 | } 626 | return $ret; 627 | } 628 | return $files; 629 | } 630 | } 631 | --------------------------------------------------------------------------------