2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
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 // +----------------------------------------------------------------------+
12 * @package ActiveSupport
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>
23 define('AK_LOG_NOTICE', 0);
24 define('AK_LOG_WARNING', 1);
25 define('AK_LOG_ERROR', 2);
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);
33 * Akelos Framework static functions
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
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>
48 * Gets an instance of AdoDb database connection
50 * Whenever a database connection is required you can get a
51 * reference to the default database connection by doing:
53 * $db =& Ak:db(); // get an adodb instance
55 * AdoDB manual can be found at http://phplens.com/adodb/
58 * @param string $dns A string containing Data Source Name (information
59 * regarding database connection)
60 * http://phplens.com/adodb/code.initialization.html#dsnsupport
62 * @return resource Php AdoDb instance.
64 function &db($dsn = null, $connection_id = null)
66 static $db, $default_connection_id;
68 // In order to retrieve a database connection we just need to provide its identifier
69 if(empty($default_connection_id)){
70 $default_connection_id = md5($dsn);
72 $connection_id = empty($connection_id) ?
$default_connection_id : $connection_id;
74 if(empty($db[$connection_id])){
75 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb.inc.php');
77 if(substr($dsn, 0, 6) == 'mysql:'){
78 $dsn = substr_replace($dsn, 'mysqlt:', 0, 6);
81 if (!$db[$connection_id] = (AK_DEBUG ?
NewADOConnection($dsn) : @NewADOConnection
($dsn))){
82 error_reporting(E_ALL
);
83 if(defined('AK_DATABASE_CONNECTION_FAILURE_CALLBACK') && function_exists(AK_DATABASE_CONNECTION_FAILURE_CALLBACK
)){
84 $fn = AK_DATABASE_CONNECTION_FAILURE_CALLBACK
;
87 if(!AK_PHP5
&& substr($dsn,0,6) == 'sqlite'){
88 echo "\nWarning, sqlite support is not available by default on PHP4.\n Check your PHP version by running \"env php -v\", and change the first line in your scripts/ so they point to a php5 binary\n\n";
90 die(Ak
::t('Connection to the database failed.').' '.
91 (AK_DEBUG?
preg_replace('/\/\/(\w+):(.*)@/i','//$1:******@', urldecode($dsn))."\n":''));
93 $db[$connection_id]->debug
= AK_DEBUG
== 2;
94 defined('AK_DATABASE_CONNECTION_AVAILABLE') ?
null : define('AK_DATABASE_CONNECTION_AVAILABLE', true);
97 return $db[$connection_id];
103 * Gets a cache object singleton instance
109 require_once(AK_LIB_DIR
.DS
.'AkCache.php');
110 $cache = new AkCache();
116 function toUrl($options, $set_routes = false)
124 require_once(AK_LIB_DIR
.DS
.'AkRouter.php');
125 $Map = new AkRouter();
126 if(is_file(AK_ROUTES_MAPPING_FILE
)){
127 include(AK_ROUTES_MAPPING_FILE
);
131 return $Map->toUrl($options);
136 * Translate strings to the current locale.
138 * When using Ak::t(), try to put entire sentences and strings
139 * in one Ak::t() call.
140 * This makes it easier for translators. HTML markup within
141 * translation strings
142 * is acceptable, if necessary. The suggested syntax for a
144 * within a translation string is:
148 * @param string $string A string containing the English string to
150 * @param array $args An associative array of replacements to make after
151 * translation. Incidences of any key in this array
152 * are replaced with the corresponding value.
153 * @return string The translated string.
155 function t($string, $args = null, $controller = null)
157 static $framework_dictionary = array(), $lang, $_dev_shutdown = true;
159 if(AK_AUTOMATICALLY_UPDATE_LANGUAGE_FILES
&& !empty($string) && is_string($string)){
160 require_once(AK_LIB_DIR
.DS
.'AkLocaleManager.php');
161 // This adds used strings to a stack for storing new entries on the locale file after shutdown
162 AkLocaleManager
::getUsedLanguageEntries($string, $controller);
164 register_shutdown_function(array('AkLocaleManager','updateLocaleFiles'));
165 $_dev_shutdown = false;
170 if(!empty($_SESSION['lang'])){
171 $lang = $_SESSION['lang'];
175 if(is_file(AK_CONFIG_DIR
.DS
.'locales'.DS
.$lang.'.php')){
176 require(AK_CONFIG_DIR
.DS
.'locales'.DS
.$lang.'.php');
177 $framework_dictionary = array_merge($framework_dictionary,$dictionary);
179 if(!defined('AK_LOCALE')){
180 define('AK_LOCALE', $lang);
182 if(!empty($locale) && is_array($locale)){
183 Ak
::locale(null, $lang, $locale);
187 if(!empty($string) && is_array($string)){
188 if(!empty($string[$lang])){
189 return $string[$lang];
191 $try_whith_lang = $args !== false && empty($string[$lang]) ? Ak
::base_lang() : $lang;
192 if(empty($string[$try_whith_lang]) && $args !== false){
193 foreach (Ak
::langs() as $try_whith_lang){
194 if(!empty($string[$try_whith_lang])){
195 return $string[$try_whith_lang];
199 return @$string[$try_whith_lang];
202 if(isset($controller) && !isset($framework_dictionary[$controller.'_dictionary']) && is_file(AK_APP_DIR
.DS
.'locales'.DS
.$controller.DS
.$lang.'.php')){
203 require(AK_APP_DIR
.DS
.'locales'.DS
.$controller.DS
.$lang.'.php');
204 $framework_dictionary[$controller.'_dictionary'] = (array)$dictionary;
207 if(isset($controller) && isset($framework_dictionary[$controller.'_dictionary'][$string])){
208 $string = $framework_dictionary[$controller.'_dictionary'][$string];
210 $string = isset($framework_dictionary[$string]) ?
$framework_dictionary[$string] : $string;
213 if(isset($args) && is_array($args)){
214 $string = @str_replace
(array_keys($args), array_values($args),$string);
218 * @todo Prepare for multiple locales by inspecting AK_DEFAULT_LOCALE
227 * Gets information about current locale from the locale settings on config/locales/LOCALE.php
229 * This are common settings on the locale file:
230 * 'description' // Locale description Example. Spanish
231 * 'charset' // 'ISO-8859-1';
232 * 'date_time_format' // '%d/%m/%Y %H:%i:%s';
233 * 'date_format' // '%d/%m/%Y';
234 * 'long_date_format' // '%d/%m/%Y';
235 * 'time_format' // '%H:%i';
236 * 'long_time_format' // '%H:%i:%s';
238 function locale($locale_setting, $locale = null)
242 // We initiate the locale settings
245 $locale = empty($locale) ?
(defined('AK_LOCALE') ? AK_LOCALE
: (Ak
::t('Akelos') && Ak
::locale($locale_setting))) : $locale;
247 if (empty($settings[$locale])) {
248 if(func_num_args() != 3){ // First time we ask for something using this locale so we will load locale details
249 $requested_locale = $locale;
250 if(@include
(AK_CONFIG_DIR
.DS
.'locales'.DS
.Ak
::sanitize_include($requested_locale).'.php')){
251 $locale = !empty($locale) && is_array($locale) ?
$locale : array();
252 Ak
::locale(null, $requested_locale, $locale);
253 return Ak
::locale($locale_setting, $requested_locale);
256 $settings[$locale] = func_get_arg(2);
257 if(isset($settings[$locale]['charset'])){
258 defined('AK_CHARSET') ?
null : (define('AK_CHARSET',$settings[$locale]['charset']) && @ini_set
('default_charset', AK_CHARSET
));
263 return isset($settings[$locale][$locale_setting]) ?
$settings[$locale][$locale_setting] : false;
267 function lang($set_language = null)
270 $lang = empty($set_language) ?
(empty($lang) ? AK_FRAMEWORK_LANGUAGE
: $lang) : $set_language;
275 function get_url_locale($set_locale = null)
281 $locale = empty($set_locale) ?
'' : $set_locale;
294 if(defined('AK_APP_LOCALES')){
295 $langs = array_diff(explode(',',AK_APP_LOCALES
.','),array(''));
297 $langs = empty($langs) ?
array($lang) : $langs;
303 return array_shift(Ak
::langs());
308 function dir($path, $options = array())
312 $path = rtrim($path, '/\\');
313 $default_options = array(
319 $options = array_merge($default_options, $options);
322 $result = array($path);
323 }elseif(is_dir($path)){
324 if ($id_dir = opendir($path)){
325 while (false !== ($file = readdir($id_dir))){
326 if ($file != "." && $file != ".." && $file != '.svn'){
327 if(!empty($options['files']) && !is_dir($path.DS
.$file)){
329 }elseif(!empty($options['dirs'])){
330 $result[][$file] = !empty($options['recurse']) ? Ak
::dir($path.DS
.$file, $options) : $file;
338 return array_reverse($result);
342 function file_put_contents($file_name, $content, $options = array())
345 $default_options = array(
346 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
347 'base_path' => AK_BASE_DIR
,
349 $options = array_merge($default_options, $options);
351 if(!function_exists('file_put_contents')){
352 include_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'PHP'.DS
.'Compat.php');
353 PHP_Compat
::loadFunction(array('file_put_contents'));
356 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
359 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
360 $file_name = trim(str_replace(array(DS
,'//'),array('/','/'),$file_name),'/');
361 if(!AkFtp
::is_dir(dirname($file_name))){
362 AkFtp
::make_dir(dirname($file_name));
365 return AkFtp
::put_contents($file_name, $content);
367 if(!is_dir(dirname($options['base_path'].DS
.$file_name))){
368 Ak
::make_dir(dirname($options['base_path'].DS
.$file_name), $options);
371 if(!$result = file_put_contents($options['base_path'].DS
.$file_name, $content)){
372 if(!empty($content)){
373 Ak
::trace("Please change file/dir permissions or enable FTP file handling by".
374 " setting the following on your config/".AK_ENVIRONMENT
.".php file \n<pre>define('AK_UPLOAD_FILES_USING_FTP', true);\n".
375 "define('AK_READ_FILES_USING_FTP', false);\n".
376 "define('AK_DELETE_FILES_USING_FTP', true);\n".
377 "define('AK_FTP_PATH', 'ftp://username:password@example.com/path_to_the_framework');\n".
378 "define('AK_FTP_AUTO_DISCONNECT', true);\n</pre>");
386 function file_get_contents($file_name, $options = array())
388 $default_options = array(
389 'ftp' => defined('AK_READ_FILES_USING_FTP') && AK_READ_FILES_USING_FTP
,
390 'base_path' => AK_BASE_DIR
,
392 $options = array_merge($default_options, $options);
394 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
396 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
397 $file_name = trim(str_replace(array(DS
,'//'),array('/','/'),$file_name),'/');
398 return AkFtp
::get_contents($file_name);
400 return file_get_contents($options['base_path'].DS
.$file_name);
405 * @todo Optimize this code (dirty add-on to log command line interpreter results)
407 function file_add_contents($file_name, $content, $options = array())
409 $original_content = @Ak
::file_get_contents($file_name, $options);
410 return Ak
::file_put_contents($file_name, $original_content.$content, $options);
413 function file_delete($file_name, $options = array())
415 $default_options = array(
416 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP
,
417 'base_path' => AK_BASE_DIR
,
419 $options = array_merge($default_options, $options);
421 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
423 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
424 $file_name = trim(str_replace(array(DS
,'//'),array('/','/'),$file_name),'/');
425 return AkFtp
::delete($file_name, true);
427 return unlink($options['base_path'].DS
.$file_name);
431 function directory_delete($dir_name, $options = array())
433 $default_options = array(
434 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP
,
435 'base_path' => AK_BASE_DIR
,
437 $options = array_merge($default_options, $options);
440 $dir_name = Ak
::_getRestrictedPath($dir_name, $options);
442 if(empty($dir_name)){
447 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
448 return AkFtp
::delete($dir_name);
450 $items = glob($options['base_path'].DS
.$dir_name."/*");
451 $hidden_items = glob($options['base_path'].DS
.$dir_name."/.*");
452 $fs_items = $items ||
$hidden_items ?
array_merge((array)$items, (array)$hidden_items) : false;
454 $items_to_delete = array('directories'=>array(), 'files'=>array());
455 foreach($fs_items as $fs_item) {
456 if($fs_item[strlen($fs_item)-1] != '.'){
457 $items_to_delete[ (is_dir($fs_item) ?
'directories' : 'files') ][] = $fs_item;
460 foreach ($items_to_delete['files'] as $file){
461 Ak
::file_delete($file, $options);
463 foreach ($items_to_delete['directories'] as $directory){
464 $sucess = $sucess ? Ak
::directory_delete($directory, $options) : $sucess;
467 return $sucess ?
rmdir($options['base_path'].DS
.$dir_name) : $sucess;
471 function make_dir($path, $options = array())
473 $default_options = array(
474 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
475 'base_path' => AK_BASE_DIR
477 $options = array_merge($default_options, $options);
479 $path = trim(str_replace($options['base_path'], '',$path),DS
);
481 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
482 $path = trim(str_replace(array(DS
,'//'),array('/','/'),$path),'/');
483 return AkFtp
::make_dir($path);
485 $path = $options['base_path'].DS
.$path;
486 if (!file_exists($path)){
487 Ak
::make_dir(dirname($path), $options);
495 * This static method will copy recursively all the files or directories from one
496 * path within an Akelos application to another.
498 * It uses current installation settings, so it can perform copies via the filesystem or via FTP
500 function copy($origin, $target, $options = array())
502 $default_options = array(
503 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
504 'base_path' => AK_BASE_DIR
,
506 $options = array_merge($default_options, $options);
510 $origin = Ak
::_getRestrictedPath($origin, $options);
511 $target = Ak
::_getRestrictedPath($target, $options);
513 if(empty($origin) ||
empty($target)){
518 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
520 $destination = str_replace($origin, $target, $origin);
521 if(is_file($options['base_path'].DS
.$origin)){
522 return Ak
::file_put_contents($options['base_path'].DS
.$destination, Ak
::file_get_contents($options['base_path'].DS
.$origin, $options), $options);
524 Ak
::make_dir($options['base_path'].DS
.$destination);
525 if($fs_items = glob($options['base_path'].DS
.$origin."/*")){
526 $items_to_copy = array('directories'=>array(), 'files'=>array());
527 foreach($fs_items as $fs_item) {
528 $items_to_copy[ (is_dir($fs_item) ?
'directories' : 'files') ][] = $fs_item;
530 foreach ($items_to_copy['files'] as $file){
531 $destination = str_replace($origin, $target, $file);
532 $sucess = $sucess ? Ak
::file_put_contents($destination, Ak
::file_get_contents($file, $options), $options) : $sucess;
534 foreach ($items_to_copy['directories'] as $directory){
535 $destination = str_replace($origin, $target, $directory);
536 $sucess = $sucess ? Ak
::copy($directory, $destination, $options) : $sucess;
543 * Returns a path restricting it to a base location
545 * This is used by Akelos to prevent functions namespaced under Ak
546 * from writing out of the Akelos base directory for security reasons.
548 function _getRestrictedPath($path, $options = array())
550 $default_options = array(
552 'base_path' => AK_BASE_DIR
,
554 $options = array_merge($default_options, $options);
556 $path = str_replace('..','', rtrim($path,'\\/. '));
557 $path = trim(str_replace($options['base_path'], '',$path),DS
);
560 $path = trim(str_replace(array(DS
,'//'),array('/','/'), $path),'/');
568 * Perform a web request using curl
570 * @param string $url URL we are going to request.
571 * @param array $options Options for current request.
573 * * referer: URL that will be set as referer url. Default is current url
574 * * params: Parameter for the request. Can be an array of key=>values or a url params string like key=value&key2=value2
575 * * method: In case params are given the will be requested using post method by default. Specify get if post is not what you need.
576 * * browser_name: How are we going to be presented to the website. Default is 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
579 function url_get_contents($url, $options = array())
581 ak_compat('http_build_query');
583 $default_options = array(
588 'browser_name' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
591 $options = array_merge($default_options, $options);
593 $options['params'] = !empty($options['params']) ?
(is_array($options['params']) ?
http_build_query(array_map('urlencode', $options['params'])) : $options['params']) : '';
594 $options['method'] = strtolower($options['method']) == 'post' ?
'post' : 'get';
598 curl_setopt($ch, CURLOPT_URL
, $url);
599 curl_setopt($ch, CURLOPT_FOLLOWLOCATION
, 1);
600 curl_setopt($ch, CURLOPT_USERAGENT
, $options['browser_name']);
601 curl_setopt($ch, CURLOPT_HEADER
, 0);
603 if(!empty($options['params']) && $options['method'] == 'post'){
604 curl_setopt($ch, CURLOPT_POST
, 1);
605 curl_setopt($ch, CURLOPT_POSTFIELDS
, $options['params']);
606 }elseif(!empty($options['params'])){
607 $url = trim($url,'?').'?'.trim($options['params'], '?');
610 curl_setopt ($ch, CURLOPT_REFERER
, $options['referer']);
612 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, 1);
613 curl_setopt($ch, CURLOPT_TIMEOUT
, $options['timeout']);
615 $result = curl_exec ($ch);
623 * Trace helper function for development purposes
627 * @param string $text Helper text
628 * @param string $line Helper line
629 * @param string $file Helper file
630 * @return echoes result to screen
632 function trace($text = null, $line = null, $file = null)
639 $line = isset($line) ?
"Line: $line".(AK_CLI?
"\n":"<br />") : "";
640 $file = isset($file) ?
"File: $file".(AK_CLI?
"\n":"<br />") : "";
646 $text = AK_CLI?
'---> '.$text:'<b>---></b>'.$text;
649 echo AK_CLI?
"----------------\n$line $file $text\n----------------\n":"<hr /><div>$line $file $text</div><hr />\n";
657 * Outputs debug info given a PHP resource (vars, objects,
662 * @param mixed $data Data to debug. It can be an object, array,
664 * @return void Prints debug info.
666 function debug ($data, $_functions=0)
668 if(!AK_DEBUG
&& !AK_DEV_MODE
){
677 if(is_object($data) && method_exists($data, 'debug')){
679 "\n------------------------------------\nEntering on ".get_class($data)." debug() method\n\n":
680 "<hr /><h2>Entering on ".get_class($data)." debug() method</h2>";
681 if(!empty($data->__activeRecordObject
)){
682 $data->toString(true);
688 if (is_array($data) ||
is_object($data)) {
691 echo AK_CLI ?
"/--\n" : "<ol>\n";
692 while (list ($key,$value) = each ($data)) {
693 $type=gettype($value);
694 if ($type=="array" ||
$type == "object") {
696 Ak
::debug ($value,$sf);
697 $lines = explode("\n",ob_get_clean()."\n");
698 foreach ($lines as $line){
699 echo "\t".$line."\n";
701 } elseif (eregi ("function", $type)) {
703 AK_CLI ?
printf ("\t* (%s) %s:\n",$type, $key, $value) :
704 printf ("<li>(%s) <b>%s</b> </li>\n",$type, $key, $value);
710 AK_CLI ?
printf ("\t* (%s) %s = %s\n",$type, $key, $value) :
711 printf ("<li>(%s) <b>%s</b> = %s</li>\n",$type, $key, $value);
714 echo AK_CLI ?
"\n--/\n" : "</ol>fin.\n";
727 * Gets information about given object
731 * @uses Ak::get_this_object_methods
732 * @uses Ak::get_this_object_attributes
733 * @param object &$object Object to get info from
734 * @param boolean $include_inherited_info By setting this to true, parent Object properties
735 * and methods will be included.
736 * @return string html output with Object info
738 function get_object_info($object, $include_inherited_info = false)
740 $object_name = get_class($object);
741 $methods = $include_inherited_info ?
get_class_methods($object) : Ak
::get_this_object_methods($object);
742 $vars = $include_inherited_info ?
get_class_vars($object_name) : Ak
::get_this_object_attributes($object);
746 foreach ($vars as $varname=>$var_value){
747 $var_desc .= "<li>$varname = $var_value (". gettype($var_value) .")</li>\n";
749 $var_desc .= "</ul>";
751 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) .'();'));
758 * Gets selected object methods.
760 * WARNING: Inherited methods are not returned by this
761 * function. You can fetch them by using PHP native function
766 * @see get_this_object_attributes
767 * @see get_object_info
768 * @param object &$object Object to inspect
769 * @return array Returns an array with selected object methods. It
770 * does not return inherited methods
772 function get_this_object_methods($object)
774 $array1 = get_class_methods($object);
775 if($parent_object = get_parent_class($object)){
776 $array2 = get_class_methods($parent_object);
777 $array3 = array_diff($array1, $array2);
781 return array_values((array)$array3);
788 * Get selected objects default attributes
790 * WARNING: Inherited attributes are not returned by this
791 * function. You can fetch them by using PHP native function
796 * @see get_this_object_methods
797 * @see get_object_info
798 * @param object &$object Object to inspect
799 * @return void Returns an array with selected object attributes.
800 * It does not return inherited attributes
802 function get_this_object_attributes($object)
804 $object = get_class($object);
805 $array1 = get_class_vars($object);
806 if($parent_object = get_parent_class($object)){
807 $array2 = get_class_vars($parent_object);
808 $array3 = array_diff_assoc($array1, $array2);
812 return (array)$array3;
817 function &getLogger()
821 require_once(AK_LIB_DIR
.DS
.'AkLogger.php');
822 $Logger =& new AkLogger();
828 function get_constants()
830 $constants = get_defined_constants();
831 $keys = array_keys($constants);
832 foreach ($keys as $k){
833 if(substr($k,0,3) != 'AK_'){
834 unset($constants[$k]);
842 * @todo Use timezone time
846 return time()+
(defined('AK_TIME_DIFERENCE') ? AK_TIME_DIFERENCE
*3600 : 0);
851 return Ak
::time()+
(AK_TIME_DIFERENCE_FROM_GMT
*3600);
856 * Gets a timestamp for input date provided in one of this formats: "year-month-day hour:min:sec", "year-month-day", "hour:min:sec"
858 function getTimestamp($iso_date_or_hour = null)
860 if(empty($iso_date_or_hour)){
864 ([0-9]{4})[-\/\.]? # year
865 ([0-9]{1,2})[-\/\.]? # month
866 ([0-9]{1,2})[ -]? # day
868 ([0-9]{1,2}):? # hour
869 ([0-9]{2}):? # minute
870 ([0-9\.]{0,4}) # seconds
871 )?/x", ($iso_date_or_hour), $rr)){
872 if (preg_match("|^(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($iso_date_or_hour), $rr)){
873 return empty($rr[0]) ? Ak
::time() : mktime($rr[2],$rr[3],$rr[4]);
876 if($rr[1]>=2038 ||
$rr[1]<=1970){
877 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb-time.inc.php');
878 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]);
880 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]);
883 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"'));
888 * Return formatted date.
890 * You can supply a format as defined at http://php.net/date
892 * Default date is in ISO format
894 function getDate($timestamp = null, $format = null)
896 $timestamp = !isset($timestamp) ? Ak
::time() : $timestamp;
897 $use_adodb = $timestamp <= -3600 ||
$timestamp >= 2147468400;
899 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb-time.inc.php');
902 return $use_adodb ?
adodb_date('Y-m-d H:i:s', $timestamp) : date('Y-m-d H:i:s', $timestamp);
903 }elseif (!empty($format)){
904 return $use_adodb ?
adodb_date($format, $timestamp) : date($format, $timestamp);
906 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")'));
912 * mail function substitute. Uses the PEAR::Mail() function API.
914 * Messaging subsystem for user communication. See PEAR::Mail() function in PHP
915 * documentation for information.
917 * User must declare any of these variables for specify the outgoing method. Currently,
918 * only Sendmail and STMP methods are available . Variables
919 * for using any of these methods are:
924 * For future upgrades, you must define which constants must be declared and add
927 * NOTE: If messaging method is SMTP, you must declare in config file (/config/config.php)
928 * the outgoing SMTP server and the authentication pair user/password as constants
929 * AK_SMTP_SERVER, AK_SMTP_USER and AK_SMTP_PASSWORD, respectively.
934 * User who sends the mail.
938 * Receiver, or receivers of the mail.
940 * The formatting of this string must comply with RFC 2822. Some examples are:
943 * user@example.com, anotheruser@example.com
944 * User <user@example.com>
945 * User <user@example.com>, Another User <anotheruser@example.com>
949 * Subject of the email to be sent. This must not contain any newline
950 * characters, or the mail may not be sent properly.
954 * Message to be sent.
956 * @param additional_headers (optional)
958 * Array to be inserted at the end of the email header.
960 * This is typically used to add extra headers (Bcc) in an associative array, where the
961 * array key is the header name (i.e., 'Bcc'), and the array value is the header value
962 * (i.e., 'test'). The header produced from those values would be 'Bcc: test'.
964 * @return boolean whether message has been sent or not.
968 function mail ($from, $to, $subject, $body, $additional_headers = array())
970 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Mail.php');
972 static $mail_connector;
974 if(!isset($mail_connector)){
975 if (defined('AK_SENDMAIL')) {
976 // Using Sendmail daemon without parameters.
977 $mail_connector = Mail
::factory('sendmail');
978 } else if (defined('AK_SMTP') && AK_SMTP
) {
979 // Using external SMTP server.
980 $params['host'] = AK_SMTP_SERVER
;
981 $params['username'] = AK_SMTP_USER
;
982 $params['password'] = AK_SMTP_PASSWORD
;
984 $mail_connector = Mail
::factory('smtp', $params);
986 // Using PHP mail() function thru PEAR. Factory without parameters.
987 $mail_connector = Mail
::factory('mail');
991 $recipients['To'] = $to;
993 if (!empty($additional_headers)) {
994 foreach ($additional_headers as $k=>$v) {
996 if (strtolower($k)=='cc' ||
strtolower($k)=='cc:') {
997 $recipients['cc'] = $v;
998 unset($additional_headers['cc']);
1001 if (strtolower($k)=='bcc' ||
strtolower($k)=='bcc:') {
1002 $recipients['bcc'] = $v;
1003 unset($additional_headers['bcc']);
1008 $headers['From'] = $from;
1009 $headers['Subject'] = $subject;
1010 $headers['Content-Type'] = empty($headers['Content-Type']) ?
'text/plain; charset='.Ak
::locale('charset').'; format=flowed' : $headers['Content-Type'];
1012 $headers = array_merge($headers, $additional_headers);
1014 $error_code = $mail_connector->send($recipients, $headers, $body);
1021 * @todo move this out of here and use Pear Benchmark instead
1023 function profile($message = '')
1026 if(AK_DEV_MODE
&& AK_ENABLE_PROFILER
){
1027 if(!isset($profiler)){
1028 @require_once
(AK_LIB_DIR
.DS
.'AkProfiler.php');
1029 $profiler = new AkProfiler();
1031 register_shutdown_function(array(&$profiler,'showReport'));
1033 $profiler->setFlag($message);
1040 * Gets the size of given element. Counts arrays, returns numbers, string length or executes size() method on given object
1042 function size($element)
1044 if(is_array($element)){
1045 return count($element);
1046 }elseif (is_numeric($element) && !is_string($element)){
1048 }elseif (is_string($element)){
1049 return strlen($element);
1050 }elseif (is_object($element) && method_exists($element,'size')){
1051 return $element->size();
1059 * Select is a function for selecting items from double depth array.
1060 * This is useful when you just need some fields for generating
1061 * tables, select lists with only desired fields.
1064 * array('name'=>'Jose','email'=>'jose@example.com','address'=>'Colon, 52'),
1065 * array('name'=>'Alicia','email'=>'alicia@example.com','address'=>'Mayor, 45'),
1066 * array('name'=>'Hilario','email'=>'hilario@example.com','address'=>'Carlet, 78'),
1067 * array('name'=>'Bermi','email'=>'bermi@example.com','address'=>'Vilanova, 33'),
1070 * $people_for_table_generation = Ak::select($People,'name','email');
1072 * Now $people_for_table_generation will hold an array with
1074 * array ('name' => 'Jose','email' => 'jose@example.com'),
1075 * array ('name' => 'Alicia','email' => 'alicia@example.com'),
1076 * array ('name' => 'Hilario','email' => 'hilario@example.com'),
1077 * array ('name' => 'Bermi','email' => 'bermi@example.com')
1081 function select(&$source_array)
1083 $resulting_array = array();
1084 if(!empty($source_array) && is_array($source_array) && func_num_args() > 1) {
1085 $args = array_slice(func_get_args(),1);
1086 foreach ($source_array as $source_item){
1087 $item_fields = array();
1088 foreach ($args as $arg){
1089 if(is_object($source_item) && isset($source_item->$arg)){
1090 $item_fields[$arg] = $source_item->$arg;
1091 }elseif(is_array($source_item) && isset($source_item[$arg])){
1092 $item_fields[$arg] = $source_item[$arg];
1095 if(!empty($item_fields)){
1096 $resulting_array[] = $item_fields;
1100 return $resulting_array;
1103 function collect(&$source_array, $key_index, $value_index)
1105 $resulting_array = array();
1106 if(!empty($source_array) && is_array($source_array)) {
1107 foreach ($source_array as $source_item){
1108 if(is_object($source_item)){
1109 $resulting_array[@$source_item->$key_index] = @$source_item->$value_index;
1110 }elseif(is_array($source_item)){
1111 $resulting_array[@$source_item[$key_index]] = @$source_item[$value_index];
1115 return $resulting_array;
1118 function delete($source_array, $attributes_to_delete_from_array)
1120 $resulting_array = (array)$source_array;
1121 $args = array_slice(func_get_args(),1);
1122 $args = count($args) == 1 ? Ak
::toArray($args[0]) : $args;
1123 foreach ($args as $arg){
1124 unset($resulting_array[$arg]);
1126 return $resulting_array;
1129 function &singleton($class_name, &$arguments)
1132 if(!isset($instances[$class_name])) {
1133 if(is_object($arguments)){
1134 $instances[$class_name] =& new $class_name($arguments);
1136 if(Ak
::size($arguments) > 0){
1137 eval("\$instances[\$class_name] =& new \$class_name(".var_export($arguments, true)."); ");
1139 $instances[$class_name] =& new $class_name();
1142 $instances[$class_name]->__singleton_id
= md5(microtime().rand(1000,9000));
1144 return $instances[$class_name];
1148 function xml_to_array ($xml_data)
1150 $xml_parser = xml_parser_create ();
1151 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING
, 0);
1152 xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE
, 1);
1153 xml_parse_into_struct ($xml_parser, $xml_data, $vals, $index);
1154 xml_parser_free ($xml_parser);
1156 $ptrs[0] = & $params;
1157 foreach ($vals as $xml_elem) {
1158 $level = $xml_elem['level'] - 1;
1159 switch ($xml_elem['type']) {
1161 $tag_or_id = (array_key_exists ('attributes', $xml_elem)) ?
@$xml_elem['attributes']['ID'] : $xml_elem['tag'];
1162 $ptrs[$level][$tag_or_id][] = array ();
1163 $ptrs[$level+
1] = & $ptrs[$level][$tag_or_id][count($ptrs[$level][$tag_or_id])-1];
1166 $ptrs[$level][$xml_elem['tag']] = (isset ($xml_elem['value'])) ?
$xml_elem['value'] : '';
1173 function array_to_xml($array, $header = "<?xml version=\"1.0\"?>\r\n", $parent = 'EMPTY_TAG')
1175 static $_tags = array();
1177 foreach ($array as $key => $value) {
1178 $key = is_numeric($key) ?
$parent : $key;
1179 $value = is_array($value) ?
"\r\n".xmlFromArray($value, '', $key) : $value;
1180 $_tags[$key] = $key;
1181 $xml .= sprintf("<%s>%s</%s>\r\n", $key, $value, $key);
1184 foreach ($_tags as $_tag){
1185 $xml = str_replace(array("<$_tag>\r\n<$_tag>","</$_tag>\r\n</$_tag>"),array("<$_tag>","</$_tag>"),$xml);
1191 function encrypt($data, $key = 'Ak3los-m3D1a')
1193 srand((double)microtime() *1000000);
1194 $k2 = md5(rand(0, 32000));
1197 for ($i = 0 ; $i < strlen($data) ; $i++
) {
1198 if ($c == strlen($k2)) $c = 0;
1199 $m.= substr($k2, $c, 1) .(substr($data, $i, 1) ^
substr($k2, $c, 1));
1206 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1207 if ($c == strlen($k)) {
1210 $m.= substr($t, $i, 1) ^
substr($k, $c, 1);
1213 return base64_encode($m);
1216 function decrypt($encrypted_data, $key = 'Ak3los-m3D1a')
1218 $t = base64_decode($encrypted_data);
1222 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1223 if ($c == strlen($k)) $c = 0;
1224 $m.= substr($t, $i, 1) ^
substr($k, $c, 1);
1229 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1230 $d = substr($t, $i, 1);
1232 $m.= (substr($t, $i, 1) ^
$d);
1238 function blowfishEncrypt($data, $key = 'Ak3los-m3D1a')
1240 $key = substr($key,0,56);
1241 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Crypt'.DS
.'Blowfish.php');
1242 $Blowfish =& Ak
::singleton('Crypt_Blowfish', $key);
1243 $Blowfish->setKey($key);
1244 return $Blowfish->encrypt(base64_encode($data));
1247 function blowfishDecrypt($encrypted_data, $key = 'Ak3los-m3D1a')
1249 $key = substr($key,0,56);
1250 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Crypt'.DS
.'Blowfish.php');
1251 $Blowfish =& Ak
::singleton('Crypt_Blowfish', $key);
1252 $Blowfish->setKey($key);
1253 return base64_decode($Blowfish->decrypt($encrypted_data));
1257 function randomString($max_length = 8)
1260 srand((double)microtime()*1000000);
1261 for($i=0;$i<$max_length;$i++
){
1262 $randnumber = rand(48,120);
1263 while (($randnumber >= 58 && $randnumber <= 64) ||
($randnumber >= 91 && $randnumber <= 96)){
1264 $randnumber = rand(48,120);
1266 $randomString .= chr($randnumber);
1268 return $randomString;
1271 function compress($data, $format = 'gzip')
1273 $key = Ak
::randomString(15);
1274 $compressed_file = AK_TMP_DIR
.DS
.'d'.$key;
1275 $uncompressed_file = AK_TMP_DIR
.DS
.'s'.$key;
1277 if(@Ak
::file_put_contents($uncompressed_file, $data)){
1278 $compressed = gzopen($compressed_file,'w9');
1279 $uncompressed = fopen($uncompressed_file, 'rb');
1280 while(!feof($uncompressed)){
1281 $string = fread($uncompressed, 1024*512);
1282 gzwrite($compressed, $string, strlen($string));
1284 fclose($uncompressed);
1285 gzclose($compressed);
1287 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
);
1289 $result = Ak
::file_get_contents($compressed_file);
1293 function uncompress($compressed_data, $format = 'gzip')
1295 $key = Ak
::randomString(15);
1296 $compressed_file = AK_TMP_DIR
.DS
.'s'.$key;
1297 $uncompressed_file = AK_TMP_DIR
.DS
.'d'.$key;
1299 if(@Ak
::file_put_contents($compressed_file, $compressed_data)){
1300 $compressed = gzopen($compressed_file, "r");
1301 $uncompressed = fopen($uncompressed_file, "w");
1302 while(!gzeof($compressed)){
1303 $string = gzread($compressed, 4096);
1304 fwrite($uncompressed, $string, strlen($string));
1306 gzclose($compressed);
1307 fclose($uncompressed);
1309 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
);
1311 $result = Ak
::file_get_contents($uncompressed_file);
1316 function unzip($file_to_unzip, $destination_folder)
1318 require_once(AK_LIB_DIR
.DS
.'AkZip.php');
1319 $ArchiveZip =& new AkZip($file_to_unzip);
1320 $ArchiveZip->extract(array('add_path'=>str_replace(DS
,'/',$destination_folder)));
1324 function decompress($compressed_data, $format = 'gzip')
1326 return Ak
::uncompress($compressed_data, $format);
1330 function handleStaticCall()
1333 trigger_error(Ak
::t('Static calls emulation is not supported by PHP5 < 5.4'));
1336 $static_call = array_slice(debug_backtrace(),1,1);
1337 return call_user_func_array(array(new $static_call[0]['class'](),$static_call[0]['function']),$static_call[0]['args']);
1342 * Gets an array or a comma separated list of models. Then it includes its
1343 * respective files and returns an array of available models.
1349 $args = func_get_args();
1350 $args = is_array($args[0]) ?
$args[0] : (func_num_args() > 1 ?
$args : Ak
::stringToArray($args[0]));
1352 foreach ($args as $arg){
1353 $model_name = AkInflector
::camelize($arg);
1354 $model = AkInflector
::toModelFilename($model_name);
1355 if(file_exists($model)){
1356 $models[] = $model_name;
1357 include_once($model);
1358 }elseif (class_exists($model_name)){
1359 $models[] = $model_name;
1368 $args = func_get_args();
1369 return call_user_func_array(array('Ak','import'),$args);
1372 function stringToArray($string)
1375 if(count($args) == 1 && !is_array($args)){
1376 (array)$args = array_unique(array_map('trim',array_diff(explode(',',strtr($args.',',';|-',',,,')),array(''))));
1384 $args = func_get_args();
1385 return is_array($args[0]) ?
$args[0] : (func_num_args() === 1 ? Ak
::stringToArray($args[0]) : $args);
1390 * Includes PHP functions that are not available on current PHP version
1392 function compat($function_name)
1394 ak_compat($function_name);
1399 * The Akelos Framework has an standardized way to convert between formats.
1400 * You can find available converters on AkConverters
1402 * Usage Example: In order to convert from HTML to RTF you just need to call.
1403 * $rtf = Ak::convert('html','rtf', $my_html_file, array('font_size'=> 24));
1405 * Where the last option is an array of options for selected converter.
1407 * Previous example is the same as.
1409 * $rtf = Ak::convert(array('from'=>'html','to'=>'rtf', 'source' => $my_html_file, 'font_size'=> 24));
1411 * In order to create converters, you just need to name them "SourceFormatName + To + DestinationFormatName".
1412 * Whenever you need to call the, you need to specify the "path" option where your converter is located.
1413 * The only thing you converter must implement is a convert function. Passes options will be made available
1414 * as attributes on the converter.
1415 * If your converter needs to prepare something before the convert method is called, you just need to implement
1416 * a "init" method. You can avoid this by inspecting passed attributes to your constructor
1420 $args = func_get_args();
1421 $number_of_arguments = func_num_args();
1422 if($number_of_arguments > 1){
1424 if($number_of_arguments > 3 && is_array($args[$number_of_arguments-1])){
1425 $options = array_pop($args);
1427 $options['from'] = $args[0];
1428 $options['to'] = $args[1];
1429 $options['source'] = $args[2];
1434 $options['class_prefix'] = empty($options['class_prefix']) && empty($options['path']) ?
'Ak' : $options['class_prefix'];
1435 $options['path'] = rtrim(empty($options['path']) ? AK_LIB_DIR
.DS
.'AkConverters' : $options['path'], DS
."\t ");
1437 $converter_class_name = $options['class_prefix'].AkInflector
::camelize($options['from']).'To'.AkInflector
::camelize($options['to']);
1438 if(!class_exists($converter_class_name)){
1439 $file_name = $options['path'].DS
.$converter_class_name.'.php';
1440 if(!file_exists($file_name)){
1441 if(defined('AK_REMOTE_CONVERTER_URI')){
1442 require_once(AK_LIB_DIR
.DS
.'AkConverters'.DS
.'AkRemoteConverter.php');
1443 $result = AkRemoteConverter
::convert($options['from'], $options['to'], $options['source']);
1444 if($result !== false){
1448 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
);
1451 require_once($file_name);
1453 if(!class_exists($converter_class_name)){
1454 trigger_error(Ak
::t('Could not load %converter_class_name converter class',array('%converter_class_name'=>$converter_class_name)),E_USER_NOTICE
);
1458 $converter = new $converter_class_name($options);
1459 foreach ($options as $option=>$value){
1460 $option[0] != '_' ?
$converter->$option = $value : null;
1463 if(method_exists($converter, 'init')){
1466 return $converter->convert();
1471 * Converts given string to UTF-8
1473 * @param string $text
1474 * @param string $input_string_encoding
1475 * @return string UTF-8 encoded string
1477 function utf8($text, $input_string_encoding = null)
1479 $input_string_encoding = empty($input_string_encoding) ? Ak
::encoding() : $input_string_encoding;
1480 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1481 $Charset =& Ak
::singleton('AkCharset',$text);
1482 return $Charset->RecodeString($text,'UTF-8',$input_string_encoding);
1485 function recode($text, $output_string_encoding = null, $input_string_encoding = null)
1487 $input_string_encoding = empty($input_string_encoding) ? Ak
::encoding() : $input_string_encoding;
1488 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1489 $Charset =& Ak
::singleton('AkCharset',$text);
1490 return $Charset->RecodeString($text,$output_string_encoding,$input_string_encoding);
1496 if(empty($encoding)){
1497 // This will force system language settings
1499 $encoding = Ak
::locale('charset', Ak
::lang());
1500 $encoding = empty($encoding) ?
'UTF-8' : $encoding;
1506 * Get the encoding in which current user is sending the request
1508 function userEncoding()
1512 if(!isset($encoding)){
1513 $encoding = Ak
::encoding();
1514 if(!empty($_SERVER['HTTP_ACCEPT_CHARSET'])){
1515 $accepted_charsets = array_map('strtoupper', array_diff(explode(';',str_replace(',',';',$_SERVER['HTTP_ACCEPT_CHARSET']).';'), array('')));
1516 if(!in_array($encoding,$accepted_charsets)){
1517 $encoding = array_shift($accepted_charsets);
1525 * strlen for UTF-8 strings
1526 * Taken from anpaza at mail dot ru post at http://php.net/strlen
1528 function strlen_utf8($str)
1531 $len = strlen ($str);
1533 $chr = ord ($str[$i]);
1541 while ($chr & 0x80){
1551 * Convert an arbitrary PHP value into a JSON representation string.
1553 * For AJAX driven pages, JSON can come in handy – you can return send JavaScript objects
1554 * directly from your actions.
1556 function toJson($php_value)
1558 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'Services'.DS
.'JSON.php');
1560 $json =& Ak
::singleton('Services_JSON', $use);
1561 return $json->encode($php_value);
1565 * Converts a JSON representation string into a PHP value.
1567 function fromJson($json_string)
1569 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'Services'.DS
.'JSON.php');
1571 $json =& Ak
::singleton('Services_JSON', $use);
1572 return $json->decode($json_string);
1575 function &memory_cache($key, &$value)
1577 static $memory, $md5;
1578 if($value === false){
1579 // remove the object from cache
1580 $memory[$key] = null;
1582 }elseif($value === true){
1583 //check if the object is on cache or unaltered
1584 $result = !empty($memory[$key]) ?
$md5[$key] == Ak
::getStatusKey($memory[$key]) : false;
1586 }elseif ($value === null){
1588 return $memory[$key];
1591 $md5[$key] = Ak
::getStatusKey($value);
1592 $memory[$key] =& $value;
1598 function getStatusKey($element)
1601 $element = clone($element);
1603 if(isset($element->___status_key
)){
1604 unset($element->___status_key
);
1606 return md5(serialize($element));
1609 function logObjectForModifications(&$object)
1611 $object->___status_key
= empty($object->___status_key
) ? Ak
::getStatusKey($object) : $object->___status_key
;
1612 return $object->___status_key
;
1615 function resetObjectModificationsWacther(&$object)
1617 unset($object->___status_key
);
1620 function objectHasBeenModified(&$object)
1622 if(isset($object->___status_key
)){
1623 $old_status = $object->___status_key
;
1624 $new_key = Ak
::getStatusKey($object);
1625 return $old_status != $new_key;
1627 Ak
::logObjectForModifications($object);
1633 function &call_user_func_array($function_name, $parameters)
1636 $result = call_user_func_array($function_name, $parameters);
1639 $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]);
1640 $arguments = array();
1641 $argument_keys = array_keys($parameters);
1642 foreach($argument_keys as $k){
1643 $arguments[] = '$parameters['.$argument_keys[$k].']';
1645 eval('$_result =& '.$user_function_name.'('.implode($arguments, ', ').');');
1646 // Dirty hack for avoiding pass by reference warnings.
1647 $result =& $_result;
1652 function &array_sort_by($array, $key = null, $direction = 'asc')
1654 $array_copy = $sorted_array = array();
1655 foreach (array_keys($array) as $k) {
1656 $array_copy[$k] =& $array[$k][$key];
1659 natcasesort($array_copy);
1660 if(strtolower($direction) == 'desc'){
1661 $array_copy = array_reverse($array_copy, true);
1664 foreach (array_keys($array_copy) as $k){
1665 $sorted_array[$k] =& $array[$k];
1668 return $sorted_array;
1672 function mime_content_type($file)
1675 ak_compat('mime_content_type');
1677 $mime = @mime_content_type
($file);
1679 if (AK_OS
== 'WINDOWS' && $mime == 'application/octet-stream' && is_file($file)){
1684 empty($mime_types) ?
require(AK_LIB_DIR
.DS
.'utils'.DS
.'mime_types.php') : null;
1685 $file_extension = substr($file,strrpos($file,'.')+
1);
1686 $mime = !empty($mime_types[$file_extension]) ?
$mime_types[$file_extension] : false;
1692 function stream($path, $buffer_size = 4096)
1694 ob_implicit_flush();
1695 $len = empty($buffer_size) ?
4096 : $buffer_size;
1696 $fp = fopen($path, "rb");
1697 while (!feof($fp)) {
1698 echo fread($fp, $len);
1702 function _nextPermutation($p, $size)
1704 for ($i = $size - 1; isset($p[$i]) && isset($p[$i+
1]) && $p[$i] >= $p[$i+
1]; --$i) { }
1705 if ($i == -1) { return false; }
1706 for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
1707 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
1708 for (++
$i, $j = $size; $i < $j; ++
$i, --$j) {
1709 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
1715 * Returns all the possible permutations of given array
1717 function permute($array, $join_with = false)
1719 $size = count($array) - 1;
1720 $perm = range(0, $size);
1723 foreach ($perm as $i) {
1724 $perms[$j][] = $array[$i];
1726 } while ($perm = Ak
::_nextPermutation($perm, $size) AND ++
$j);
1729 foreach ($perms as $perm){
1730 $joined_perm[] = join(' ',$perm);
1732 return $joined_perm;
1738 * Generates a Universally Unique IDentifier, version 4.
1740 * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally
1741 * Unique IDentifiers (GUID), as well as several methods for producing them. One
1742 * such method, described in section 4.4, is based on truly random or pseudo-random
1743 * number generators, and is therefore implementable in a language like PHP.
1745 * We choose to produce pseudo-random numbers with the Mersenne Twister, and to always
1746 * limit single generated numbers to 16 bits (ie. the decimal value 65535). That is
1747 * because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed*
1748 * value, with only the equivalent of 31 significant bits. Producing two 16-bit random
1749 * numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits
1752 * The algorithm for version 4 UUIDs (ie. those based on random number generators)
1753 * states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits,
1754 * 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should
1755 * be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should
1756 * be 01. We try to conform to that definition as efficiently as possible, generating
1757 * smaller values where possible, and minimizing the number of base conversions.
1759 * @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for
1760 * any purpose ; it is distributed without any form of warranty whatsoever.
1761 * @author David Holmes <dholmes@cfdsoftware.net>
1763 * @return string A UUID, made up of 32 hex digits and 4 hyphens.
1768 // The field names refer to RFC 4122 section 4.1.2
1769 return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x',
1770 mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low"
1771 mt_rand(0, 65535), // 16 bits for "time_mid"
1772 mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version"
1773 bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)),
1774 // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
1775 // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
1776 // 8 bits for "clk_seq_low"
1777 mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node"
1782 function test($test_case_name, $use_sessions = false)
1784 ak_test($test_case_name, $use_sessions);
1788 * Use this function for securing includes. This way you can prevent file inclusion attacks
1790 function sanitize_include($include, $mode = 'normal')
1793 'paranoid' => '/([^A-Z^a-z^0-9^_^-^ ]+)/',
1794 'high' => '/([^A-Z^a-z^0-9^_^-^ ^\/^\\\^:]+)/',
1795 'normal' => '/([^A-Z^a-z^0-9^_^-^ ^\.^\/^\\\]+)/'
1797 $mode = array_key_exists($mode,$rules) ?
$mode : 'normal';
1798 return preg_replace($rules[$mode],'',$include);
1802 * Returns a PHP Object from an API resource
1805 function client_api($resource, $options = array())
1807 $default_options = array(
1808 'protocol' => 'xml_rpc',
1811 $options = array_merge($default_options, $options);
1813 require(AK_LIB_DIR
.DS
.'AkActionWebService'.DS
.'AkActionWebServiceClient.php');
1814 $Client =& new AkActionWebServiceClient($options['protocol']);
1815 $Client->init($resource, $options);
1821 * Cross PHP version replacement for html_entity_decode. Emulates PHP5 behaviour on PHP4 on UTF-8 entities
1823 function html_entity_decode($html, $translation_table_or_quote_style = null)
1826 return html_entity_decode($html,empty($translation_table_or_quote_style) ? ENT_QUOTES
: $translation_table_or_quote_style,'UTF-8');
1828 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1829 $html = preg_replace('~&#x([0-9a-f]+);~ei', 'AkCharset::_CharToUtf8(hexdec("\\1"))', $html);
1830 $html = preg_replace('~&#([0-9]+);~e', 'AkCharset::_CharToUtf8("\\1")', $html);
1831 if(empty($translation_table_or_quote_style)){
1832 $translation_table_or_quote_style = get_html_translation_table(HTML_ENTITIES
);
1833 $translation_table_or_quote_style = array_flip($translation_table_or_quote_style);
1835 return strtr($html, $translation_table_or_quote_style);
1839 * Loads the plugins found at app/vendor/plugins
1841 function &loadPlugins()
1843 require_once(AK_LIB_DIR
.DS
.'AkPlugin.php');
1844 $PluginManager =& new AkPluginLoader();
1845 $PluginManager->loadPlugins();
1846 return $PluginManager;
1851 // Now some static functions that are needed by the whole framework
1853 function translate($string, $args = null, $controller = null)
1855 return Ak
::t($string, $args, $controller);
1859 function ak_test($test_case_name, $use_sessions = false)
1861 if(!defined('ALL_TESTS_CALL')){
1862 $use_sessions ? @session_start
() : null;
1863 $test = &new $test_case_name();
1864 if (defined('AK_CLI') && AK_CLI || TextReporter
::inCli() ||
(defined('AK_CONSOLE_MODE') && AK_CONSOLE_MODE
) ||
(defined('AK_WEB_REQUEST') && !AK_WEB_REQUEST
)) {
1865 $test->run(new TextReporter());
1867 $test->run(new HtmlReporter());
1872 function ak_compat($function_name)
1874 if(!function_exists($function_name)){
1875 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'PHP'.DS
.'Compat'.DS
.'Function'.DS
.$function_name.'.php');
1879 function ak_generate_mock($name)
1885 $Mock->generate($name);
1889 * This function sets a constant and returns it's value. If constant has been already defined it
1890 * will reutrn its original value.
1892 * Returns null in case the constant does not exist
1894 * @param string $name
1895 * @param mixed $value
1897 function ak_define($name, $value = null)
1899 $name = strtoupper($name);
1900 $name = substr($name,0,3) == 'AK_' ?
$name : 'AK_'.$name;
1901 return defined($name) ?
constant($name) : (is_null($value) ?
null : (define($name, $value) ?
$value : null));
1905 * PHP4 triggers "Only variable references should be returned by reference" error when
1906 * a method that should return an object reference returns a boolean/array
1908 * The old method was to use a global variables, but it can lead into hard to debug bugs.
1910 * Now you'll need to use the following technique if you whant to build functions that
1911 * can return Object references or TRUE/FALSE.
1918 * Globals are deprecated. Used ak_false, ak_true and ak_array instead
1922 $GLOBALS['false'] = false;
1923 $GLOBALS['true'] = true;
1926 AK_PHP5 ||
function_exists('clone') ?
null : eval('function clone($object){return $object;}');
1928 Ak
::profile('Ak.php class included'.__FILE__
);