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 AkDbAdapter
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)
66 require_once(AK_LIB_DIR
.DS
.'AkActiveRecord'.DS
.'AkDbAdapter.php');
67 return AkDbAdapter
::getInstance($dsn);
71 * @param string $message
72 * @param [OPTIONAL] $fatal triggers even in production-mode
74 function deprecateWarning($message, $fatal=false)
76 if (!$fatal && AK_ENVIRONMENT
== 'production'){
79 if (is_array($message)){
80 trigger_error(Ak
::t("DEPRECATED WARNING: ".array_shift($message),$message), E_USER_NOTICE
);
82 trigger_error(Ak
::t("DEPRECATED WARNING: ".$message), E_USER_NOTICE
);
87 * Gets a cache object singleton instance
93 require_once(AK_LIB_DIR
.DS
.'AkCache.php');
94 $cache = new AkCache();
100 function toUrl($options, $set_routes = false)
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
);
114 } else if (is_a($options,'akrouter') && $set_routes) {
118 return $Map->toUrl($options);
123 * Translate strings to the current locale.
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
131 * within a translation string is:
135 * @param string $string A string containing the English string to
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.
142 function t($string, $args = null, $controller = null)
144 static $framework_dictionary = array(), $lang, $_dev_shutdown = true;
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);
151 register_shutdown_function(array('AkLocaleManager','updateLocaleFiles'));
152 $_dev_shutdown = false;
157 if(!empty($_SESSION['lang'])){
158 $lang = $_SESSION['lang'];
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);
166 if(!defined('AK_LOCALE')){
167 define('AK_LOCALE', $lang);
169 if(!empty($locale) && is_array($locale)){
170 Ak
::locale(null, $lang, $locale);
174 if(!empty($string) && is_array($string)){
175 if(!empty($string[$lang])){
176 return $string[$lang];
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];
186 return @$string[$try_whith_lang];
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;
194 if(isset($controller) && isset($framework_dictionary[$controller.'_dictionary'][$string])){
195 $string = $framework_dictionary[$controller.'_dictionary'][$string];
197 $string = isset($framework_dictionary[$string]) ?
$framework_dictionary[$string] : $string;
200 if(isset($args) && is_array($args)){
201 $string = @str_replace
(array_keys($args), array_values($args),$string);
205 * @todo Prepare for multiple locales by inspecting AK_DEFAULT_LOCALE
214 * Gets information about current locale from the locale settings on config/locales/LOCALE.php
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';
225 function locale($locale_setting, $locale = null)
229 // We initiate the locale settings
232 $locale = empty($locale) ?
(defined('AK_LOCALE') ? AK_LOCALE
: (Ak
::t('Akelos') && Ak
::locale($locale_setting))) : $locale;
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);
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
));
250 return isset($settings[$locale][$locale_setting]) ?
$settings[$locale][$locale_setting] : false;
254 function lang($set_language = null)
257 $lang = empty($set_language) ?
(empty($lang) ? AK_FRAMEWORK_LANGUAGE
: $lang) : $set_language;
262 function get_url_locale($set_locale = null)
268 $locale = empty($set_locale) ?
'' : $set_locale;
281 if(defined('AK_APP_LOCALES')){
282 $langs = array_diff(explode(',',AK_APP_LOCALES
.','),array(''));
284 $langs = empty($langs) ?
array($lang) : $langs;
290 return array_shift(Ak
::langs());
295 function dir($path, $options = array())
299 $path = rtrim($path, '/\\');
300 $default_options = array(
306 $options = array_merge($default_options, $options);
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)){
316 }elseif(!empty($options['dirs'])){
317 $result[][$file] = !empty($options['recurse']) ? Ak
::dir($path.DS
.$file, $options) : $file;
325 return array_reverse($result);
329 function file_put_contents($file_name, $content, $options = array())
332 $default_options = array(
333 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
334 'base_path' => AK_BASE_DIR
,
336 $options = array_merge($default_options, $options);
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'));
343 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
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));
352 return AkFtp
::put_contents($file_name, $content);
354 if(!is_dir(dirname($options['base_path'].DS
.$file_name))){
355 Ak
::make_dir(dirname($options['base_path'].DS
.$file_name), $options);
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>");
373 function file_get_contents($file_name, $options = array())
375 $default_options = array(
376 'ftp' => defined('AK_READ_FILES_USING_FTP') && AK_READ_FILES_USING_FTP
,
377 'base_path' => AK_BASE_DIR
,
379 $options = array_merge($default_options, $options);
381 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
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);
387 return file_get_contents($options['base_path'].DS
.$file_name);
392 * @todo Optimize this code (dirty add-on to log command line interpreter results)
394 function file_add_contents($file_name, $content, $options = array())
396 $original_content = @Ak
::file_get_contents($file_name, $options);
397 return Ak
::file_put_contents($file_name, $original_content.$content, $options);
400 function file_delete($file_name, $options = array())
402 $default_options = array(
403 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP
,
404 'base_path' => AK_BASE_DIR
,
406 $options = array_merge($default_options, $options);
408 $file_name = trim(str_replace($options['base_path'], '',$file_name),DS
);
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);
414 return unlink($options['base_path'].DS
.$file_name);
418 function directory_delete($dir_name, $options = array())
420 $default_options = array(
421 'ftp' => defined('AK_DELETE_FILES_USING_FTP') && AK_DELETE_FILES_USING_FTP
,
422 'base_path' => AK_BASE_DIR
,
424 $options = array_merge($default_options, $options);
427 $dir_name = Ak
::_getRestrictedPath($dir_name, $options);
429 if(empty($dir_name)){
434 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
435 return AkFtp
::delete($dir_name);
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;
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;
447 foreach ($items_to_delete['files'] as $file){
448 Ak
::file_delete($file, $options);
450 foreach ($items_to_delete['directories'] as $directory){
451 $sucess = $sucess ? Ak
::directory_delete($directory, $options) : $sucess;
454 return $sucess ? @rmdir
($options['base_path'].DS
.$dir_name) : $sucess;
458 function make_dir($path, $options = array())
460 $default_options = array(
461 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
462 'base_path' => AK_BASE_DIR
464 $options = array_merge($default_options, $options);
466 $path = trim(str_replace($options['base_path'], '',$path),DS
);
468 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
469 $path = trim(str_replace(array(DS
,'//'),array('/','/'),$path),'/');
470 return AkFtp
::make_dir($path);
472 $path = $options['base_path'].DS
.$path;
473 if (!file_exists($path)){
474 Ak
::make_dir(dirname($path), $options);
482 * This static method will copy recursively all the files or directories from one
483 * path within an Akelos application to another.
485 * It uses current installation settings, so it can perform copies via the filesystem or via FTP
487 function copy($origin, $target, $options = array())
489 $default_options = array(
490 'ftp' => defined('AK_UPLOAD_FILES_USING_FTP') && AK_UPLOAD_FILES_USING_FTP
,
491 'base_path' => AK_BASE_DIR
,
493 $options = array_merge($default_options, $options);
497 $origin = Ak
::_getRestrictedPath($origin, $options);
498 $target = Ak
::_getRestrictedPath($target, $options);
500 if(empty($origin) ||
empty($target)){
505 require_once(AK_LIB_DIR
.DS
.'AkFtp.php');
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);
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;
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;
521 foreach ($items_to_copy['directories'] as $directory){
522 $destination = str_replace($origin, $target, $directory);
523 $sucess = $sucess ? Ak
::copy($directory, $destination, $options) : $sucess;
530 * Returns a path restricting it to a base location
532 * This is used by Akelos to prevent functions namespaced under Ak
533 * from writing out of the Akelos base directory for security reasons.
535 function _getRestrictedPath($path, $options = array())
537 $default_options = array(
539 'base_path' => AK_BASE_DIR
,
541 $options = array_merge($default_options, $options);
543 $path = str_replace('..','', rtrim($path,'\\/. '));
544 $path = trim(str_replace($options['base_path'], '',$path),DS
);
547 $path = trim(str_replace(array(DS
,'//'),array('/','/'), $path),'/');
555 * Perform a web request
557 * @param string $url URL we are going to request.
558 * @param array $options Options for current request.
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.
565 function url_get_contents($url, $options = array())
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
);
573 return $Client->$method($url, $options);
578 * Trace helper function for development purposes
582 * @param string $text Helper text
583 * @param string $line Helper line
584 * @param string $file Helper file
585 * @return echoes result to screen
587 function trace($text = null, $line = null, $file = null)
594 $line = isset($line) ?
"Line: $line".(AK_CLI?
"\n":"<br />") : "";
595 $file = isset($file) ?
"File: $file".(AK_CLI?
"\n":"<br />") : "";
601 $text = AK_CLI?
'---> '.$text:'<b>---></b>'.$text;
604 echo AK_CLI?
"----------------\n$line $file $text\n----------------\n":"<hr /><div>$line $file $text</div><hr />\n";
612 * Outputs debug info given a PHP resource (vars, objects,
617 * @param mixed $data Data to debug. It can be an object, array,
619 * @return void Prints debug info.
621 function debug ($data, $_functions=0)
623 if(!AK_DEBUG
&& !AK_DEV_MODE
){
632 if(is_object($data) && method_exists($data, 'debug')){
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);
643 if (is_array($data) ||
is_object($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") {
651 Ak
::debug ($value,$sf);
652 $lines = explode("\n",ob_get_clean()."\n");
653 foreach ($lines as $line){
654 echo "\t".$line."\n";
656 } elseif (eregi ("function", $type)) {
658 AK_CLI ?
printf ("\t* (%s) %s:\n",$type, $key, $value) :
659 printf ("<li>(%s) <b>%s</b> </li>\n",$type, $key, $value);
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);
669 echo AK_CLI ?
"\n--/\n" : "</ol>fin.\n";
682 * Gets information about given object
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
693 function get_object_info($object, $include_inherited_info = false)
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);
701 foreach ($vars as $varname=>$var_value){
702 $var_desc .= "<li>$varname = $var_value (". gettype($var_value) .")</li>\n";
704 $var_desc .= "</ul>";
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) .'();'));
713 * Gets selected object methods.
715 * WARNING: Inherited methods are not returned by this
716 * function. You can fetch them by using PHP native function
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
727 function get_this_object_methods($object)
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);
736 return array_values((array)$array3);
743 * Get selected objects default attributes
745 * WARNING: Inherited attributes are not returned by this
746 * function. You can fetch them by using PHP native function
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
757 function get_this_object_attributes($object)
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);
767 return (array)$array3;
772 function &getLogger()
776 require_once(AK_LIB_DIR
.DS
.'AkLogger.php');
777 $Logger = new AkLogger();
784 function get_constants()
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]);
798 * @todo Use timezone time
802 return time()+
(defined('AK_TIME_DIFERENCE') ? AK_TIME_DIFERENCE
*3600 : 0);
807 return Ak
::time()+
(AK_TIME_DIFERENCE_FROM_GMT
*3600);
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"
814 function getTimestamp($iso_date_or_hour = null)
816 if(empty($iso_date_or_hour)){
820 ([0-9]{4})[-\/\.]? # year
821 ([0-9]{1,2})[-\/\.]? # month
822 ([0-9]{1,2})[ -]? # day
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]);
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]);
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]);
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"'));
844 * Return formatted date.
846 * You can supply a format as defined at http://php.net/date
848 * Default date is in ISO format
850 function getDate($timestamp = null, $format = null)
852 $timestamp = !isset($timestamp) ? Ak
::time() : $timestamp;
853 $use_adodb = $timestamp <= -3600 ||
$timestamp >= 2147468400;
855 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb-time.inc.php');
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);
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")'));
868 * mail function substitute. Uses the PEAR::Mail() function API.
870 * Messaging subsystem for user communication. See PEAR::Mail() function in PHP
871 * documentation for information.
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:
880 * For future upgrades, you must define which constants must be declared and add
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.
890 * User who sends the mail.
894 * Receiver, or receivers of the mail.
896 * The formatting of this string must comply with RFC 2822. Some examples are:
899 * user@example.com, anotheruser@example.com
900 * User <user@example.com>
901 * User <user@example.com>, Another User <anotheruser@example.com>
905 * Subject of the email to be sent. This must not contain any newline
906 * characters, or the mail may not be sent properly.
910 * Message to be sent.
912 * @param additional_headers (optional)
914 * Array to be inserted at the end of the email header.
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'.
920 * @return boolean whether message has been sent or not.
923 function mail ($from, $to, $subject, $body, $additional_headers = array())
925 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Mail.php');
927 static $mail_connector;
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
;
939 $mail_connector = Mail
::factory('smtp', $params);
941 // Using PHP mail() function thru PEAR. Factory without parameters.
942 $mail_connector = Mail
::factory('mail');
946 $recipients['To'] = $to;
948 if (!empty($additional_headers)) {
949 foreach ($additional_headers as $k=>$v) {
951 if (strtolower($k)=='cc' ||
strtolower($k)=='cc:') {
952 $recipients['cc'] = $v;
953 unset($additional_headers['cc']);
956 if (strtolower($k)=='bcc' ||
strtolower($k)=='bcc:') {
957 $recipients['bcc'] = $v;
958 unset($additional_headers['bcc']);
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'];
967 $headers = array_merge($headers, $additional_headers);
969 return $mail_connector->send($recipients, $headers, $body) == true;
974 * @todo move this out of here and use Pear Benchmark instead
976 function profile($message = '')
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();
984 register_shutdown_function(array(&$profiler,'showReport'));
986 $profiler->setFlag($message);
993 * Gets the size of given element. Counts arrays, returns numbers, string length or executes size() method on given object
995 function size($element)
997 if(is_array($element)){
998 return count($element);
999 }elseif (is_numeric($element) && !is_string($element)){
1001 }elseif (is_string($element)){
1002 return strlen($element);
1003 }elseif (is_object($element) && method_exists($element,'size')){
1004 return $element->size();
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.
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'),
1023 * $people_for_table_generation = Ak::select($People,'name','email');
1025 * Now $people_for_table_generation will hold an array with
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')
1034 function select(&$source_array)
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];
1048 if(!empty($item_fields)){
1049 $resulting_array[] = $item_fields;
1053 return $resulting_array;
1056 function collect(&$source_array, $key_index, $value_index)
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];
1068 return $resulting_array;
1071 function delete($source_array, $attributes_to_delete_from_array)
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]);
1079 return $resulting_array;
1082 function &singleton($class_name, &$arguments)
1085 if(!isset($instances[$class_name])) {
1086 if(is_object($arguments)){
1087 $instances[$class_name] =& new $class_name($arguments);
1089 if(Ak
::size($arguments) > 0){
1090 eval("\$instances[\$class_name] =& new \$class_name(".var_export($arguments, true)."); ");
1092 $instances[$class_name] =& new $class_name();
1095 $instances[$class_name]->__singleton_id
= md5(microtime().rand(1000,9000));
1097 return $instances[$class_name];
1101 function xml_to_array ($xml_data)
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);
1109 $ptrs[0] = & $params;
1110 foreach ($vals as $xml_elem) {
1111 $level = $xml_elem['level'] - 1;
1112 switch ($xml_elem['type']) {
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];
1119 $ptrs[$level][$xml_elem['tag']] = (isset ($xml_elem['value'])) ?
$xml_elem['value'] : '';
1126 function array_to_xml($array, $header = "<?xml version=\"1.0\"?>\r\n", $parent = 'EMPTY_TAG')
1128 static $_tags = array();
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);
1137 foreach ($_tags as $_tag){
1138 $xml = str_replace(array("<$_tag>\r\n<$_tag>","</$_tag>\r\n</$_tag>"),array("<$_tag>","</$_tag>"),$xml);
1144 function encrypt($data, $key = 'Ak3los-m3D1a')
1146 srand((double)microtime() *1000000);
1147 $k2 = md5(rand(0, 32000));
1150 for ($i = 0 ; $i < strlen($data) ; $i++
) {
1151 if ($c == strlen($k2)) $c = 0;
1152 $m.= substr($k2, $c, 1) .(substr($data, $i, 1) ^
substr($k2, $c, 1));
1159 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1160 if ($c == strlen($k)) {
1163 $m.= substr($t, $i, 1) ^
substr($k, $c, 1);
1166 return base64_encode($m);
1169 function decrypt($encrypted_data, $key = 'Ak3los-m3D1a')
1171 $t = base64_decode($encrypted_data);
1175 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1176 if ($c == strlen($k)) $c = 0;
1177 $m.= substr($t, $i, 1) ^
substr($k, $c, 1);
1182 for ($i = 0 ; $i < strlen($t) ; $i++
) {
1183 $d = substr($t, $i, 1);
1185 $m.= (substr($t, $i, 1) ^
$d);
1191 function blowfishEncrypt($data, $key = 'Ak3los-m3D1a')
1193 $key = substr($key,0,56);
1194 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Crypt'.DS
.'Blowfish.php');
1195 $Blowfish =& Ak
::singleton('Crypt_Blowfish', $key);
1196 $Blowfish->setKey($key);
1197 return $Blowfish->encrypt(base64_encode($data));
1200 function blowfishDecrypt($encrypted_data, $key = 'Ak3los-m3D1a')
1202 $key = substr($key,0,56);
1203 require_once(AK_CONTRIB_DIR
.DS
.'pear'.DS
.'Crypt'.DS
.'Blowfish.php');
1204 $Blowfish =& Ak
::singleton('Crypt_Blowfish', $key);
1205 $Blowfish->setKey($key);
1206 return base64_decode($Blowfish->decrypt($encrypted_data));
1210 function randomString($max_length = 8)
1213 srand((double)microtime()*1000000);
1214 for($i=0;$i<$max_length;$i++
){
1215 $randnumber = rand(48,120);
1216 while (($randnumber >= 58 && $randnumber <= 64) ||
($randnumber >= 91 && $randnumber <= 96)){
1217 $randnumber = rand(48,120);
1219 $randomString .= chr($randnumber);
1221 return $randomString;
1225 function compress($data, $format = 'gzip')
1227 $key = Ak
::randomString(15);
1228 $compressed_file = AK_TMP_DIR
.DS
.'d'.$key;
1229 $uncompressed_file = AK_TMP_DIR
.DS
.'s'.$key;
1230 if(Ak
::file_put_contents($uncompressed_file, $data, array('base_path'=>AK_TMP_DIR
))){
1231 $compressed = gzopen($compressed_file,'w9');
1232 $uncompressed = fopen($uncompressed_file, 'rb');
1233 while(!feof($uncompressed)){
1234 $string = fread($uncompressed, 1024*512);
1235 gzwrite($compressed, $string, strlen($string));
1237 fclose($uncompressed);
1238 gzclose($compressed);
1240 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
);
1242 $result = Ak
::file_get_contents($compressed_file, array('base_path'=>AK_TMP_DIR
));
1246 function uncompress($compressed_data, $format = 'gzip')
1248 $key = Ak
::randomString(15);
1249 $compressed_file = AK_TMP_DIR
.DS
.'s'.$key;
1250 $uncompressed_file = AK_TMP_DIR
.DS
.'d'.$key;
1252 if(Ak
::file_put_contents($compressed_file, $compressed_data, array('base_path'=>AK_TMP_DIR
))){
1253 $compressed = gzopen($compressed_file, "r");
1254 $uncompressed = fopen($uncompressed_file, "w");
1255 while(!gzeof($compressed)){
1256 $string = gzread($compressed, 4096);
1257 fwrite($uncompressed, $string, strlen($string));
1259 gzclose($compressed);
1260 fclose($uncompressed);
1262 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
);
1264 $result = Ak
::file_get_contents($uncompressed_file, array('base_path'=>AK_TMP_DIR
));
1269 function unzip($file_to_unzip, $destination_folder)
1271 require_once(AK_LIB_DIR
.DS
.'AkZip.php');
1272 $ArchiveZip =& new AkZip($file_to_unzip);
1273 $ArchiveZip->extract(array('add_path'=>str_replace(DS
,'/',$destination_folder)));
1277 function decompress($compressed_data, $format = 'gzip')
1279 return Ak
::uncompress($compressed_data, $format);
1283 function handleStaticCall()
1286 trigger_error(Ak
::t('Static calls emulation is not supported by PHP5 < 5.4'));
1289 $static_call = array_slice(debug_backtrace(),1,1);
1290 return call_user_func_array(array(new $static_call[0]['class'](),$static_call[0]['function']),$static_call[0]['args']);
1295 * Gets an array or a comma separated list of models. Then it includes its
1296 * respective files and returns an array of available models.
1298 * @return array available models
1302 $args = func_get_args();
1303 $args = is_array($args[0]) ?
$args[0] : (func_num_args() > 1 ?
$args : Ak
::stringToArray($args[0]));
1305 foreach ($args as $arg){
1306 $model_name = AkInflector
::camelize($arg);
1307 if (class_exists($model_name)){
1308 $models[] = $model_name;
1311 $model = AkInflector
::toModelFilename($model_name);
1312 if (file_exists($model)){
1313 $models[] = $model_name;
1314 include_once($model);
1317 // Shouldn't we trigger an user-error?: Unknown Model or could not find the Model
1323 function import_mailer()
1325 require_once(AK_LIB_DIR
.DS
.'AkActionMailer.php');
1326 $args = func_get_args();
1327 return call_user_func_array(array('Ak','import'),$args);
1332 $args = func_get_args();
1333 return call_user_func_array(array('Ak','import'),$args);
1336 function stringToArray($string)
1339 if(count($args) == 1 && !is_array($args)){
1340 (array)$args = array_unique(array_map('trim',array_diff(explode(',',strtr($args.',',';|-',',,,')),array(''))));
1348 $args = func_get_args();
1349 return is_array($args[0]) ?
$args[0] : (func_num_args() === 1 ? Ak
::stringToArray($args[0]) : $args);
1353 * Returns an array including only the elements with provided keys.
1355 * This is useful to limit the parameters of an array used by a method.
1357 * This utility can be used for modifying arrays which is useful for securing record creation/updating.
1359 * If you have this code on a controller
1361 * $this->user->setAttributes($this->params['user']);
1363 * 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.
1365 * You could avoid by using the new Ak::pick method which will return and array with desired keys.
1367 * $this->user->setAttributes(Ak::pick('name,email', $this->params['user']));
1370 function pick($keys, $source_array)
1373 foreach (Ak
::toArray($keys) as $k){
1374 $result[$k] = isset($source_array[$k]) ?
$source_array[$k] : null;
1380 * Gets a copy of the first element of an array. Similar to array_shift but it does not modify the original array
1384 $args = func_get_args();
1385 return array_shift(array_slice(is_array($args[0]) ?
$args[0] : $args , 0));
1389 * Gets a copy of the last element of an array. Similar to array_pop but it does not modify the original array
1393 $args = func_get_args();
1394 return array_shift(array_slice(is_array($args[0]) ?
$args[0] : $args , -1));
1398 * Includes PHP functions that are not available on current PHP version
1400 function compat($function_name)
1402 ak_compat($function_name);
1407 * The Akelos Framework has an standardized way to convert between formats.
1408 * You can find available converters on AkConverters
1410 * Usage Example: In order to convert from HTML to RTF you just need to call.
1411 * $rtf = Ak::convert('html','rtf', $my_html_file, array('font_size'=> 24));
1413 * Where the last option is an array of options for selected converter.
1415 * Previous example is the same as.
1417 * $rtf = Ak::convert(array('from'=>'html','to'=>'rtf', 'source' => $my_html_file, 'font_size'=> 24));
1419 * In order to create converters, you just need to name them "SourceFormatName + To + DestinationFormatName".
1420 * Whenever you need to call the, you need to specify the "path" option where your converter is located.
1421 * The only thing you converter must implement is a convert function. Passes options will be made available
1422 * as attributes on the converter.
1423 * If your converter needs to prepare something before the convert method is called, you just need to implement
1424 * a "init" method. You can avoid this by inspecting passed attributes to your constructor
1428 $args = func_get_args();
1429 $number_of_arguments = func_num_args();
1430 if($number_of_arguments > 1){
1432 if($number_of_arguments > 3 && is_array($args[$number_of_arguments-1])){
1433 $options = array_pop($args);
1435 $options['from'] = $args[0];
1436 $options['to'] = $args[1];
1437 $options['source'] = $args[2];
1441 if ($options['from'] == $options['to']) {
1442 return $options['source'];
1444 $options['class_prefix'] = empty($options['class_prefix']) && empty($options['path']) ?
'Ak' : $options['class_prefix'];
1445 $options['path'] = rtrim(empty($options['path']) ? AK_LIB_DIR
.DS
.'AkConverters' : $options['path'], DS
."\t ");
1447 $converter_class_name = $options['class_prefix'].AkInflector
::camelize($options['from']).'To'.AkInflector
::camelize($options['to']);
1448 if(!class_exists($converter_class_name)){
1449 $file_name = $options['path'].DS
.$converter_class_name.'.php';
1450 if(!file_exists($file_name)){
1451 if(defined('AK_REMOTE_CONVERTER_URI')){
1452 require_once(AK_LIB_DIR
.DS
.'AkConverters'.DS
.'AkRemoteConverter.php');
1453 $result = AkRemoteConverter
::convert($options['from'], $options['to'], $options['source']);
1454 if($result !== false){
1458 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
);
1461 require_once($file_name);
1463 if(!class_exists($converter_class_name)){
1464 trigger_error(Ak
::t('Could not load %converter_class_name converter class',array('%converter_class_name'=>$converter_class_name)),E_USER_NOTICE
);
1468 $converter = new $converter_class_name($options);
1469 foreach ($options as $option=>$value){
1470 $option[0] != '_' ?
$converter->$option = $value : null;
1473 if(method_exists($converter, 'init')){
1476 return $converter->convert();
1481 * Converts given string to UTF-8
1483 * @param string $text
1484 * @param string $input_string_encoding
1485 * @return string UTF-8 encoded string
1487 function utf8($text, $input_string_encoding = null)
1489 $input_string_encoding = empty($input_string_encoding) ? Ak
::encoding() : $input_string_encoding;
1490 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1491 $Charset =& Ak
::singleton('AkCharset',$text);
1492 return $Charset->RecodeString($text,'UTF-8',$input_string_encoding);
1495 function recode($text, $output_string_encoding = null, $input_string_encoding = null, $recoding_engine = null)
1497 $input_string_encoding = empty($input_string_encoding) ? Ak
::encoding() : $input_string_encoding;
1498 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1499 $Charset =& Ak
::singleton('AkCharset',$text);
1500 return $Charset->RecodeString($text,$output_string_encoding,$input_string_encoding, $recoding_engine);
1506 if(empty($encoding)){
1507 // This will force system language settings
1509 $encoding = Ak
::locale('charset', Ak
::lang());
1510 $encoding = empty($encoding) ?
'UTF-8' : $encoding;
1516 * Get the encoding in which current user is sending the request
1518 function userEncoding()
1522 if(!isset($encoding)){
1523 $encoding = Ak
::encoding();
1524 if(!empty($_SERVER['HTTP_ACCEPT_CHARSET'])){
1525 $accepted_charsets = array_map('strtoupper', array_diff(explode(';',str_replace(',',';',$_SERVER['HTTP_ACCEPT_CHARSET']).';'), array('')));
1526 if(!in_array($encoding,$accepted_charsets)){
1527 $encoding = array_shift($accepted_charsets);
1535 * strlen for UTF-8 strings
1536 * Taken from anpaza at mail dot ru post at http://php.net/strlen
1538 function strlen_utf8($str)
1541 $len = strlen ($str);
1543 $chr = ord ($str[$i]);
1551 while ($chr & 0x80){
1561 * Convert an arbitrary PHP value into a JSON representation string.
1563 * For AJAX driven pages, JSON can come in handy – you can return send JavaScript objects
1564 * directly from your actions.
1566 function toJson($php_value)
1568 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'Services'.DS
.'JSON.php');
1570 $json =& Ak
::singleton('Services_JSON', $use);
1571 return $json->encode($php_value);
1575 * Converts a JSON representation string into a PHP value.
1577 function fromJson($json_string)
1579 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'Services'.DS
.'JSON.php');
1581 $json =& Ak
::singleton('Services_JSON', $use);
1582 return $json->decode($json_string);
1585 function &memory_cache($key, &$value)
1587 static $memory, $md5;
1588 if($value === false){
1589 // remove the object from cache
1590 $memory[$key] = null;
1592 }elseif($value === true){
1593 //check if the object is on cache or unaltered
1594 $result = !empty($memory[$key]) ?
$md5[$key] == Ak
::getStatusKey($memory[$key]) : false;
1596 }elseif ($value === null){
1598 return $memory[$key];
1601 $md5[$key] = Ak
::getStatusKey($value);
1602 $memory[$key] =& $value;
1608 function getStatusKey($element)
1611 $element = clone($element);
1613 if(isset($element->___status_key
)){
1614 unset($element->___status_key
);
1616 return md5(serialize($element));
1619 function logObjectForModifications(&$object)
1621 $object->___status_key
= empty($object->___status_key
) ? Ak
::getStatusKey($object) : $object->___status_key
;
1622 return $object->___status_key
;
1625 function resetObjectModificationsWacther(&$object)
1627 unset($object->___status_key
);
1630 function objectHasBeenModified(&$object)
1632 if(isset($object->___status_key
)){
1633 $old_status = $object->___status_key
;
1634 $new_key = Ak
::getStatusKey($object);
1635 return $old_status != $new_key;
1637 Ak
::logObjectForModifications($object);
1643 function &call_user_func_array($function_name, $parameters)
1646 $result = call_user_func_array($function_name, $parameters);
1649 $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]);
1650 $arguments = array();
1651 $argument_keys = array_keys($parameters);
1652 foreach($argument_keys as $k){
1653 $arguments[] = '$parameters['.$argument_keys[$k].']';
1655 eval('$_result =& '.$user_function_name.'('.implode($arguments, ', ').');');
1656 // Dirty hack for avoiding pass by reference warnings.
1657 $result =& $_result;
1662 function &array_sort_by($array, $key = null, $direction = 'asc')
1664 $array_copy = $sorted_array = array();
1665 foreach (array_keys($array) as $k) {
1666 $array_copy[$k] =& $array[$k][$key];
1669 natcasesort($array_copy);
1670 if(strtolower($direction) == 'desc'){
1671 $array_copy = array_reverse($array_copy, true);
1674 foreach (array_keys($array_copy) as $k){
1675 $sorted_array[$k] =& $array[$k];
1678 return $sorted_array;
1681 function mime_content_type($file)
1684 ak_compat('mime_content_type');
1685 empty($mime_types) ?
require(AK_LIB_DIR
.DS
.'utils'.DS
.'mime_types.php') : null;
1686 $file_extension = substr($file,strrpos($file,'.')+
1);
1687 return !empty($mime_types[$file_extension]) ?
$mime_types[$file_extension] : false;
1690 function stream($path, $buffer_size = 4096)
1692 ob_implicit_flush();
1693 $len = empty($buffer_size) ?
4096 : $buffer_size;
1694 $fp = fopen($path, "rb");
1695 while (!feof($fp)) {
1696 echo fread($fp, $len);
1700 function _nextPermutation($p, $size)
1702 for ($i = $size - 1; isset($p[$i]) && isset($p[$i+
1]) && $p[$i] >= $p[$i+
1]; --$i) { }
1703 if ($i == -1) { return false; }
1704 for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
1705 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
1706 for (++
$i, $j = $size; $i < $j; ++
$i, --$j) {
1707 $tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
1713 * Returns all the possible permutations of given array
1715 function permute($array, $join_with = false)
1717 $size = count($array) - 1;
1718 $perm = range(0, $size);
1721 foreach ($perm as $i) {
1722 $perms[$j][] = $array[$i];
1724 } while ($perm = Ak
::_nextPermutation($perm, $size) AND ++
$j);
1727 foreach ($perms as $perm){
1728 $joined_perm[] = join(' ',$perm);
1730 return $joined_perm;
1736 * Generates a Universally Unique IDentifier, version 4.
1738 * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally
1739 * Unique IDentifiers (GUID), as well as several methods for producing them. One
1740 * such method, described in section 4.4, is based on truly random or pseudo-random
1741 * number generators, and is therefore implementable in a language like PHP.
1743 * We choose to produce pseudo-random numbers with the Mersenne Twister, and to always
1744 * limit single generated numbers to 16 bits (ie. the decimal value 65535). That is
1745 * because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed*
1746 * value, with only the equivalent of 31 significant bits. Producing two 16-bit random
1747 * numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits
1750 * The algorithm for version 4 UUIDs (ie. those based on random number generators)
1751 * states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits,
1752 * 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should
1753 * be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should
1754 * be 01. We try to conform to that definition as efficiently as possible, generating
1755 * smaller values where possible, and minimizing the number of base conversions.
1757 * @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for
1758 * any purpose ; it is distributed without any form of warranty whatsoever.
1759 * @author David Holmes <dholmes@cfdsoftware.net>
1761 * @return string A UUID, made up of 32 hex digits and 4 hyphens.
1766 // The field names refer to RFC 4122 section 4.1.2
1767 return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x',
1768 mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low"
1769 mt_rand(0, 65535), // 16 bits for "time_mid"
1770 mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version"
1771 bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)),
1772 // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
1773 // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
1774 // 8 bits for "clk_seq_low"
1775 mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node"
1780 function test($test_case_name, $use_sessions = false)
1782 ak_test($test_case_name, $use_sessions);
1786 * Use this function for securing includes. This way you can prevent file inclusion attacks
1788 function sanitize_include($include, $mode = 'normal')
1791 'paranoid' => '/([^A-Z^a-z^0-9^_^-^ ]+)/',
1792 'high' => '/([^A-Z^a-z^0-9^_^-^ ^\/^\\\^:]+)/',
1793 'normal' => '/([^A-Z^a-z^0-9^_^-^ ^\.^\/^\\\]+)/'
1795 $mode = array_key_exists($mode,$rules) ?
$mode : 'normal';
1796 return preg_replace($rules[$mode],'',$include);
1800 * Returns a PHP Object from an API resource
1803 function client_api($resource, $options = array())
1805 $default_options = array(
1806 'protocol' => 'xml_rpc',
1809 $options = array_merge($default_options, $options);
1811 require(AK_LIB_DIR
.DS
.'AkActionWebService'.DS
.'AkActionWebServiceClient.php');
1812 $Client =& new AkActionWebServiceClient($options['protocol']);
1813 $Client->init($resource, $options);
1819 * Cross PHP version replacement for html_entity_decode. Emulates PHP5 behaviour on PHP4 on UTF-8 entities
1821 function html_entity_decode($html, $translation_table_or_quote_style = null)
1824 return html_entity_decode($html,empty($translation_table_or_quote_style) ? ENT_QUOTES
: $translation_table_or_quote_style,'UTF-8');
1826 require_once(AK_LIB_DIR
.DS
.'AkCharset.php');
1827 $html = preg_replace('~&#x([0-9a-f]+);~ei', 'AkCharset::_CharToUtf8(hexdec("\\1"))', $html);
1828 $html = preg_replace('~&#([0-9]+);~e', 'AkCharset::_CharToUtf8("\\1")', $html);
1829 if(empty($translation_table_or_quote_style)){
1830 $translation_table_or_quote_style = get_html_translation_table(HTML_ENTITIES
);
1831 $translation_table_or_quote_style = array_flip($translation_table_or_quote_style);
1833 return strtr($html, $translation_table_or_quote_style);
1837 * Loads the plugins found at app/vendor/plugins
1839 function &loadPlugins()
1841 require_once(AK_LIB_DIR
.DS
.'AkPlugin.php');
1842 $PluginManager =& new AkPluginLoader();
1843 $PluginManager->loadPlugins();
1844 return $PluginManager;
1847 function setStaticVar($name,&$value)
1849 $refhack =& Ak
::_staticVar($name,$value);
1854 * Strategy for unifying in-function static vars used mainly for performance improvements framework-wide.
1861 * if(!isset($cache[$var])){
1862 * $cache[$var] = some_heavy_function($var);
1864 * return $cache[$var];
1868 * 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.
1870 * We can refresh this static values the new Ak::getStaticVar method. So from previous example we will have to replace
1874 function &getStaticVar($name)
1876 $refhack =& Ak
::_staticVar($name,$refhackvar = null);
1880 function &unsetStaticVar($name)
1882 $refhack =& Ak
::_staticVar($name,$refhackvar = null,true);
1886 function &_staticVar($name, &$value, $destruct = false)
1893 if ($value === null && $destruct === false) {
1897 if (isset($_memory[$name])) {
1898 $return = &$_memory[$name];
1900 } else if ($value !== null) {
1904 if (is_string($name)) {
1905 $_memory[$name] = &$value;
1911 } else if ($destruct === true) {
1912 if ($name !== null) {
1913 $value = isset($_memory[$name])?
$_memory[$name]:$null;
1914 if (is_object($value) && method_exists($value,'__destruct')) {
1915 $value->__destruct();
1918 unset($_memory[$name]);
1920 foreach ($_memory as $name => $value) {
1921 Ak
::unsetStaticVar($name);
1930 * @param array $options
1931 * @param array $default_options
1932 * @param array $available_options
1933 * @param boolean $walk_keys
1935 function parseOptions(&$options, $default_options = array(), $parameters = array(), $walk_keys=false)
1938 foreach ($options as $key=>$value) {
1939 if (!is_array($value)) {
1940 $options[$value] = $default_options;
1942 Ak
::parseOptions($value, $default_options, $parameters);
1943 $options[$key] = $value;
1949 $options = array_merge($default_options, $options);
1950 foreach($options as $key => $value) {
1951 if(isset($params['available_options'])) {
1952 if (!isset($params['available_options'][$key])) {
1956 $options[$key] = $value;
1962 * Returns YAML settings from config/$namespace.yml
1964 function getSettings($namespace, $raise_error_if_config_file_not_found = true)
1966 $staticVarNs = 'Ak::getSettings';
1967 $loaded_settings = &Ak
::getStaticVar($staticVarNs);
1969 if(isset($loaded_settings[$namespace])){
1970 return $loaded_settings[$namespace];
1973 $namespace = Ak
::sanitize_include($namespace, 'paranoid');
1974 $yaml_file_name = AK_CONFIG_DIR
.DS
.$namespace.'.yml';
1976 if (!is_file($yaml_file_name)){
1977 if($raise_error_if_config_file_not_found){
1978 die(Ak
::t('Could not find %namespace settings file in %path.', array('%namespace'=>$namespace, '%path'=>$yaml_file_name))."\n");
1982 require_once(AK_VENDOR_DIR
.DS
.'TextParsers'.DS
.'spyc.php');
1983 $content = file_get_contents($yaml_file_name);
1984 $content = Ak
::_parseSettingsConstants($content);
1985 $return = Spyc
::YAMLLoad($content);
1986 Ak
::setStaticVar($staticVarNs,$return);
1990 function _parseSettingsConstants($settingsStr)
1992 return preg_replace_callback('/\$\{(AK_.*?)\}/',array('Ak','_getConstant'),$settingsStr);
1995 function _getConstant($name)
1997 return defined($name[1])?
constant($name[1]):'';
2002 // Now some static functions that are needed by the whole framework
2004 function translate($string, $args = null, $controller = null)
2006 return Ak
::t($string, $args, $controller);
2010 function ak_test($test_case_name, $use_sessions = false)
2012 if(!defined('ALL_TESTS_CALL')){
2013 $use_sessions ? @session_start
() : null;
2014 $test = &new $test_case_name();
2015 if (defined('AK_CLI') && AK_CLI || TextReporter
::inCli() ||
(defined('AK_CONSOLE_MODE') && AK_CONSOLE_MODE
) ||
(defined('AK_WEB_REQUEST') && !AK_WEB_REQUEST
)) {
2016 $test->run(new TextReporter());
2018 $test->run(new HtmlReporter());
2023 function ak_compat($function_name)
2025 if(!function_exists($function_name)){
2026 require_once(AK_VENDOR_DIR
.DS
.'pear'.DS
.'PHP'.DS
.'Compat'.DS
.'Function'.DS
.$function_name.'.php');
2030 function ak_generate_mock($name)
2036 $Mock->generate($name);
2040 * This function sets a constant and returns it's value. If constant has been already defined it
2041 * will reutrn its original value.
2043 * Returns null in case the constant does not exist
2045 * @param string $name
2046 * @param mixed $value
2048 function ak_define($name, $value = null)
2050 $name = strtoupper($name);
2051 $name = substr($name,0,3) == 'AK_' ?
$name : 'AK_'.$name;
2052 return defined($name) ?
constant($name) : (is_null($value) ?
null : (define($name, $value) ?
$value : null));
2056 * PHP4 triggers "Only variable references should be returned by reference" error when
2057 * a method that should return an object reference returns a boolean/array
2059 * The old method was to use a global variables, but it can lead into hard to debug bugs.
2061 * Now you'll need to use the following technique if you whant to build functions that
2062 * can return Object references or TRUE/FALSE.
2069 * Globals are deprecated. Used ak_false, ak_true and ak_array instead
2073 $GLOBALS['false'] = false;
2074 $GLOBALS['true'] = true;
2077 AK_PHP5 ||
function_exists('clone') ?
null : eval('function clone($object){return $object;}');
2079 Ak
::profile('Ak.php class included'.__FILE__
);