1 : <?php
2 : /**
3 : * PradoBase class file.
4 : *
5 : * This is the file that establishes the PRADO component model
6 : * and error handling mechanism.
7 : *
8 : * @author Qiang Xue <qiang.xue@gmail.com>
9 : * @link http://www.pradosoft.com/
10 : * @copyright Copyright © 2005 PradoSoft
11 : * @license http://www.pradosoft.com/license/
12 : * @version $Id: PradoBase.php 2283 2007-10-01 00:33:28Z xue $
13 : * @package System
14 : */
15 :
16 : /**
17 : * Defines the PRADO framework installation path.
18 : */
19 : if(!defined('PRADO_DIR'))
20 : define('PRADO_DIR',dirname(__FILE__));
21 : /**
22 : * Defines the default permission for writable directories and files
23 : */
24 : if(!defined('PRADO_CHMOD'))
25 : define('PRADO_CHMOD',0777);
26 :
27 : /**
28 : * PradoBase class.
29 : *
30 : * PradoBase implements a few fundamental static methods.
31 : *
32 : * To use the static methods, Use Prado as the class name rather than PradoBase.
33 : * PradoBase is meant to serve as the base class of Prado. The latter might be
34 : * rewritten for customization.
35 : *
36 : * @author Qiang Xue <qiang.xue@gmail.com>
37 : * @version $Id: PradoBase.php 2283 2007-10-01 00:33:28Z xue $
38 : * @package System
39 : * @since 3.0
40 : */
41 : class PradoBase
42 : {
43 : /**
44 : * File extension for Prado class files.
45 : */
46 : const CLASS_FILE_EXT='.php';
47 : /**
48 : * @var array list of path aliases
49 : */
50 : private static $_aliases=array('System'=>PRADO_DIR);
51 : /**
52 : * @var array list of namespaces currently in use
53 : */
54 : private static $_usings=array();
55 : /**
56 : * @var TApplication the application instance
57 : */
58 : private static $_application=null;
59 : /**
60 : * @var TLogger logger instance
61 : */
62 : private static $_logger=null;
63 :
64 : /**
65 : * @return string the version of Prado framework
66 : */
67 : public static function getVersion()
68 : {
69 3 : return '3.1.2a';
70 : }
71 :
72 : /**
73 : * Initializes error handlers.
74 : * This method set error and exception handlers to be functions
75 : * defined in this class.
76 : */
77 : public static function initErrorHandlers()
78 : {
79 : /**
80 : * Sets error handler to be Prado::phpErrorHandler
81 : */
82 0 : set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
83 : /**
84 : * Sets exception handler to be Prado::exceptionHandler
85 : */
86 0 : set_exception_handler(array('PradoBase','exceptionHandler'));
87 0 : }
88 :
89 : /**
90 : * Class autoload loader.
91 : * This method is provided to be invoked within an __autoload() magic method.
92 : * @param string class name
93 : */
94 : public static function autoload($className)
95 : {
96 0 : include_once($className.self::CLASS_FILE_EXT);
97 0 : if(!class_exists($className,false) && !interface_exists($className,false))
98 0 : self::fatalError("Class file for '$className' cannot be found.");
99 0 : }
100 :
101 : /**
102 : * @param integer the type of "powered logo". Valid values include 0 and 1.
103 : * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
104 : */
105 : public static function poweredByPrado($logoType=0)
106 : {
107 0 : $logoName=$logoType==1?'powered2':'powered';
108 0 : if(self::$_application!==null)
109 0 : {
110 0 : $am=self::$_application->getAssetManager();
111 0 : $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
112 0 : }
113 : else
114 0 : $url='http://www.pradosoft.com/images/'.$logoName.'.gif';
115 0 : return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
116 : }
117 :
118 : /**
119 : * PHP error handler.
120 : * This method should be registered as PHP error handler using
121 : * {@link set_error_handler}. The method throws an exception that
122 : * contains the error information.
123 : * @param integer the level of the error raised
124 : * @param string the error message
125 : * @param string the filename that the error was raised in
126 : * @param integer the line number the error was raised at
127 : */
128 : public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
129 : {
130 55 : if(error_reporting()!=0)
131 55 : throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
132 55 : }
133 :
134 : /**
135 : * Default exception handler.
136 : * This method should be registered as default exception handler using
137 : * {@link set_exception_handler}. The method tries to use the errorhandler
138 : * module of the Prado application to handle the exception.
139 : * If the application or the module does not exist, it simply echoes the
140 : * exception.
141 : * @param Exception exception that is not caught
142 : */
143 : public static function exceptionHandler($exception)
144 : {
145 0 : if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
146 0 : {
147 0 : $errorHandler->handleError(null,$exception);
148 0 : }
149 : else
150 : {
151 0 : echo $exception;
152 : }
153 0 : exit(1);
154 : }
155 :
156 : /**
157 : * Stores the application instance in the class static member.
158 : * This method helps implement a singleton pattern for TApplication.
159 : * Repeated invocation of this method or the application constructor
160 : * will cause the throw of an exception.
161 : * This method should only be used by framework developers.
162 : * @param TApplication the application instance
163 : * @throws TInvalidOperationException if this method is invoked twice or more.
164 : */
165 : public static function setApplication($application)
166 : {
167 0 : if(self::$_application!==null)
168 0 : throw new TInvalidOperationException('prado_application_singleton_required');
169 0 : self::$_application=$application;
170 0 : }
171 :
172 : /**
173 : * @return TApplication the application singleton, null if the singleton has not be created yet.
174 : */
175 : public static function getApplication()
176 : {
177 0 : return self::$_application;
178 : }
179 :
180 : /**
181 : * @return string the path of the framework
182 : */
183 : public static function getFrameworkPath()
184 : {
185 51 : return PRADO_DIR;
186 : }
187 :
188 : /**
189 : * Serializes a data.
190 : * The original PHP serialize function has a bug that may not serialize
191 : * properly an object.
192 : * @param mixed data to be serialized
193 : * @return string the serialized data
194 : */
195 : public static function serialize($data)
196 : {
197 0 : $arr[0]=$data;
198 0 : return serialize($arr);
199 : }
200 :
201 : /**
202 : * Unserializes a data.
203 : * The original PHP unserialize function has a bug that may not unserialize
204 : * properly an object.
205 : * @param string data to be unserialized
206 : * @return mixed unserialized data, null if unserialize failed
207 : */
208 : public static function unserialize($str)
209 : {
210 0 : $arr=unserialize($str);
211 0 : return isset($arr[0])?$arr[0]:null;
212 : }
213 :
214 : /**
215 : * Creates a component with the specified type.
216 : * A component type can be either the component class name
217 : * or a namespace referring to the path of the component class file.
218 : * For example, 'TButton', 'System.Web.UI.WebControls.TButton' are both
219 : * valid component type.
220 : * This method can also pass parameters to component constructors.
221 : * All parameters passed to this method except the first one (the component type)
222 : * will be supplied as component constructor parameters.
223 : * @param string component type
224 : * @return TComponent component instance of the specified type
225 : * @throws TInvalidDataValueException if the component type is unknown
226 : */
227 : public static function createComponent($type)
228 : {
229 3 : self::using($type);
230 3 : if(($pos=strrpos($type,'.'))!==false)
231 3 : $type=substr($type,$pos+1);
232 3 : if(($n=func_num_args())>1)
233 3 : {
234 1 : $args=func_get_args();
235 1 : $s='$args[1]';
236 1 : for($i=2;$i<$n;++$i)
237 0 : $s.=",\$args[$i]";
238 1 : eval("\$component=new $type($s);");
239 1 : return $component;
240 : }
241 : else
242 2 : return new $type;
243 : }
244 :
245 : /**
246 : * Uses a namespace.
247 : * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
248 : * If the namespace corresponds to a directory, the directory will be appended
249 : * to the include path. If the namespace corresponds to a file, it will be included (include_once).
250 : * @param string namespace to be used
251 : * @param boolean whether to check the existence of the class after the class file is included
252 : * @throws TInvalidDataValueException if the namespace is invalid
253 : */
254 : public static function using($namespace,$checkClassExistence=true)
255 : {
256 3 : if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
257 3 : return;
258 1 : if(($pos=strrpos($namespace,'.'))===false) // a class name
259 1 : {
260 : try
261 : {
262 0 : include_once($namespace.self::CLASS_FILE_EXT);
263 : }
264 0 : catch(Exception $e)
265 : {
266 : if($checkClassExistence && !class_exists($namespace,false))
267 : throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
268 : else
269 : throw $e;
270 : }
271 0 : }
272 1 : else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
273 1 : {
274 1 : $className=substr($namespace,$pos+1);
275 1 : if($className==='*') // a directory
276 1 : {
277 0 : self::$_usings[$namespace]=$path;
278 0 : set_include_path(get_include_path().PATH_SEPARATOR.$path);
279 0 : }
280 : else // a file
281 : {
282 1 : self::$_usings[$namespace]=$path;
283 1 : if(!$checkClassExistence || !class_exists($className,false))
284 1 : {
285 : try
286 : {
287 0 : include_once($path);
288 : }
289 0 : catch(Exception $e)
290 : {
291 : if($checkClassExistence && !class_exists($className,false))
292 : throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
293 : else
294 : throw $e;
295 : }
296 0 : }
297 : }
298 1 : }
299 : else
300 0 : throw new TInvalidDataValueException('prado_using_invalid',$namespace);
301 1 : }
302 :
303 : /**
304 : * Translates a namespace into a file path.
305 : * The first segment of the namespace is considered as a path alias
306 : * which is replaced with the actual path. The rest segments are
307 : * subdirectory names appended to the aliased path.
308 : * If the namespace ends with an asterisk '*', it represents a directory;
309 : * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
310 : * Note, this method does not ensure the existence of the resulting file path.
311 : * @param string namespace
312 : * @param string extension to be appended if the namespace refers to a file
313 : * @return string file path corresponding to the namespace, null if namespace is invalid
314 : */
315 : public static function getPathOfNamespace($namespace,$ext='')
316 : {
317 1 : if(isset(self::$_usings[$namespace]))
318 1 : return self::$_usings[$namespace];
319 1 : else if(isset(self::$_aliases[$namespace]))
320 1 : return self::$_aliases[$namespace];
321 : else
322 : {
323 1 : $segs=explode('.',$namespace);
324 1 : $alias=array_shift($segs);
325 1 : if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
326 1 : return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext);
327 : else
328 0 : return null;
329 : }
330 : }
331 :
332 : /**
333 : * @param string alias to the path
334 : * @return string the path corresponding to the alias, null if alias not defined.
335 : */
336 : public static function getPathOfAlias($alias)
337 : {
338 1 : return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
339 : }
340 :
341 : protected static function getPathAliases()
342 : {
343 0 : return self::$_aliases;
344 : }
345 :
346 : /**
347 : * @param string alias to the path
348 : * @param string the path corresponding to the alias
349 : * @throws TInvalidOperationException if the alias is already defined
350 : * @throws TInvalidDataValueException if the path is not a valid file path
351 : */
352 : public static function setPathOfAlias($alias,$path)
353 : {
354 0 : if(isset(self::$_aliases[$alias]))
355 0 : throw new TInvalidOperationException('prado_alias_redefined',$alias);
356 0 : else if(($rp=realpath($path))!==false && is_dir($rp))
357 0 : {
358 0 : if(strpos($alias,'.')===false)
359 0 : self::$_aliases[$alias]=$rp;
360 : else
361 0 : throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
362 0 : }
363 : else
364 0 : throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
365 0 : }
366 :
367 : /**
368 : * Fatal error handler.
369 : * This method displays an error message together with the current call stack.
370 : * The application will exit after calling this method.
371 : * @param string error message
372 : */
373 : public static function fatalError($msg)
374 : {
375 0 : echo '<h1>Fatal Error</h1>';
376 0 : echo '<p>'.$msg.'</p>';
377 0 : if(!function_exists('debug_backtrace'))
378 0 : return;
379 0 : echo '<h2>Debug Backtrace</h2>';
380 0 : echo '<pre>';
381 0 : $index=-1;
382 0 : foreach(debug_backtrace() as $t)
383 : {
384 0 : $index++;
385 0 : if($index==0) // hide the backtrace of this function
386 0 : continue;
387 0 : echo '#'.$index.' ';
388 0 : if(isset($t['file']))
389 0 : echo basename($t['file']) . ':' . $t['line'];
390 : else
391 0 : echo '<PHP inner-code>';
392 0 : echo ' -- ';
393 0 : if(isset($t['class']))
394 0 : echo $t['class'] . $t['type'];
395 0 : echo $t['function'] . '(';
396 0 : if(isset($t['args']) && sizeof($t['args']) > 0)
397 0 : {
398 0 : $count=0;
399 0 : foreach($t['args'] as $item)
400 : {
401 0 : if(is_string($item))
402 0 : {
403 0 : $str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
404 0 : if (strlen($item) > 70)
405 0 : echo "'". substr($str, 0, 70) . "...'";
406 : else
407 0 : echo "'" . $str . "'";
408 0 : }
409 0 : else if (is_int($item) || is_float($item))
410 0 : echo $item;
411 0 : else if (is_object($item))
412 0 : echo get_class($item);
413 0 : else if (is_array($item))
414 0 : echo 'array(' . count($item) . ')';
415 0 : else if (is_bool($item))
416 0 : echo $item ? 'true' : 'false';
417 0 : else if (is_null($item))
418 0 : echo 'NULL';
419 0 : else if (is_resource($item))
420 0 : echo get_resource_type($item);
421 0 : $count++;
422 0 : if (count($t['args']) > $count)
423 0 : echo ', ';
424 0 : }
425 0 : }
426 0 : echo ")\n";
427 0 : }
428 0 : echo '</pre>';
429 0 : exit(1);
430 : }
431 :
432 : /**
433 : * Returns a list of user preferred languages.
434 : * The languages are returned as an array. Each array element
435 : * represents a single language preference. The languages are ordered
436 : * according to user preferences. The first language is the most preferred.
437 : * @return array list of user preferred languages.
438 : */
439 : public static function getUserLanguages()
440 : {
441 0 : static $languages=null;
442 0 : if($languages===null)
443 0 : {
444 0 : if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
445 0 : $languages[0]='en';
446 : else
447 : {
448 0 : $languages=array();
449 0 : foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
450 : {
451 0 : $array=split(';q=',trim($language));
452 0 : $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
453 0 : }
454 0 : arsort($languages);
455 0 : $languages=array_keys($languages);
456 0 : if(empty($languages))
457 0 : $languages[0]='en';
458 : }
459 0 : }
460 0 : return $languages;
461 : }
462 :
463 : /**
464 : * Returns the most preferred language by the client user.
465 : * @return string the most preferred language by the client user, defaults to English.
466 : */
467 : public static function getPreferredLanguage()
468 : {
469 51 : static $language=null;
470 51 : if($language===null)
471 51 : {
472 1 : $langs=Prado::getUserLanguages();
473 1 : $lang=explode('-',$langs[0]);
474 1 : if(empty($lang[0]) || !ctype_alpha($lang[0]))
475 1 : $language='en';
476 : else
477 1 : $language=$lang[0];
478 1 : }
479 51 : return $language;
480 : }
481 :
482 : /**
483 : * Writes a log message.
484 : * This method wraps {@link log()} by checking the application mode.
485 : * When the application is in Debug mode, debug backtrace information is appended
486 : * to the message and the message is logged at DEBUG level.
487 : * When the application is in Performance mode, this method does nothing.
488 : * Otherwise, the message is logged at INFO level.
489 : * @param string message to be logged
490 : * @param string category of the message
491 : * @see log, getLogger
492 : */
493 : public static function trace($msg,$category='Uncategorized')
494 : {
495 30 : if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
496 30 : return;
497 30 : if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
498 30 : {
499 30 : $trace=debug_backtrace();
500 30 : if(isset($trace[0]['file']) && isset($trace[0]['line']))
501 30 : $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
502 30 : $level=TLogger::DEBUG;
503 30 : }
504 : else
505 0 : $level=TLogger::INFO;
506 30 : self::log($msg,$level,$category);
507 30 : }
508 :
509 : /**
510 : * Logs a message.
511 : * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
512 : * and may be recorded in different media, such as file, email, database, using
513 : * {@link TLogRouter}.
514 : * @param string message to be logged
515 : * @param integer level of the message. Valid values include
516 : * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
517 : * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
518 : * @param string category of the message
519 : */
520 : public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
521 : {
522 30 : if(self::$_logger===null)
523 30 : self::$_logger=new TLogger;
524 30 : self::$_logger->log($msg,$level,$category);
525 30 : }
526 :
527 : /**
528 : * @return TLogger message logger
529 : */
530 : public static function getLogger()
531 : {
532 0 : if(self::$_logger===null)
533 0 : self::$_logger=new TLogger;
534 0 : return self::$_logger;
535 : }
536 :
537 : /**
538 : * Converts a variable into a string representation.
539 : * This method achieves the similar functionality as var_dump and print_r
540 : * but is more robust when handling complex objects such as PRADO controls.
541 : * @param mixed variable to be dumped
542 : * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
543 : * @param boolean whether to syntax highlight the output. Defaults to false.
544 : * @return string the string representation of the variable
545 : */
546 : public static function varDump($var,$depth=10,$highlight=false)
547 : {
548 0 : Prado::using('System.Util.TVarDumper');
549 0 : return TVarDumper::dump($var,$depth,$highlight);
550 : }
551 :
552 : /**
553 : * Localize a text to the locale/culture specified in the globalization handler.
554 : * @param string text to be localized.
555 : * @param array a set of parameters to substitute.
556 : * @param string a different catalogue to find the localize text.
557 : * @param string the input AND output charset.
558 : * @return string localized text.
559 : * @see TTranslate::formatter()
560 : * @see TTranslate::init()
561 : */
562 : public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
563 : {
564 0 : Prado::using('System.I18N.Translation');
565 0 : $app = Prado::getApplication()->getGlobalization(false);
566 :
567 0 : $params = array();
568 0 : foreach($parameters as $key => $value)
569 0 : $params['{'.$key.'}'] = $value;
570 :
571 : //no translation handler provided
572 0 : if($app===null || ($config = $app->getTranslationConfiguration())===null)
573 0 : return strtr($text, $params);
574 :
575 0 : Translation::init();
576 :
577 0 : if(empty($catalogue) && isset($config['catalogue']))
578 0 : $catalogue = $config['catalogue'];
579 :
580 : //globalization charset
581 0 : $appCharset = $app===null ? '' : $app->getCharset();
582 :
583 : //default charset
584 0 : $defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
585 :
586 : //fall back
587 0 : if(empty($charset)) $charset = $appCharset;
588 0 : if(empty($charset)) $charset = $defaultCharset;
589 :
590 0 : return Translation::formatter()->format($text,$params,$catalogue,$charset);
591 : }
592 : }
593 :
594 : /**
595 : * TReflectionClass class.
596 : * This class was originally written to cope with the incompatibility between different PHP versions.
597 : * It is equivalent to ReflectionClass for PHP version >= 5.1.0
598 : * @author Qiang Xue <qiang.xue@gmail.com>
599 : * @version $Id: PradoBase.php 2283 2007-10-01 00:33:28Z xue $
600 : * @package System
601 : * @since 3.0
602 : */
603 : class TReflectionClass extends ReflectionClass
604 : {
605 : }
606 :
607 : /**
608 : * Includes the classes essential for PradoBase class
609 : */
610 : PradoBase::using('System.TComponent');
611 : PradoBase::using('System.Exceptions.TException');
612 : PradoBase::using('System.Util.TLogger');
613 :
614 : ?>
|