| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4 // +----------------------------------------------------------------------+ 5 // | Akelos Framework - http://www.akelos.org | 6 // +----------------------------------------------------------------------+ 7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez | 8 // | Released under the GNU Lesser General Public License, see LICENSE.txt| 9 // +----------------------------------------------------------------------+ 10 11 /** 12 * @package ActiveSupport 13 * @subpackage Base 14 * @author Bermi Ferrer <bermi a.t akelos c.om> 15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org 16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> 17 */ 18 19 /** 20 * Define LOG Levels 21 * @todo Log events 22 */ 23 define('AK_LOG_NOTICE', 0); 24 define('AK_LOG_WARNING', 1); 25 define('AK_LOG_ERROR', 2); 26 27 defined('AK_FRAMEWORK_LANGUAGE') ? null : define('AK_FRAMEWORK_LANGUAGE', 'en'); 28 defined('AK_DEV_MODE') ? null : define('AK_DEV_MODE', false); 29 defined('AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION') ? null : define('AK_AUTOMATIC_CONFIG_VARS_ENCRYPTION', false); 30 31 32 /** 33 * Akelos Framework static functions 34 * 35 * Ak contains all the Akelos Framework static functions. This 36 * class acts like a name space to avoid naming collisions 37 * when PHP gets new functions into its core. And also to provide 38 * additional functionality to existing PHP functions mantaining the same interface 39 * 40 * @author Bermi Ferrer <bermi at akelos com> 41 * @copyright Copyright (c) 2002-2005, Akelos Media, S.L. http://www.akelos.org 42 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> 43 */ 44 class Ak 45 { 46 47 /** 48 * Gets an instance of AkDbAdapter 49 * 50 * Whenever a database connection is required you can get a 51 * reference to the default database connection by doing: 52 * 53 * $db =& Ak::db(); // get an adodb instance 54 * 55 * AdoDB manual can be found at http://phplens.com/adodb/ 56 * 57 * @access public 58 * @param string $dns A string containing Data Source Name (information 59 * regarding database connection) 60 * http://phplens.com/adodb/code.initialization.html#dsnsupport 61 * @static 62 * @return resource Php AdoDb instance. 63 */ 64 function &db($dsn = null) 65 { 66 require_once (AK_LIB_DIR.DS.'AkActiveRecord'.DS.'AkDbAdapter.php'); 67 return AkDbAdapter::getInstance($dsn); 68 } 69 70 /** 71 * @param string $message 72 * @param [OPTIONAL] $fatal triggers even in production-mode 73 */ 74 function deprecateWarning($message, $fatal=false) 75 { 76 if (!$fatal && AK_ENVIRONMENT == 'production'){ 77 return; 78 } 79 if (is_array($message)){ 80 trigger_error(Ak::t("DEPRECATED WARNING: ".array_shift($message),$message), E_USER_NOTICE); 81 } else { 82 trigger_error(Ak::t("DEPRECATED WARNING: ".$message), E_USER_NOTICE); 83 } 84 } 85 86 /** 87 * Gets a cache object singleton instance 88 */ 89 function &cache() 90 { 91 static $cache; 92 if(!isset($cache)){ 93 require_once (AK_LIB_DIR.DS.'AkCache.php'); 94 $cache = new AkCache(); 95 } 96 return $cache; 97 } 98 99 100 function toUrl($options, $set_routes = false) 101 { 102 static $Map; 103 if(empty($Map)){ 104 if($set_routes){ 105 $Map = $options; 106 return; 107 }else{ 108 require_once (AK_LIB_DIR.DS.'AkRouter.php'); 109 $Map = new AkRouter(); 110 if(is_file(AK_ROUTES_MAPPING_FILE)){ 111 include(AK_ROUTES_MAPPING_FILE); 112 } 113 } 114 } else if (is_a($options,'akrouter') && $set_routes) { 115 $Map = $options; 116 return; 117 } 118 return $Map->toUrl($options); 119 } 120 121 122 /** 123 * Translate strings to the current locale. 124 * 125 * When using Ak::t(), try to put entire sentences and strings 126 * in one Ak::t() call. 127 * This makes it easier for translators. HTML markup within 128 * translation strings 129 * is acceptable, if necessary. The suggested syntax for a 130 * link embedded 131 * within a translation string is: 132 * 133 * @access public 134 * @static 135 * @param string $string A string containing the English string to 136 * translate. 137 * @param array $args An associative array of replacements to make after 138 * translation. Incidences of any key in this array 139 * are replaced with the corresponding value. 140 * @return string The translated string. 141 */ 142 function t($string, $args = null, $controller = null) 143 { 144 static $framework_dictionary = array(), $lang, $_dev_shutdown = true; 145 146 if(AK_AUTOMATICALLY_UPDATE_LANGUAGE_FILES && !empty($string) && is_string($string)){ 147 require_once (AK_LIB_DIR.DS.'AkLocaleManager.php'); 148 // This adds used strings to a stack for storing new entries on the locale file after shutdown 149 AkLocaleManager::getUsedLanguageEntries($string, $controller); 150 if($_dev_shutdown){ 151 register_shutdown_function(array('AkLocaleManager','updateLocaleFiles')); 152 $_dev_shutdown = false; 153 } 154 } 155 156 if(!isset($lang)){ 157 if(!empty($_SESSION['lang'])){ 158 $lang = $_SESSION['lang']; 159 }else{ 160 $lang = Ak::lang(); 161 } 162 if(is_file(AK_CONFIG_DIR.DS.'locales'.DS.$lang.'.php')){ 163 require(AK_CONFIG_DIR.DS.'locales'.DS.$lang.'.php'); 164 $framework_dictionary = array_merge($framework_dictionary,$dictionary); 165 } 166 if(!defined('AK_LOCALE')){ 167 define('AK_LOCALE', $lang); 168 } 169 if(!empty($locale) && is_array($locale)){ 170 Ak::locale(null, $lang, $locale); 171 } 172 } 173 174 if(!empty($string) && is_array($string)){ 175 if(!empty($string[$lang])){ 176 return $string[$lang]; 177 } 178 $try_whith_lang = $args !== false && empty($string[$lang]) ? Ak::base_lang() : $lang; 179 if(empty($string[$try_whith_lang]) && $args !== false){ 180 foreach (Ak::langs() as $try_whith_lang){ 181 if(!empty($string[$try_whith_lang])){ 182 return $string[$try_whith_lang]; 183 } 184 } 185 } 186 return @$string[$try_whith_lang]; 187 } 188 189 if(isset($controller) && !isset($framework_dictionary[$controller.'_dictionary']) && is_file(AK_APP_DIR.DS.'locales'.DS.$controller.DS.$lang.'.php')){ 190 require(AK_APP_DIR.DS.'locales'.DS.$controller.DS.$lang.'.php'); 191 $framework_dictionary[$controller.'_dictionary'] = (array)$dictionary; 192 } 193 194 if(isset($controller) && isset($framework_dictionary[$controller.'_dictionary'][$string])){ 195 $string = $framework_dictionary[$controller.'_dictionary'][$string]; 196 }else { 197 $string = isset($framework_dictionary[$string]) ? $framework_dictionary[$string] : $string; 198 } 199 200 if(isset($args) && is_array($args)){ 201 $string = @str_replace(array_keys($args), array_values($args),$string); 202 } 203 204 /** 205 * @todo Prepare for multiple locales by inspecting AK_DEFAULT_LOCALE 206 */ 207 208 return $string; 209 } 210 211 212 213 /** 214 * Gets information about current locale from the locale settings on config/locales/LOCALE.php 215 * 216 * This are common settings on the locale file: 217 * 'description' // Locale description Example. Spanish 218 * 'charset' // 'ISO-8859-1'; 219 * 'date_time_format' // '%d/%m/%Y %H:%i:%s'; 220 * 'date_format' // '%d/%m/%Y'; 221 * 'long_date_format' // '%d/%m/%Y'; 222 * 'time_format' // '%H:%i'; 223 * 'long_time_format' // '%H:%i:%s'; 224 */ 225 function locale($locale_setting, $locale = null) 226 { 227 static $settings; 228 229 // We initiate the locale settings 230 Ak::t('Akelos'); 231 232 $locale = empty($locale) ? (defined('AK_LOCALE') ? AK_LOCALE : (Ak::t('Akelos') && Ak::locale($locale_setting))) : $locale; 233 234 if (empty($settings[$locale])) { 235 if(func_num_args() != 3){ // First time we ask for something using this locale so we will load locale details 236 $requested_locale = $locale; 237 if(@include(AK_CONFIG_DIR.DS.'locales'.DS.Ak::sanitize_include($requested_locale).'.php')){ 238 $locale = !empty($locale) && is_array($locale) ? $locale : array(); 239 Ak::locale(null, $requested_locale, $locale); 240 return Ak::locale($locale_setting, $requested_locale); 241 } 242 }else{ 243 $settings[$locale] = func_get_arg(2); 244 if(isset($settings[$locale]['charset'])){ 245 defined('AK_CHARSET') ? null : (define('AK_CHARSET',$settings[$locale]['charset']) && @ini_set('default_charset', AK_CHARSET)); 246 } 247 } 248 } 249 250 return isset($settings[$locale][$locale_setting]) ? $settings[$locale][$locale_setting] : false; 251 } 252 253 254 function lang($set_language = null) 255 { 256 static $lang; 257 $lang = empty($set_language) ? (empty($lang) ? AK_FRAMEWORK_LANGUAGE : $lang) : $set_language; 258 return $lang; 259 } 260 261 262 function get_url_locale($set_locale = null) 263 { 264 static $locale; 265 if(!empty($locale)){ 266 return $locale; 267 } 268 $locale = empty($set_locale) ? '' : $set_locale; 269 return $locale; 270 } 271 272 273 274 function langs() 275 { 276 static $langs; 277 if(!empty($lang)){ 278 return $lang; 279 } 280 $lang = Ak::lang(); 281 if(defined('AK_APP_LOCALES')){ 282 $langs = array_diff(explode(',',AK_APP_LOCALES.','),array('')); 283 } 284 $langs = empty($langs) ? array($lang) : $langs; 285 return $langs; 286 } 287 288 function base_lang() 289 { 290 return array_shift(Ak::langs()); 291 } 292 293 294 295 function dir($path, $options = array()) 296 { 297 $result = array(); 298 299 $path = rtrim($path, '/\\'); 300 $default_options = array( 301 'files' => true, 302 'dirs' => true, 303 'recurse' => false, 304 ); 305 306 $options = array_merge($default_options, $options); 307 308 if(is_file($path)){ 309 $result = array($path); 310 }elseif(is_dir($path)){ 311 if ($id_dir = opendir($path)){ 312 while (false !== ($file = readdir($id_dir))){ 313 if ($file != "." && $file != ".." && $file != '.svn'){ 314 if(!empty($options['files']) && !is_dir($path.DS.$file)){ 315 $result[] = $file; 316 }elseif(!empty($options['dirs'])){ 317 $result[][$file] = !empty($options['recurse']) ? Ak::dir($path.DS.$file, $options) : $file; 318 } 319 } 320 } 321 closedir($id_dir); 322 } 323 } 324 325 return array_reverse($result); 326 } 327 328 329 function file_put_contents($file_name, $content, $options = array()) 330 { 331 332 $default_options = array( 333 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP, 334 'base_path' => AK_BASE_DIR, 335 ); 336 $options = array_merge($default_options, $options); 337 338 if(!function_exists('file_put_contents')){ 339 include_once(AK_CONTRIB_DIR.DS.'pear'.DS.'PHP'.DS.'Compat.php'); 340 PHP_Compat::loadFunction(array('file_put_contents')); 341 } 342 343 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS); 344 345 if($options['ftp']){ 346 require_once (AK_LIB_DIR.DS.'AkFtp.php'); 347 $file_name = trim(str_replace(array(DS,'//'),array('/','/'),$file_name),'/'); 348 if(!AkFtp::is_dir(dirname($file_name))){ 349 AkFtp::make_dir(dirname($file_name)); 350 } 351 352 return AkFtp::put_contents($file_name, $content); 353 }else{ 354 if(!is_dir(dirname($options['base_path'].DS.$file_name))){ 355 Ak::make_dir(dirname($options['base_path'].DS.$file_name), $options); 356 } 357 358 if(!$result = file_put_contents($options['base_path'].DS.$file_name, $content)){ 359 if(!empty($content)){ 360 Ak::trace("Could not write to file: \"".$options['base_path'].DS."$file_name\". Please change file/dir permissions or enable FTP file handling by". 361 " setting the following on your config/".AK_ENVIRONMENT.".php file \n<pre>define('AK_UPLOAD_FILES_USING_FTP', true);\n". 362 "define('AK_READ_FILES_USING_FTP', false);\n". 363 "define('AK_DELETE_FILES_USING_FTP', true);\n". 364 "define('AK_FTP_PATH', 'ftp://username:password@example.com/path_to_the_framework');\n". 365 "define('AK_FTP_AUTO_DISCONNECT', true);\n</pre>"); 366 } 367 } 368 return $result; 369 } 370 } 371 372 373 function file_get_contents($file_name, $options = array()) 374 { 375 $default_options = array( 376 'ftp' => defined('AK_READ_FILES_USING_FTP') && AK_READ_FILES_USING_FTP, 377 'base_path' => AK_BASE_DIR, 378 ); 379 $options = array_merge($default_options, $options); 380 381 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS); 382 if($options['ftp']){ 383 require_once (AK_LIB_DIR.DS.'AkFtp.php'); 384 $file_name = trim(str_replace(array(DS,'//'),array('/','/'),$file_name),'/'); 385 return AkFtp::get_contents($file_name); 386 }else{ 387 return file_get_contents($options['base_path'].DS.$file_name); 388 } 389 } 390 391 /** 392 * @todo Optimize this code (dirty add-on to log command line interpreter results) 393 */ 394 function file_add_contents($file_name, $content, $options = array()) 395 { 396 $original_content = @Ak::file_get_contents($file_name, $options); 397 return Ak::file_put_contents($file_name, $original_content.$content, $options); 398 } 399 400 function file_delete($file_name, $options = array()) 401 { 402 $default_options = array( 403 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP, 404 'base_path' => AK_BASE_DIR, 405 ); 406 $options = array_merge($default_options, $options); 407 408 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS); 409 if($options['ftp']){ 410 require_once (AK_LIB_DIR.DS.'AkFtp.php'); 411 $file_name = trim(str_replace(array(DS,'//'),array('/','/'),$file_name),'/'); 412 return AkFtp::delete($file_name, true); 413 }else{ 414 return unlink($options['base_path'].DS.$file_name); 415 } 416 } 417 418 function directory_delete($dir_name, $options = array()) 419 { 420 $default_options = array( 421 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP, 422 'base_path' => AK_BASE_DIR, 423 ); 424 $options = array_merge($default_options, $options); 425 426 $sucess = true; 427 $dir_name = Ak::_getRestrictedPath($dir_name, $options); 428 429 if(empty($dir_name)){ 430 return false; 431 } 432 433 if($options['ftp']){ 434 require_once (AK_LIB_DIR.DS.'AkFtp.php'); 435 return AkFtp::delete($dir_name); 436 }else{ 437 $items = glob($options['base_path'].DS.$dir_name."/*"); 438 $hidden_items = glob($options['base_path'].DS.$dir_name."/.*"); 439 $fs_items = $items || $hidden_items ? array_merge((array)$items, (array)$hidden_items) : false; 440 if($fs_items){ 441 $items_to_delete = array('directories'=>array(), 'files'=>array()); 442 foreach($fs_items as $fs_item) { 443 if($fs_item[strlen($fs_item)-1] != '.'){ 444 $items_to_delete[ (is_dir($fs_item) ? 'directories' : 'files') ][] = $fs_item; 445 } 446 } 447 foreach ($items_to_delete['files'] as $file){ 448 Ak::file_delete($file, $options); 449 } 450 foreach ($items_to_delete['directories'] as $directory){ 451 $sucess = $sucess ? Ak::directory_delete($directory, $options) : $sucess; 452 } 453 } 454 return $sucess ? @rmdir($options['base_path'].DS.$dir_name) : $sucess; 455 } 456 } 457 458 function make_dir($path, $options = array()) 459 { 460 $default_options = array( 461 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP, 462 'base_path' => AK_BASE_DIR 463 ); 464 $options = array_merge($default_options, $options); 465 466 $path = trim(str_replace($options['base_path'], '',$path),DS); 467 if($options['ftp']){ 468 require_once(AK_LIB_DIR.DS.'AkFtp.php'); 469 $path = trim(str_replace(array(DS,'//'),array('/','/'),$path),'/'); 470 return AkFtp::make_dir($path); 471 }else{ 472 $path = $options['base_path'].DS.$path; 473 if (!file_exists($path)){ 474 Ak::make_dir(dirname($path), $options); 475 return mkdir($path); 476 } 477 } 478 return false; 479 } 480 481 /** 482 * This static method will copy recursively all the files or directories from one 483 * path within an Akelos application to another. 484 * 485 * It uses current installation settings, so it can perform copies via the filesystem or via FTP 486 */ 487 function copy($origin, $target, $options = array()) 488 { 489 $default_options = array( 490 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP, 491 'base_path' => AK_BASE_DIR, 492 ); 493 $options = array_merge($default_options, $options); 494 495 $sucess = true; 496 497 $origin = Ak::_getRestrictedPath($origin, $options); 498 $target = Ak::_getRestrictedPath($target, $options); 499 500 if(empty($origin) || empty($target)){ 501 return false; 502 } 503 504 if($options['ftp']){ 505 require_once (AK_LIB_DIR.DS.'AkFtp.php'); 506 } 507 $destination = str_replace($origin, $target, $origin); 508 if(is_file($options['base_path'].DS.$origin)){ 509 return Ak::file_put_contents($options['base_path'].DS.$destination, Ak::file_get_contents($options['base_path'].DS.$origin, $options), $options); 510 } 511 Ak::make_dir($options['base_path'].DS.$destination); 512 if($fs_items = glob($options['base_path'].DS.$origin."/*")){ 513 $items_to_copy = array('directories'=>array(), 'files'=>array()); 514 foreach($fs_items as $fs_item) { 515 $items_to_copy[ (is_dir($fs_item) ? 'directories' : 'files') ][] = $fs_item; 516 } 517 foreach ($items_to_copy['files'] as $file){ 518 $destination = str_replace($origin, $target, $file); 519 $sucess = $sucess ? Ak::file_put_contents($destination, Ak::file_get_contents($file, $options), $options) : $sucess; 520 } 521 foreach ($items_to_copy['directories'] as $directory){ 522 $destination = str_replace($origin, $target, $directory); 523 $sucess = $sucess ? Ak::copy($directory, $destination, $options) : $sucess; 524 } 525 } 526 return $sucess; 527 } 528 529 /** 530 * Returns a path restricting it to a base location 531 * 532 * This is used by Akelos to prevent functions namespaced under Ak 533 * from writing out of the Akelos base directory for security reasons. 534 */ 535 function _getRestrictedPath($path, $options = array()) 536 { 537 $default_options = array( 538 'ftp' => false, 539 'base_path' => AK_BASE_DIR, 540 ); 541 $options = array_merge($default_options, $options); 542 543 $path = str_replace('..','', rtrim($path,'\\/. ')); 544 $path = trim(str_replace($options['base_path'], '',$path),DS); 545 546 if($options['ftp']){ 547 $path = trim(str_replace(array(DS,'//'),array('/','/'), $path),'/'); 548 } 549 550 return $path; 551 } 552 553 554 /** 555 * Perform a web request 556 * 557 * @param string $url URL we are going to request. 558 * @param array $options Options for current request. 559 * Options are: 560 * * referer: URL that will be set as referer url. Default is current url 561 * * params: Parameter for the request. Can be an array of key=>values or a url params string like key=value&key2=value2 562 * * method: In case params are given the will be requested using get method by default. Specify post if get is not what you need. 563 * @return string 564 */ 565 function url_get_contents($url, $options = array()) 566 { 567 include_once (AK_LIB_DIR.DS.'AkHttpClient.php'); 568 $Client =& new AkHttpClient(); 569 $method = empty($options['method']) ? 'get' : strtolower($options['method']); 570 if(empty($method) || !in_array($method, array('get','post','put','delete'))){ 571 trigger_error(Ak::t('Invalid HTTP method %method', array('%method'=>$options['method'])), E_USER_ERROR); 572 } 573 return $Client->$method($url, $options); 574 } 575 576 577 /** 578 * Trace helper function for development purposes 579 * 580 * @access public 581 * @static 582 * @param string $text Helper text 583 * @param string $line Helper line 584 * @param string $file Helper file 585 * @return echoes result to screen 586 */ 587 function trace($text = null, $line = null, $file = null) 588 { 589 static $counter = 0; 590 if(!AK_DEBUG){ 591 //return; 592 } 593 594 $line = isset($line) ? "Line: $line".(AK_CLI?"\n":"<br />") : ""; 595 $file = isset($file) ? "File: $file".(AK_CLI?"\n":"<br />") : ""; 596 597 if(!isset($text)){ 598 $counter++; 599 $text = ''; 600 }else { 601 $text = AK_CLI?'---> '.$text:'<b>---></b>'.$text; 602 } 603 604 echo AK_CLI?"----------------\n$line $file $text\n----------------\n":"<hr /><div>$line $file $text</div><hr />\n"; 605 606 } 607 608 609 610 611 /** 612 * Outputs debug info given a PHP resource (vars, objects, 613 * arrays...) 614 * 615 * @access public 616 * @static 617 * @param mixed $data Data to debug. It can be an object, array, 618 * resource.. 619 * @return void Prints debug info. 620 */ 621 function debug ($data, $_functions=0) 622 { 623 if(!AK_DEBUG && !AK_DEV_MODE){ 624 return; 625 } 626 627 if($_functions!=0) { 628 $sf=1; 629 } else { 630 $sf=0 ; 631 } 632 if(is_object($data) && method_exists($data, 'debug')){ 633 echo AK_CLI ? 634 "\n------------------------------------\nEntering on ".get_class($data)." debug() method\n\n": 635 "<hr /><h2>Entering on ".get_class($data)." debug() method</h2>"; 636 if(!empty($data->__activeRecordObject)){ 637 $data->toString(true); 638 } 639 $data->debug(); 640 return ; 641 } 642 if (isset ($data)) { 643 if (is_array($data) || is_object($data)) { 644 645 if (count ($data)) { 646 echo AK_CLI ? "/--\n" : "<ol>\n"; 647 while (list ($key,$value) = each ($data)) { 648 $type=gettype($value); 649 if ($type=="array" || $type == "object") { 650 ob_start(); 651 Ak::debug ($value,$sf); 652 $lines = explode("\n",ob_get_clean()."\n"); 653 foreach ($lines as $line){ 654 echo "\t".$line."\n"; 655 } 656 } elseif (eregi ("function", $type)) { 657 if ($sf) { 658 AK_CLI ? printf ("\t* (%s) %s:\n",$type, $key, $value) : 659 printf ("<li>(%s) <b>%s</b> </li>\n",$type, $key, $value); 660 } 661 } else { 662 if (!$value) { 663 $value="(none)"; 664 } 665 AK_CLI ? printf ("\t* (%s) %s = %s\n",$type, $key, $value) : 666 printf ("<li>(%s) <b>%s</b> = %s</li>\n",$type, $key, $value); 667 } 668 } 669 echo AK_CLI ? "\n--/\n" : "</ol>fin.\n"; 670 } else { 671 echo "(empty)"; 672 } 673 } 674 } 675 } 676 677 678 679 680 681 /** 682 * Gets information about given object 683 * 684 * @access public 685 * @static 686 * @uses Ak::get_this_object_methods 687 * @uses Ak::get_this_object_attributes 688 * @param object &$object Object to get info from 689 * @param boolean $include_inherited_info By setting this to true, parent Object properties 690 * and methods will be included. 691 * @return string html output with Object info 692 */ 693 function get_object_info($object, $include_inherited_info = false) 694 { 695 $object_name = get_class($object); 696 $methods = $include_inherited_info ? get_class_methods($object) : Ak::get_this_object_methods($object); 697 $vars = $include_inherited_info ? get_class_vars($object_name) : Ak::get_this_object_attributes($object); 698 $var_desc = ''; 699 if(is_array($vars)){ 700 $var_desc = '<ul>'; 701 foreach ($vars as $varname=>$var_value){ 702 $var_desc .= "<li>$varname = $var_value (". gettype($var_value) .")</li>\n"; 703 } 704 $var_desc .= "</ul>"; 705 } 706 return Ak::t('Object <b>%object_name</b> information:<hr> <b>object Vars:</b><br>%var_desc <hr> <b>object Methods:</b><br><ul><li>%methods</li></ul>',array('%object_name'=>$object_name,'%var_desc'=>$var_desc,'%methods'=>join("();</li>\n<li>",$methods) .'();')); 707 } 708 709 710 711 712 /** 713 * Gets selected object methods. 714 * 715 * WARNING: Inherited methods are not returned by this 716 * function. You can fetch them by using PHP native function 717 * get_class_methods 718 * 719 * @access public 720 * @static 721 * @see get_this_object_attributes 722 * @see get_object_info 723 * @param object &$object Object to inspect 724 * @return array Returns an array with selected object methods. It 725 * does not return inherited methods 726 */ 727 function get_this_object_methods($object) 728 { 729 $array1 = get_class_methods($object); 730 if($parent_object = get_parent_class($object)){ 731 $array2 = get_class_methods($parent_object); 732 $array3 = array_diff($array1, $array2); 733 }else{ 734 $array3 = $array1; 735 } 736 return array_values((array)$array3); 737 } 738 739 740 741 742 /** 743 * Get selected objects default attributes 744 * 745 * WARNING: Inherited attributes are not returned by this 746 * function. You can fetch them by using PHP native function 747 * get_class_vars 748 * 749 * @access public 750 * @static 751 * @see get_this_object_methods 752 * @see get_object_info 753 * @param object &$object Object to inspect 754 * @return void Returns an array with selected object attributes. 755 * It does not return inherited attributes 756 */ 757 function get_this_object_attributes($object) 758 { 759 $object = get_class($object); 760 $array1 = get_class_vars($object); 761 if($parent_object = get_parent_class($object)){ 762 $array2 = get_class_vars($parent_object); 763 $array3 = array_diff_assoc($array1, $array2); 764 }else{ 765 $array3 = $array1; 766 } 767 return (array)$array3; 768 } 769 770 771 772 function &getLogger() 773 { 774 static $Logger; 775 if(empty($Logger)){ 776 require_once (AK_LIB_DIR.DS.'AkLogger.php'); 777 $Logger = new AkLogger(); 778 } 779 $return =& $Logger; 780 return $Logger; 781 } 782 783 784 function get_constants() 785 { 786 $constants = get_defined_constants(); 787 $keys = array_keys($constants); 788 foreach ($keys as $k){ 789 if(substr($k,0,3) != 'AK_'){ 790 unset($constants[$k]); 791 } 792 } 793 return $constants; 794 } 795 796 797 /** 798 * @todo Use timezone time 799 */ 800 function time() 801 { 802 return time()+(defined('AK_TIME_DIFERENCE') ? AK_TIME_DIFERENCE*3600 : 0); 803 } 804 805 function gmt_time() 806 { 807 return Ak::time()+(AK_TIME_DIFERENCE_FROM_GMT*3600); 808 } 809 810 811 /** 812 * Gets a timestamp for input date provided in one of this formats: "year-month-day hour:min:sec", "year-month-day", "hour:min:sec" 813 */ 814 function getTimestamp($iso_date_or_hour = null) 815 { 816 if(empty($iso_date_or_hour)){ 817 return Ak::time(); 818 } 819 if (!preg_match("/^ 820 ([0-9]{4})[-\/\.]? # year 821 ([0-9]{1,2})[-\/\.]? # month 822 ([0-9]{1,2})[ -]? # day 823 ( 824 ([0-9]{1,2}):? # hour 825 ([0-9]{2}):? # minute 826 ([0-9\.]{0,4}) # seconds 827 )?/x", ($iso_date_or_hour), $rr)){ 828 if (preg_match("|^(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($iso_date_or_hour), $rr)){ 829 return empty($rr[0]) ? Ak::time() : mktime($rr[2],$rr[3],$rr[4]); 830 } 831 }else{ 832 if($rr[1]>=2038 || $rr[1]<=1970){ 833 require_once(AK_CONTRIB_DIR.DS.'adodb'.DS.'adodb-time.inc.php'); 834 return isset($rr[5]) ? adodb_mktime($rr[5],$rr[6],(int)$rr[7],$rr[2],$rr[3],$rr[1]) : adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 835 }else{ 836 return isset($rr[5]) ? mktime($rr[5],$rr[6],(int)$rr[7],$rr[2],$rr[3],$rr[1]) : mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 837 } 838 } 839 trigger_error(Ak::t('Invalid ISO date. You must supply date in one of the following formats: "year-month-day hour:min:sec", "year-month-day", "hour:min:sec"')); 840 return false; 841 } 842 843 /** 844 * Return formatted date. 845 * 846 * You can supply a format as defined at http://php.net/date 847 * 848 * Default date is in ISO format 849 */ 850 function getDate($timestamp = null, $format = null) 851 { 852 $timestamp = !isset($timestamp) ? Ak::time() : $timestamp; 853 $use_adodb = $timestamp <= -3600 || $timestamp >= 2147468400; 854 if($use_adodb){ 855 require_once(AK_CONTRIB_DIR.DS.'adodb'.DS.'adodb-time.inc.php'); 856 } 857 if(!isset($format)){ 858 return $use_adodb ? adodb_date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s', $timestamp); 859 }elseif (!empty($format)){ 860 return $use_adodb ? adodb_date($format, $timestamp) : date($format, $timestamp); 861 } 862 trigger_error(Ak::t('You must supply a valid UNIX timetamp. You can get the timestamp by calling Ak::getTimestamp("2006-09-27 20:45:57")')); 863 return false; 864 } 865 866 867 /** 868 * mail function substitute. Uses the PEAR::Mail() function API. 869 * 870 * Messaging subsystem for user communication. See PEAR::Mail() function in PHP 871 * documentation for information. 872 * 873 * User must declare any of these variables for specify the outgoing method. Currently, 874 * only Sendmail and STMP methods are available . Variables 875 * for using any of these methods are: 876 * 877 * AK_SENDMAIL = 0 878 * AK_SMTP = 1 879 * 880 * For future upgrades, you must define which constants must be declared and add 881 * the functionality. 882 * 883 * NOTE: If messaging method is SMTP, you must declare in config file (/config/config.php) 884 * the outgoing SMTP server and the authentication pair user/password as constants 885 * AK_SMTP_SERVER, AK_SMTP_USER and AK_SMTP_PASSWORD, respectively. 886 * 887 * 888 * @param $from 889 * 890 * User who sends the mail. 891 * 892 * @param $to 893 * 894 * Receiver, or receivers of the mail. 895 * 896 * The formatting of this string must comply with RFC 2822. Some examples are: 897 * 898 * user@example.com 899 * user@example.com, anotheruser@example.com 900 * User <user@example.com> 901 * User <user@example.com>, Another User <anotheruser@example.com> 902 * 903 * @param $subject 904 * 905 * Subject of the email to be sent. This must not contain any newline 906 * characters, or the mail may not be sent properly. 907 * 908 * @param $body 909 * 910 * Message to be sent. 911 * 912 * @param additional_headers (optional) 913 * 914 * Array to be inserted at the end of the email header. 915 * 916 * This is typically used to add extra headers (Bcc) in an associative array, where the 917 * array key is the header name (i.e., 'Bcc'), and the array value is the header value 918 * (i.e., 'test'). The header produced from those values would be 'Bcc: test'. 919 * 920 * @return boolean whether message has been sent or not. 921 * 922 */ 923 function mail ($from, $to, $subject, $body, $additional_headers = array()) 924 { 925 require_once(AK_CONTRIB_DIR.DS.'pear'.DS.'Mail.php'); 926 927 static $mail_connector; 928 929 if(!isset($mail_connector)){ 930 if (defined('AK_SENDMAIL')) { 931 // Using Sendmail daemon without parameters. 932 $mail_connector = Mail::factory('sendmail'); 933 } else if (defined('AK_SMTP') && AK_SMTP) { 934 // Using external SMTP server. 935 $params['host'] = AK_SMTP_SERVER; 936 $params['username'] = AK_SMTP_USER; 937 $params['password'] = AK_SMTP_PASSWORD; 938 939 $mail_connector = Mail::factory('smtp', $params); 940 } else { 941 // Using PHP mail() function thru PEAR. Factory without parameters. 942 $mail_connector = Mail::factory('mail'); 943 } 944 } 945 946 $recipients['To'] = $to; 947 948 if (!empty($additional_headers)) { 949 foreach ($additional_headers as $k=>$v) { 950 951 if (strtolower($k)=='cc' || strtolower($k)=='cc:') { 952 $recipients['cc'] = $v; 953 unset($additional_headers['cc']); 954 } 955 956 if (strtolower($k)=='bcc' || strtolower($k)=='bcc:') { 957 $recipients['bcc'] = $v; 958 unset($additional_headers['bcc']); 959 } 960 } 961 } 962 963 $headers['From'] = $from; 964 $headers['Subject'] = $subject; 965 $headers['Content-Type'] = empty($headers['Content-Type']) ? 'text/plain; charset='.Ak::locale('charset').'; format=flowed' : $headers['Content-Type']; 966 967 $headers = array_merge($headers, $additional_headers); 968 969 return $mail_connector->send($recipients, $headers, $body) == true; 970 } 971 972 973 /** 974 * @todo move this out of here and use Pear Benchmark instead 975 */ 976 function profile($message = '') 977 { 978 static $profiler; 979 if(AK_DEV_MODE && AK_ENABLE_PROFILER){ 980 if(!isset($profiler)){ 981 @require_once (AK_LIB_DIR.DS.'AkProfiler.php'); 982 $profiler = new AkProfiler(); 983 $profiler->init(); 984 register_shutdown_function(array(&$profiler,'showReport')); 985 }else { 986 $profiler->setFlag($message); 987 } 988 } 989 } 990 991 992 /** 993 * Gets the size of given element. Counts arrays, returns numbers, string length or executes size() method on given object 994 */ 995 function size($element) 996 { 997 if(is_array($element)){ 998 return count($element); 999 }elseif (is_numeric($element) && !is_string($element)){ 1000 return $element; 1001 }elseif (is_string($element)){ 1002 return strlen($element); 1003 }elseif (is_object($element) && method_exists($element,'size')){ 1004 return $element->size(); 1005 }else{ 1006 return 0; 1007 } 1008 } 1009 1010 1011 /** 1012 * Select is a function for selecting items from double depth array. 1013 * This is useful when you just need some fields for generating 1014 * tables, select lists with only desired fields. 1015 * 1016 * $People = array( 1017 * array('name'=>'Jose','email'=>'jose@example.com','address'=>'Colon, 52'), 1018 * array('name'=>'Alicia','email'=>'alicia@example.com','address'=>'Mayor, 45'), 1019 * array('name'=>'Hilario','email'=>'hilario@example.com','address'=>'Carlet, 78'), 1020 * array('name'=>'Bermi','email'=>'bermi@example.com','address'=>'Vilanova, 33'), 1021 * ); 1022 * 1023 * $people_for_table_generation = Ak::select($People,'name','email'); 1024 * 1025 * Now $people_for_table_generation will hold an array with 1026 * array ( 1027 * array ('name' => 'Jose','email' => 'jose@example.com'), 1028 * array ('name' => 'Alicia','email' => 'alicia@example.com'), 1029 * array ('name' => 'Hilario','email' => 'hilario@example.com'), 1030 * array ('name' => 'Bermi','email' => 'bermi@example.com') 1031 * ); 1032 */ 1033 1034 function select(&$source_array) 1035 { 1036 $resulting_array = array(); 1037 if(!empty($source_array) && is_array($source_array) && func_num_args() > 1) { 1038 $args = array_slice(func_get_args(),1); 1039 foreach ($source_array as $source_item){ 1040 $item_fields = array(); 1041 foreach ($args as $arg){ 1042 if(is_object($source_item) && isset($source_item->$arg)){ 1043 $item_fields[$arg] = $source_item->$arg; 1044 }elseif(is_array($source_item) && isset($source_item[$arg])){ 1045 $item_fields[$arg] = $source_item[$arg]; 1046 } 1047 } 1048 if(!empty($item_fields)){ 1049 $resulting_array[] = $item_fields; 1050 } 1051 } 1052 } 1053 return $resulting_array; 1054 } 1055 1056 function collect(&$source_array, $key_index, $value_index) 1057 { 1058 $resulting_array = array(); 1059 if(!empty($source_array) && is_array($source_array)) { 1060 foreach ($source_array as $source_item){ 1061 if(is_object($source_item)){ 1062 $resulting_array[@$source_item->$key_index] = @$source_item->$value_index; 1063 }elseif(is_array($source_item)){ 1064 $resulting_array[@$source_item[$key_index]] = @$source_item[$value_index]; 1065 } 1066 } 1067 } 1068 return $resulting_array; 1069 } 1070 1071 function delete($source_array, $attributes_to_delete_from_array) 1072 { 1073 $resulting_array = (array)$source_array; 1074 $args = array_slice(func_get_args(),1); 1075 $args = count($args) == 1 ? Ak::toArray($args[0]) : $args; 1076 foreach ($args as $arg){ 1077 unset($resulting_array[$arg]); 1078 } 1079 return $resulting_array; 1080 } 1081 1082 function &singleton($class_name, &$arguments) 1083 { 1084 static $instances; 1085 if(!isset($instances[$class_name])) { 1086 if(is_object($arguments)){ 1087 $instances[$class_name] =& new $class_name($arguments); 1088 }else{ 1089 if(Ak::size($arguments) > 0){ 1090 eval("\$instances[\$class_name] =& new \$class_name(".var_export($arguments, true)."); "); 1091 }else{ 1092 $instances[$class_name] =& new $class_name(); 1093 } 1094 } 1095 $instances[$class_name]->__singleton_id = md5(microtime().rand(1000,9000)); 1096 } 1097 return $instances[$class_name]; 1098 } 1099 1100 1101 function xml_to_array ($xml_data) 1102 { 1103 $xml_parser = xml_parser_create (); 1104 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0); 1105 xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1); 1106 xml_parse_into_struct ($xml_parser, $xml_data, $vals, $index); 1107 xml_parser_free ($xml_parser); 1108 $params = array(); 1109 $ptrs[0] = & $params; 1110 foreach ($vals as $xml_elem) { 1111 $level = $xml_elem['level'] - 1; 1112 switch ($xml_elem['type']) { 1113 case 'open': 1114 $tag_or_id = (array_key_exists ('attributes', $xml_elem)) ? @$xml_elem['attributes']['ID'] : $xml_elem['tag']; 1115 $ptrs[$level][$tag_or_id][] = array (); 1116 $ptrs[$level+1] = & $ptrs[$level][$tag_or_id][count($ptrs[$level][$tag_or_id])-1]; 1117 break; 1118 case 'complete': 1119 $ptrs[$level][$xml_elem['tag']] = (isset ($xml_elem['value'])) ? $xml_elem['value'] : ''; 1120 break; 1121 } 1122 } 1123 return ($params); 1124 } 1125 1126 function array_to_xml($array, $header = "<?xml version=\"1.0\"?>\r\n", $parent = 'EMPTY_TAG') 1127 { 1128 static $_tags = array(); 1129 $xml = $header; 1130 foreach ($array as $key => $value) { 1131 $key = is_numeric($key) ? $parent : $key; 1132 $value = is_array($value) ? "\r\n".Ak::array_to_xml($value, '', $key) : $value; 1133 $_tags[$key] = $key; 1134 $xml .= sprintf("<%s>%s</%s>\r\n", $key, $value, $key); 1135 $parent = $key; 1136 } 1137 foreach ($_tags as $_tag){ 1138 $xml = str_replace(array("<$_tag>\r\n<$_tag>","</$_tag>\r\n</$_tag>"),array("<$_tag>","</$_tag>"),$xml); 1139 } 1140 return $xml; 1141 } 1142 1143 1144 function encrypt($data, $key = null) 1145 { 1146 $key = empty($key) ? md5(AK_SESSION_NAME) : $key; 1147 srand((double)microtime() *1000000); 1148 $k2 = md5(rand(0, 32000)); 1149 $c = 0; 1150 $m = ''; 1151 for ($i = 0 ; $i < strlen($data) ; $i++) { 1152 if ($c == strlen($k2)) $c = 0; 1153 $m.= substr($k2, $c, 1) .(substr($data, $i, 1) ^substr($k2, $c, 1)); 1154 $c++; 1155 } 1156 $k = md5($key); 1157 $c = 0; 1158 $t = $m; 1159 $m = ''; 1160 for ($i = 0 ; $i < strlen($t) ; $i++) { 1161 if ($c == strlen($k)) { 1162 $c = 0; 1163 } 1164 $m.= substr($t, $i, 1) ^substr($k, $c, 1); 1165 $c++; 1166 } 1167 return base64_encode($m); 1168 } 1169 1170 function decrypt($encrypted_data, $key = null) 1171 { 1172 $key = empty($key) ? md5(AK_SESSION_NAME) : $key; 1173 $t = base64_decode($encrypted_data); 1174 $k = md5($key); 1175 $c = 0; 1176 $m = ''; 1177 for ($i = 0 ; $i < strlen($t) ; $i++) { 1178 if ($c == strlen($k)) $c = 0; 1179 $m.= substr($t, $i, 1) ^substr($k, $c, 1); 1180 $c++; 1181 } 1182 $t = $m; 1183 $m = ''; 1184 for ($i = 0 ; $i < strlen($t) ; $i++) { 1185 $d = substr($t, $i, 1); 1186 $i++; 1187 $m.= (substr($t, $i, 1) ^$d); 1188 } 1189 return $m; 1190 } 1191 1192 1193 function blowfishEncrypt($data, $key = null) 1194 { 1195 $key = empty($key) ? md5(AK_SESSION_NAME) : $key; 1196 $key = substr($key,0,56); 1197 require_once(AK_CONTRIB_DIR.DS.'pear'.DS.'Crypt'.DS.'Blowfish.php'); 1198 $Blowfish =& Ak::singleton('Crypt_Blowfish', $key); 1199 $Blowfish->setKey($key); 1200 return $Blowfish->encrypt(base64_encode($data)); 1201 } 1202 1203 function blowfishDecrypt($encrypted_data, $key = null) 1204 { 1205 $key = empty($key) ? md5(AK_SESSION_NAME) : $key; 1206 $key = substr($key,0,56); 1207 require_once(AK_CONTRIB_DIR.DS.'pear'.DS.'Crypt'.DS.'Blowfish.php'); 1208 $Blowfish =& Ak::singleton('Crypt_Blowfish', $key); 1209 $Blowfish->setKey($key); 1210 return base64_decode($Blowfish->decrypt($encrypted_data)); 1211 } 1212 1213 1214 function randomString($max_length = 8) 1215 { 1216 $randomString = ''; 1217 srand((double)microtime()*1000000); 1218 for($i=0;$i<$max_length;$i++){ 1219 $randnumber = rand(48,120); 1220 while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96)){ 1221 $randnumber = rand(48,120); 1222 } 1223 $randomString .= chr($randnumber); 1224 } 1225 return $randomString; 1226 } 1227 1228 1229 function compress($data, $format = 'gzip') 1230 { 1231 $key = Ak::randomString(15); 1232 $compressed_file = AK_TMP_DIR.DS.'d'.$key; 1233 $uncompressed_file = AK_TMP_DIR.DS.'s'.$key; 1234 if(Ak::file_put_contents($uncompressed_file, $data, array('base_path'=>AK_TMP_DIR))){ 1235 $compressed = gzopen($compressed_file,'w9'); 1236 $uncompressed = fopen($uncompressed_file, 'rb'); 1237 while(!feof($uncompressed)){ 1238 $string = fread($uncompressed, 1024*512); 1239 gzwrite($compressed, $string, strlen($string)); 1240 } 1241 fclose($uncompressed); 1242 gzclose($compressed); 1243 }else{ 1244 trigger_error(Ak::t('Could not write to temporary directory for generating compressed file using Ak::compress(). Please provide write access to %dirname', array('%dirname'=>AK_TMP_DIR)), E_USER_ERROR); 1245 } 1246 $result = Ak::file_get_contents($compressed_file, array('base_path'=>AK_TMP_DIR)); 1247 return $result; 1248 } 1249 1250 function uncompress($compressed_data, $format = 'gzip') 1251 { 1252 $key = Ak::randomString(15); 1253 $compressed_file = AK_TMP_DIR.DS.'s'.$key; 1254 $uncompressed_file = AK_TMP_DIR.DS.'d'.$key; 1255 1256 if(Ak::file_put_contents($compressed_file, $compressed_data, array('base_path'=>AK_TMP_DIR))){ 1257 $compressed = gzopen($compressed_file, "r"); 1258 $uncompressed = fopen($uncompressed_file, "w"); 1259 while(!gzeof($compressed)){ 1260 $string = gzread($compressed, 4096); 1261 fwrite($uncompressed, $string, strlen($string)); 1262 } 1263 gzclose($compressed); 1264 fclose($uncompressed); 1265 }else{ 1266 trigger_error(Ak::t('Could not write to temporary directory for generating uncompressing file using Ak::uncompress(). Please provide write access to %dirname', array('%dirname'=>AK_TMP_DIR)), E_USER_ERROR); 1267 } 1268 $result = Ak::file_get_contents($uncompressed_file, array('base_path'=>AK_TMP_DIR)); 1269 return $result; 1270 } 1271 1272 1273 function unzip($file_to_unzip, $destination_folder) 1274 { 1275 require_once (AK_LIB_DIR.DS.'AkZip.php'); 1276 $ArchiveZip =& new AkZip($file_to_unzip); 1277 $ArchiveZip->extract(array('add_path'=>str_replace(DS,'/',$destination_folder))); 1278 } 1279 1280 1281 function decompress($compressed_data, $format = 'gzip') 1282 { 1283 return Ak::uncompress($compressed_data, $format); 1284 } 1285 1286 1287 function handleStaticCall() 1288 { 1289 if (AK_PHP5) { 1290 trigger_error(Ak::t('Static calls emulation is not supported by PHP5 < 5.4')); 1291 die(); 1292 } 1293 $static_call = array_slice(debug_backtrace(),1,1); 1294 return call_user_func_array(array(new $static_call[0]['class'](),$static_call[0]['function']),$static_call[0]['args']); 1295 } 1296 1297 1298 /** 1299 * Gets an array or a comma separated list of models. Then it includes its 1300 * respective files and returns an array of available models. 1301 * 1302 * @return array available models 1303 */ 1304 function import() 1305 { 1306 $args = func_get_args(); 1307 $args = is_array($args[0]) ? $args[0] : (func_num_args() > 1 ? $args : Ak::stringToArray($args[0])); 1308 $models = array(); 1309 foreach ($args as $arg){ 1310 $model_name = AkInflector::camelize($arg); 1311 if (class_exists($model_name)){ 1312 $models[] = $model_name; 1313 continue; 1314 } 1315 $model = AkInflector::toModelFilename($model_name); 1316 if (file_exists($model)){ 1317 $models[] = $model_name; 1318 include_once($model); 1319 continue; 1320 } 1321 // Shouldn't we trigger an user-error?: Unknown Model or could not find the Model 1322 } 1323 1324 return $models; 1325 } 1326 1327 function import_mailer() 1328 { 1329 require_once (AK_LIB_DIR.DS.'AkActionMailer.php'); 1330 $args = func_get_args(); 1331 return call_user_func_array(array('Ak','import'),$args); 1332 } 1333 1334 function uses() 1335 { 1336 $args = func_get_args(); 1337 return call_user_func_array(array('Ak','import'),$args); 1338 } 1339 1340 function stringToArray($string) 1341 { 1342 $args = $string; 1343 if(count($args) == 1 && !is_array($args)){ 1344 (array)$args = array_unique(array_map('trim',array_diff(explode(',',strtr($args.',',';|-',',,,')),array('')))); 1345 } 1346 return $args; 1347 } 1348 1349 1350 function toArray() 1351 { 1352 $args = func_get_args(); 1353 return is_array($args[0]) ? $args[0] : (func_num_args() === 1 ? Ak::stringToArray($args[0]) : $args); 1354 } 1355 1356 /** 1357 * Returns an array including only the elements with provided keys. 1358 * 1359 * This is useful to limit the parameters of an array used by a method. 1360 * 1361 * This utility can be used for modifying arrays which is useful for securing record creation/updating. 1362 * 1363 * If you have this code on a controller 1364 * 1365 * $this->user->setAttributes($this->params['user']); 1366 * 1367 * and your users table has a column named is_admin. All it would take to a malicious user is to modify the page html to add the need field and gain admin privileges. 1368 * 1369 * You could avoid by using the new Ak::pick method which will return and array with desired keys. 1370 * 1371 * $this->user->setAttributes(Ak::pick('name,email', $this->params['user'])); 1372 * 1373 */ 1374 function pick($keys, $source_array) 1375 { 1376 $result = array(); 1377 foreach (Ak::toArray($keys) as $k){ 1378 $result[$k] = isset($source_array[$k]) ? $source_array[$k] : null; 1379 } 1380 return $result; 1381 } 1382 1383 /** 1384 * Gets a copy of the first element of an array. Similar to array_shift but it does not modify the original array 1385 */ 1386 function first() 1387 { 1388 $args = func_get_args(); 1389 return array_shift(array_slice(is_array($args[0]) ? $args[0] : $args , 0)); 1390 } 1391 1392 /** 1393 * Gets a copy of the last element of an array. Similar to array_pop but it does not modify the original array 1394 */ 1395 function last() 1396 { 1397 $args = func_get_args(); 1398 return array_shift(array_slice(is_array($args[0]) ? $args[0] : $args , -1)); 1399 } 1400 1401 /** 1402 * Includes PHP functions that are not available on current PHP version 1403 */ 1404 function compat($function_name) 1405 { 1406 ak_compat($function_name); 1407 } 1408 1409 1410 /** 1411 * The Akelos Framework has an standardized way to convert between formats. 1412 * You can find available converters on AkConverters 1413 * 1414 * Usage Example: In order to convert from HTML to RTF you just need to call. 1415 * $rtf = Ak::convert('html','rtf', $my_html_file, array('font_size'=> 24)); 1416 * 1417 * Where the last option is an array of options for selected converter. 1418 * 1419 * Previous example is the same as. 1420 * 1421 * $rtf = Ak::convert(array('from'=>'html','to'=>'rtf', 'source' => $my_html_file, 'font_size'=> 24)); 1422 * 1423 * In order to create converters, you just need to name them "SourceFormatName + To + DestinationFormatName". 1424 * Whenever you need to call the, you need to specify the "path" option where your converter is located. 1425 * The only thing you converter must implement is a convert function. Passes options will be made available 1426 * as attributes on the converter. 1427 * If your converter needs to prepare something before the convert method is called, you just need to implement 1428 * a "init" method. You can avoid this by inspecting passed attributes to your constructor 1429 */ 1430 function convert() 1431 { 1432 $args = func_get_args(); 1433 $number_of_arguments = func_num_args(); 1434 if($number_of_arguments > 1){ 1435 $options = array(); 1436 if($number_of_arguments > 3 && is_array($args[$number_of_arguments-1])){ 1437 $options = array_pop($args); 1438 } 1439 $options['from'] = $args[0]; 1440 $options['to'] = $args[1]; 1441 $options['source'] = $args[2]; 1442 }else{ 1443 $options = $args; 1444 } 1445 if ($options['from'] == $options['to']) { 1446 return $options['source']; 1447 } 1448 $options['class_prefix'] = empty($options['class_prefix']) && empty($options['path']) ? 'Ak' : $options['class_prefix']; 1449 $options['path'] = rtrim(empty($options['path']) ? AK_LIB_DIR.DS.'AkConverters' : $options['path'], DS."\t "); 1450 1451 $converter_class_name = $options['class_prefix'].AkInflector::camelize($options['from']).'To'.AkInflector::camelize($options['to']); 1452 if(!class_exists($converter_class_name)){ 1453 $file_name = $options['path'].DS.$converter_class_name.'.php'; 1454 if(!file_exists($file_name)){ 1455 if(defined('AK_REMOTE_CONVERTER_URI')){ 1456 require_once (AK_LIB_DIR.DS.'AkConverters'.DS.'AkRemoteConverter.php'); 1457 $result = AkRemoteConverter::convert($options['from'], $options['to'], $options['source']); 1458 if($result !== false){ 1459 return $result; 1460 } 1461 } 1462 trigger_error(Ak::t('Could not locate %from to %to converter on %file_name',array('%from'=>$options['from'],'%to'=>$options['to'],'%file_name'=>$file_name)),E_USER_NOTICE); 1463 return false; 1464 } 1465 require_once($file_name); 1466 } 1467 if(!class_exists($converter_class_name)){ 1468 trigger_error(Ak::t('Could not load %converter_class_name converter class',array('%converter_class_name'=>$converter_class_name)),E_USER_NOTICE); 1469 return false; 1470 } 1471 1472 $converter = new $converter_class_name($options); 1473 foreach ($options as $option=>$value){ 1474 $option[0] != '_' ? $converter->$option = $value : null; 1475 } 1476 1477 if(method_exists($converter, 'init')){ 1478 $converter->init(); 1479 } 1480 return $converter->convert(); 1481 } 1482 1483 1484 /** 1485 * Converts given string to UTF-8 1486 * 1487 * @param string $text 1488 * @param string $input_string_encoding 1489 * @return string UTF-8 encoded string 1490 */ 1491 function utf8($text, $input_string_encoding = null) 1492 { 1493 $input_string_encoding = empty($input_string_encoding) ? Ak::encoding() : $input_string_encoding; 1494 require_once (AK_LIB_DIR.DS.'AkCharset.php'); 1495 $Charset =& Ak::singleton('AkCharset',$text); 1496 return $Charset->RecodeString($text,'UTF-8',$input_string_encoding); 1497 } 1498 1499 function recode($text, $output_string_encoding = null, $input_string_encoding = null, $recoding_engine = null) 1500 { 1501 $input_string_encoding = empty($input_string_encoding) ? Ak::encoding() : $input_string_encoding; 1502 require_once (AK_LIB_DIR.DS.'AkCharset.php'); 1503 $Charset =& Ak::singleton('AkCharset',$text); 1504 return $Charset->RecodeString($text,$output_string_encoding,$input_string_encoding, $recoding_engine); 1505 } 1506 1507 function encoding() 1508 { 1509 static $encoding; 1510 if(empty($encoding)){ 1511 // This will force system language settings 1512 Ak::t('Akelos'); 1513 $encoding = Ak::locale('charset', Ak::lang()); 1514 $encoding = empty($encoding) ? 'UTF-8' : $encoding; 1515 } 1516 return $encoding; 1517 } 1518 1519 /** 1520 * Get the encoding in which current user is sending the request 1521 */ 1522 function userEncoding() 1523 { 1524 static $encoding; 1525 1526 if(!isset($encoding)){ 1527 $encoding = Ak::encoding(); 1528 if(!empty($_SERVER['HTTP_ACCEPT_CHARSET'])){ 1529 $accepted_charsets = array_map('strtoupper', array_diff(explode(';',str_replace(',',';',$_SERVER['HTTP_ACCEPT_CHARSET']).';'), array(''))); 1530 if(!in_array($encoding,$accepted_charsets)){ 1531 $encoding = array_shift($accepted_charsets); 1532 } 1533 } 1534 } 1535 return $encoding; 1536 } 1537 1538 /** 1539 * strlen for UTF-8 strings 1540 * Taken from anpaza at mail dot ru post at http://php.net/strlen 1541 */ 1542 function strlen_utf8($str) 1543 { 1544 $i = $count = 0; 1545 $len = strlen ($str); 1546 while ($i < $len){ 1547 $chr = ord ($str[$i]); 1548 $count++; 1549 $i++; 1550 if ($i >= $len){ 1551 break; 1552 } 1553 if ($chr & 0x80){ 1554 $chr <<= 1; 1555 while ($chr & 0x80){ 1556 $i++; 1557 $chr <<= 1; 1558 } 1559 } 1560 } 1561 return $count; 1562 } 1563 1564 /** 1565 * Convert an arbitrary PHP value into a JSON representation string. 1566 * 1567 * For AJAX driven pages, JSON can come in handy – you can return send JavaScript objects 1568 * directly from your actions. 1569 */ 1570 function toJson($php_value) 1571 { 1572 require_once(AK_VENDOR_DIR.DS.'pear'.DS.'Services'.DS.'JSON.php'); 1573 $use = 0; 1574 $json =& Ak::singleton('Services_JSON', $use); 1575 return $json->encode($php_value); 1576 } 1577 1578 /** 1579 * Converts a JSON representation string into a PHP value. 1580 */ 1581 function fromJson($json_string) 1582 { 1583 require_once(AK_VENDOR_DIR.DS.'pear'.DS.'Services'.DS.'JSON.php'); 1584 $use = 0; 1585 $json =& Ak::singleton('Services_JSON', $use); 1586 return $json->decode($json_string); 1587 } 1588 1589 function &memory_cache($key, &$value) 1590 { 1591 static $memory, $md5; 1592 if($value === false){ 1593 // remove the object from cache 1594 $memory[$key] = null; 1595 $md5[$key] = null; 1596 }elseif($value === true){ 1597 //check if the object is on cache or unaltered 1598 $result = !empty($memory[$key]) ? $md5[$key] == Ak::getStatusKey($memory[$key]) : false; 1599 return $result; 1600 }elseif ($value === null){ 1601 //get the object 1602 return $memory[$key]; 1603 }else{ 1604 //set the object 1605 $md5[$key] = Ak::getStatusKey($value); 1606 $memory[$key] =& $value; 1607 } 1608 1609 return $value; 1610 } 1611 1612 function getStatusKey($element) 1613 { 1614 if(AK_PHP5){ 1615 $element = clone($element); 1616 } 1617 if(isset($element->___status_key)){ 1618 unset($element->___status_key); 1619 } 1620 return md5(serialize($element)); 1621 } 1622 1623 function logObjectForModifications(&$object) 1624 { 1625 $object->___status_key = empty($object->___status_key) ? Ak::getStatusKey($object) : $object->___status_key; 1626 return $object->___status_key; 1627 } 1628 1629 function resetObjectModificationsWacther(&$object) 1630 { 1631 unset($object->___status_key); 1632 } 1633 1634 function objectHasBeenModified(&$object) 1635 { 1636 if(isset($object->___status_key)){ 1637 $old_status = $object->___status_key; 1638 $new_key = Ak::getStatusKey($object); 1639 return $old_status != $new_key; 1640 }else{ 1641 Ak::logObjectForModifications($object); 1642 return false; 1643 } 1644 return true; 1645 } 1646 1647 function &call_user_func_array($function_name, $parameters) 1648 { 1649 if(AK_PHP5){ 1650 $result = call_user_func_array($function_name, $parameters); 1651 return $result; 1652 } 1653 $user_function_name = is_string($function_name) ? $function_name : (is_object($function_name[0]) ? '$function_name[0]->'.$function_name[1] : $function_name[0].'::'.$function_name[1]); 1654 $arguments = array(); 1655 $argument_keys = array_keys($parameters); 1656 foreach($argument_keys as $k){ 1657 $arguments[] = '$parameters['.$argument_keys[$k].']'; 1658 } 1659 eval('$_result =& '.$user_function_name.'('.implode($arguments, ', ').');'); 1660 // Dirty hack for avoiding pass by reference warnings. 1661 $result =& $_result; 1662 return $result; 1663 } 1664 1665 1666 function &array_sort_by($array, $key = null, $direction = 'asc') 1667 { 1668 $array_copy = $sorted_array = array(); 1669 foreach (array_keys($array) as $k) { 1670 $array_copy[$k] =& $array[$k][$key]; 1671 } 1672 1673 natcasesort($array_copy); 1674 if(strtolower($direction) == 'desc'){ 1675 $array_copy = array_reverse($array_copy, true); 1676 } 1677 1678 foreach (array_keys($array_copy) as $k){ 1679 $sorted_array[$k] =& $array[$k]; 1680 } 1681 1682 return $sorted_array; 1683 } 1684 1685 function mime_content_type($file) 1686 { 1687 static $mime_types; 1688 ak_compat('mime_content_type'); 1689 empty($mime_types) ? require (AK_LIB_DIR.DS.'utils'.DS.'mime_types.php') : null; 1690 $file_extension = substr($file,strrpos($file,'.')+1); 1691 return !empty($mime_types[$file_extension]) ? $mime_types[$file_extension] : false; 1692 } 1693 1694 function stream($path, $buffer_size = 4096) 1695 { 1696 ob_implicit_flush(); 1697 $len = empty($buffer_size) ? 4096 : $buffer_size; 1698 $fp = fopen($path, "rb"); 1699 while (!feof($fp)) { 1700 echo fread($fp, $len); 1701 } 1702 } 1703 1704 function _nextPermutation($p, $size) 1705 { 1706 for ($i = $size - 1; isset($p[$i]) && isset($p[$i+1]) && $p[$i] >= $p[$i+1]; --$i) { } 1707 if ($i == -1) { return false; } 1708 for ($j = $size; $p[$j] <= $p[$i]; --$j) { } 1709 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp; 1710 for (++$i, $j = $size; $i < $j; ++$i, --$j) { 1711 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp; 1712 } 1713 return $p; 1714 } 1715 1716 /** 1717 * Returns all the possible permutations of given array 1718 */ 1719 function permute($array, $join_with = false) 1720 { 1721 $size = count($array) - 1; 1722 $perm = range(0, $size); 1723 $j = 0; 1724 do { 1725 foreach ($perm as $i) { 1726 $perms[$j][] = $array[$i]; 1727 } 1728 } while ($perm = Ak::_nextPermutation($perm, $size) AND ++$j); 1729 1730 if($join_with){ 1731 foreach ($perms as $perm){ 1732 $joined_perm[] = join(' ',$perm); 1733 } 1734 return $joined_perm; 1735 } 1736 return $perms; 1737 } 1738 1739 /** 1740 * Generates a Universally Unique IDentifier, version 4. 1741 * 1742 * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally 1743 * Unique IDentifiers (GUID), as well as several methods for producing them. One 1744 * such method, described in section 4.4, is based on truly random or pseudo-random 1745 * number generators, and is therefore implementable in a language like PHP. 1746 * 1747 * We choose to produce pseudo-random numbers with the Mersenne Twister, and to always 1748 * limit single generated numbers to 16 bits (ie. the decimal value 65535). That is 1749 * because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed* 1750 * value, with only the equivalent of 31 significant bits. Producing two 16-bit random 1751 * numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits 1752 * are random. 1753 * 1754 * The algorithm for version 4 UUIDs (ie. those based on random number generators) 1755 * states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits, 1756 * 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should 1757 * be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should 1758 * be 01. We try to conform to that definition as efficiently as possible, generating 1759 * smaller values where possible, and minimizing the number of base conversions. 1760 * 1761 * @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for 1762 * any purpose ; it is distributed without any form of warranty whatsoever. 1763 * @author David Holmes <dholmes@cfdsoftware.net> 1764 * 1765 * @return string A UUID, made up of 32 hex digits and 4 hyphens. 1766 */ 1767 function uuid() 1768 { 1769 1770 // The field names refer to RFC 4122 section 4.1.2 1771 return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x', 1772 mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low" 1773 mt_rand(0, 65535), // 16 bits for "time_mid" 1774 mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version" 1775 bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)), 1776 // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res" 1777 // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d) 1778 // 8 bits for "clk_seq_low" 1779 mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node" 1780 ); 1781 } 1782 1783 1784 function test($test_case_name, $use_sessions = false) 1785 { 1786 ak_test($test_case_name, $use_sessions); 1787 } 1788 1789 /** 1790 * Use this function for securing includes. This way you can prevent file inclusion attacks 1791 */ 1792 function sanitize_include($include, $mode = 'normal') 1793 { 1794 $rules = array( 1795 'paranoid' => '/([^A-Z^a-z^0-9^_^-^ ]+)/', 1796 'high' => '/([^A-Z^a-z^0-9^_^-^ ^\/^\\\^:]+)/', 1797 'normal' => '/([^A-Z^a-z^0-9^_^-^ ^\.^\/^\\\]+)/' 1798 ); 1799 $mode = array_key_exists($mode,$rules) ? $mode : 'normal'; 1800 return preg_replace($rules[$mode],'',$include); 1801 } 1802 1803 /** 1804 * Returns a PHP Object from an API resource 1805 * 1806 */ 1807 function client_api($resource, $options = array()) 1808 { 1809 $default_options = array( 1810 'protocol' => 'xml_rpc', 1811 'build' => true 1812 ); 1813 $options = array_merge($default_options, $options); 1814 1815 require (AK_LIB_DIR.DS.'AkActionWebService'.DS.'AkActionWebServiceClient.php'); 1816 $Client =& new AkActionWebServiceClient($options['protocol']); 1817 $Client->init($resource, $options); 1818 return $Client; 1819 } 1820 1821 1822 /** 1823 * Cross PHP version replacement for html_entity_decode. Emulates PHP5 behaviour on PHP4 on UTF-8 entities 1824 */ 1825 function html_entity_decode($html, $translation_table_or_quote_style = null) 1826 { 1827 if(AK_PHP5){ 1828 return html_entity_decode($html,empty($translation_table_or_quote_style) ? ENT_QUOTES : $translation_table_or_quote_style,'UTF-8'); 1829 } 1830 require_once (AK_LIB_DIR.DS.'AkCharset.php'); 1831 $html = preg_replace('~&#x([0-9a-f]+);~ei', 'AkCharset::_CharToUtf8(hexdec("\\1"))', $html); 1832 $html = preg_replace('~&#([0-9]+);~e', 'AkCharset::_CharToUtf8("\\1")', $html); 1833 if(empty($translation_table_or_quote_style)){ 1834 $translation_table_or_quote_style = get_html_translation_table(HTML_ENTITIES); 1835 $translation_table_or_quote_style = array_flip($translation_table_or_quote_style); 1836 } 1837 return strtr($html, $translation_table_or_quote_style); 1838 } 1839 1840 /** 1841 * Loads the plugins found at app/vendor/plugins 1842 */ 1843 function &loadPlugins() 1844 { 1845 require_once (AK_LIB_DIR.DS.'AkPlugin.php'); 1846 $PluginManager =& new AkPluginLoader(); 1847 $PluginManager->loadPlugins(); 1848 return $PluginManager; 1849 } 1850 1851 function setStaticVar($name,&$value) 1852 { 1853 $refhack =& Ak::_staticVar($name,$value); 1854 return $refhack; 1855 } 1856 1857 /** 1858 * Strategy for unifying in-function static vars used mainly for performance improvements framework-wide. 1859 * 1860 * Before we had 1861 * 1862 * class A{ 1863 * function b($var){ 1864 * static $chache; 1865 * if(!isset($cache[$var])){ 1866 * $cache[$var] = some_heavy_function($var); 1867 * } 1868 * return $cache[$var]; 1869 * } 1870 * } 1871 * 1872 * Now imagine we want to create an application server which handles multiple requests on a single instantiation, with the showcased implementation this is not possible as we can't reset $cache, unless we hack badly every single method that uses this strategy. 1873 * 1874 * We can refresh this static values the new Ak::getStaticVar method. So from previous example we will have to replace 1875 * 1876 * static $chache; 1877 */ 1878 function &getStaticVar($name) 1879 { 1880 $refhack =& Ak::_staticVar($name,$refhackvar = null); 1881 return $refhack; 1882 } 1883 1884 function &unsetStaticVar($name) 1885 { 1886 $refhack =& Ak::_staticVar($name,$refhackvar = null,true); 1887 return $refhack; 1888 } 1889 1890 function &_staticVar($name, &$value, $destruct = false) 1891 { 1892 static $_memory; 1893 $null = null; 1894 $true = true; 1895 $false = false; 1896 $return = $null; 1897 if ($value === null && $destruct === false) { 1898 /** 1899 * GET mode 1900 */ 1901 if (isset($_memory[$name])) { 1902 $return = &$_memory[$name]; 1903 } 1904 } else if ($value !== null) { 1905 /** 1906 * SET mode 1907 */ 1908 if (is_string($name)) { 1909 $_memory[$name] = &$value; 1910 $return = $true; 1911 } else { 1912 $return = $false; 1913 } 1914 1915 } else if ($destruct === true) { 1916 if ($name !== null) { 1917 $value = isset($_memory[$name])?$_memory[$name]:$null; 1918 if (is_object($value) && method_exists($value,'__destruct')) { 1919 $value->__destruct(); 1920 } 1921 unset($value); 1922 unset($_memory[$name]); 1923 } else { 1924 foreach ($_memory as $name => $value) { 1925 Ak::unsetStaticVar($name); 1926 } 1927 } 1928 } 1929 return $return; 1930 } 1931 1932 /** 1933 * 1934 * @param array $options 1935 * @param array $default_options 1936 * @param array $available_options 1937 * @param boolean $walk_keys 1938 */ 1939 function parseOptions(&$options, $default_options = array(), $parameters = array(), $walk_keys=false) 1940 { 1941 if ($walk_keys) { 1942 foreach ($options as $key=>$value) { 1943 if (!is_array($value)) { 1944 unset($options[$key]); 1945 $options[$value] = $default_options; 1946 } else { 1947 Ak::parseOptions($value, $default_options, $parameters); 1948 $options[$key] = $value; 1949 } 1950 } 1951 return; 1952 } 1953 1954 $options = array_merge($default_options, $options); 1955 foreach($options as $key => $value) { 1956 if(isset($parameters['available_options'])) { 1957 if (!isset($parameters['available_options'][$key])) { 1958 continue; 1959 } 1960 } 1961 $options[$key] = $value; 1962 1963 } 1964 } 1965 1966 /** 1967 * Returns YAML settings from config/$namespace.yml 1968 */ 1969 function getSettings($namespace, $raise_error_if_config_file_not_found = true, $environment = AK_ENVIRONMENT) 1970 { 1971 static $_config; 1972 if (!in_array($environment,Ak::toArray(AK_AVAILABLE_ENVIRONMENTS))) { 1973 trigger_error('The environment '.$environment.' is not allowed. Allowed environments: '.AK_AVAILABLE_ENVIRONMENTS); 1974 return false; 1975 } 1976 if (!isset($_config)) { 1977 require_once (AK_LIB_DIR.DS.'AkConfig.php'); 1978 $_config = new AkConfig(); 1979 } 1980 return $_config->get($namespace,$environment,$raise_error_if_config_file_not_found); 1981 } 1982 1983 function getSetting($namespace, $variable, $default_value = null) 1984 { 1985 if($settings = Ak::getSettings($namespace)){ 1986 return isset($settings[$variable]) ? $settings[$variable] : $default_value; 1987 } 1988 return $default_value; 1989 } 1990 1991 function _parseSettingsConstants($settingsStr) 1992 { 1993 return preg_replace_callback('/\$\{(AK_.*?)\}/',array('Ak','_getConstant'),$settingsStr); 1994 } 1995 1996 function _getConstant($name) 1997 { 1998 return defined($name[1])?constant($name[1]):''; 1999 } 2000 } 2001 2002 Ak::profile('Ak.php class included'.__FILE__); 2003 2004 ?>