| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4 // +----------------------------------------------------------------------+ 5 // | Akelos Framework - http://www.akelos.org | 6 // +----------------------------------------------------------------------+ 7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez | 8 // | Released under the GNU Lesser General Public License, see LICENSE.txt| 9 // +----------------------------------------------------------------------+ 10 11 /** 12 * @package ActionView 13 * @subpackage TemplateEngines 14 * @author Bermi Ferrer <bermi a.t akelos c.om> 15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org 16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> 17 */ 18 19 /** 20 * The AkPhpCodeSanitizer ensures that Action View templates do not contain illegal function/variable calls 21 * it is used by the AkPhpTemplateHander by default. If you want to stablish your own 22 * set of forbidden functionalities extend this class and set AK_PHP_CODE_SANITIZER_FOR_TEMPLATE_HANDLER 23 * with the name of your newly created class. 24 */ 25 class AkPhpCodeSanitizer 26 { 27 var $Analyzer; 28 var $_invalid = array(); 29 var $secure_active_record_method_calls = false; 30 var $_errors = array(); 31 var $_options = array(); 32 var $_protedted_types = array('constructs','variables','member variables','functions','classes','methods'); 33 34 function clearErrors() 35 { 36 $this->_errors = array(); 37 $this->_invalid = array(); 38 } 39 40 function setOptions($options) 41 { 42 $this->_options = $options; 43 } 44 45 function isCodeSecure($code =null, $raise_if_insecure = true) 46 { 47 $this->clearErrors(); 48 if(empty($code) && isset($this->_options['code'])){ 49 $code =& $this->_options['code']; 50 } 51 $this->AnalyzeCode($code); 52 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_VARIABLES') || !AK_PHP_CODE_SANITIZER_SKIP_VARIABLES){ 53 $this->secureVariables($code); 54 } 55 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_FUNCTIONS') || !AK_PHP_CODE_SANITIZER_SKIP_FUNCTIONS){ 56 $this->secureFunctions($code); 57 } 58 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_CONSTRUCTS') || !AK_PHP_CODE_SANITIZER_SKIP_CONSTRUCTS){ 59 $this->secureConstructs($code); 60 } 61 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_CLASSES') || !AK_PHP_CODE_SANITIZER_SKIP_CLASSES){ 62 $this->secureClasses($code); 63 } 64 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_PROTECTED_TYPES') || !AK_PHP_CODE_SANITIZER_SKIP_PROTECTED_TYPES){ 65 $this->secureProtectedTypes($code); 66 } 67 68 if(!empty($this->_errors)){ 69 if($raise_if_insecure){ 70 $this->raiseError(); 71 } 72 return false; 73 } 74 75 return true; 76 } 77 78 function raiseError($code = null) 79 { 80 $code = empty($code) ? @$this->_options['code'] : $code; 81 if(AK_DEBUG){ 82 // We can't halt execution while testing and the error message is too large for trigger_error 83 if(AK_ENVIRONMENT == 'testing'){ 84 trigger_error(join("\n", $this->getErrors()), E_USER_WARNING); 85 }else{ 86 echo 87 '<h1>'.Ak::t('Template %template_file security error', array('%template_file'=>@$this->_options['file_path'])).':</h1>'. 88 "<ul><li>".join("</li>\n<li>",$this->getErrors())."</li></ul><hr />\n". 89 '<h2>'.Ak::t('Showing template source from %file:',array('%file'=>$this->_options['file_path'])).'</h2>'. 90 (isset($this->_options['file_path']) ? '<pre>'.htmlentities(Ak::file_get_contents($this->_options['file_path'])).'</pre><hr />':''). 91 '<h2>'.Ak::t('Showing compiled template source:').'</h2>'.highlight_string($code,true); 92 93 die(); 94 } 95 }else{ 96 trigger_error(Ak::t('Template compilation error'),E_USER_ERROR); 97 } 98 } 99 100 function getErrors() 101 { 102 return $this->_errors; 103 } 104 105 function _addDollarSymbol_(&$var) 106 { 107 if($var[0] != "$") { 108 $var = "$".$var; 109 } 110 } 111 112 function secureVariables($code) 113 { 114 $_forbidden['variables'] = empty($this->_options['forbidden_variables']) ? 115 array_unique(array_merge(array_keys($GLOBALS), array_keys(get_defined_vars()))) : 116 $this->_options['forbidden_variables']; 117 118 array_map(array(&$this,'_addDollarSymbol_'), $_forbidden['variables']); 119 120 $_used_vars = array_keys((array)$this->Analyzer->usedVariables); 121 122 if(!defined('AK_PHP_CODE_SANITIZER_SKIP_MEMBER_VARIABLES') || !AK_PHP_CODE_SANITIZER_SKIP_MEMBER_VARIABLES){ 123 $this->lookForPrivateMemberVariables($this->Analyzer->usedMemberVariables); 124 } 125 126 $this->_invalid['variables'] = array_diff($_used_vars, array_diff($_used_vars,array_merge($_forbidden['variables'], array_filter($_used_vars, array(&$this, 'isPrivateVar'))))); 127 } 128 129 function secureFunctions($code = null) 130 { 131 if(!empty($this->Analyzer->createdFunctions)){ 132 $this->_errors[] = Ak::t('You can\'t create functions within templates'); 133 } 134 $_used_functions = array_merge(array_keys((array)@$this->Analyzer->calledFunctions),array_keys((array)@$this->Analyzer->calledConstructs)); 135 136 $_forbidden['functions'] = array_merge($this->getForbiddenFunctions(),$this->_getFuntionsAsVariables($_used_functions)); 137 $this->_invalid['functions'] = array_diff($_used_functions, array_diff($_used_functions,$_forbidden['functions'])); 138 } 139 140 function secureClasses($code = null) 141 { 142 if(!empty($this->Analyzer->createdClasses)){ 143 $this->_errors[] = Ak::t('You can\'t create classes within templates'); 144 } 145 if(!empty($this->Analyzer->classesInstantiated)){ 146 $this->_errors[] = Ak::t('You can\'t instantiate classes within templates'); 147 } 148 $this->_invalid['classes'] = array_diff(array_keys((array)$this->Analyzer->calledStaticMethods),(array)@$this->_options['classes']); 149 150 $_class_calls = array_merge((array)$this->Analyzer->calledStaticMethods, (array)@$this->Analyzer->calledMethods); 151 $forbidden_methods = array_merge($this->getForbiddenMethods(),(array)@$this->_options['forbidden_methods']); 152 foreach ($_class_calls as $_class_name=>$_method_calls){ 153 foreach (array_keys($_method_calls) as $_method_call){ 154 if(empty($_method_call)){ 155 continue; 156 } 157 $_method_name = $_class_name.($_class_name[0]=='$'?'->':'::').$_method_call; 158 if($_method_call[0] === '_' || $_method_call[0] === '$' || in_array($_method_call, $forbidden_methods)){ 159 $this->_invalid['methods'][] = $_method_name; 160 } 161 } 162 } 163 } 164 165 function secureConstructs($code = null) 166 { 167 if(!empty($this->Analyzer->filesIncluded)){ 168 $this->_errors[] = Ak::t('You can\'t include files within templates using PHP include or require please use $this->render() instead'); 169 } 170 $_used_constructs = array_keys((array)$this->Analyzer->calledConstructs); 171 $this->_invalid['constructs'] = array_diff($_used_constructs, array_diff($_used_constructs, empty($this->_options['forbidden_constructs']) ? array('include','include_once','require','require_once') : 172 $this->_options['forbidden_constructs'])); 173 } 174 175 176 function secureProtectedTypes() 177 { 178 foreach ($this->_protedted_types as $_type){ 179 if(!empty($this->_invalid[$_type])){ 180 $this->_invalid[$_type] = array_diff($this->_invalid[$_type],(array)@$this->_options[$_type]); 181 } 182 if(!empty($this->_invalid[$_type])){ 183 array_unique($this->_invalid[$_type]); 184 sort($this->_invalid[$_type]); 185 $this->_errors[] = Ak::t('You can\'t use the following %type within templates:',array('%type'=>Ak::t($_type))).' '.join(', ',$this->_invalid[$_type]); 186 } 187 } 188 } 189 190 function isPrivateVar($var) 191 { 192 return preg_match('/^["\'${\.]*_/', $var); 193 } 194 195 function isPrivateDynamicVar($var) 196 { 197 if(preg_match('/^["\'{\.]*\$/', $var)){ 198 $var_name = trim($var, '{"\'.$'); 199 if(isset($GLOBALS[$var_name])){ 200 return $this->isPrivateVar($GLOBALS[$var_name]); 201 } 202 return true; 203 } 204 return false; 205 } 206 207 function lookForPrivateMemberVariables($var, $nested = false) 208 { 209 if(is_string($var) && $this->isPrivateVar($var)){ 210 $this->_invalid['member variables'][$var] = $var; 211 return true; 212 }elseif (is_array($var)){ 213 foreach (array_keys($var) as $k){ 214 if($this->isPrivateVar($k) || ($nested && $this->isPrivateDynamicVar($k))){ 215 $this->_invalid['member variables'][$k] = $k; 216 return true; 217 }elseif($this->lookForPrivateMemberVariables($var[$k], true)){ 218 return true; 219 } 220 } 221 }elseif (is_object($var)){ 222 return $this->lookForPrivateMemberVariables((array)$var, true); 223 } 224 return false; 225 } 226 227 function &getCodeAnalyzerInstance() 228 { 229 if(empty($this->Analyzer)){ 230 require_once(AK_CONTRIB_DIR.DS.'PHPCodeAnalyzer'.DS.'PHPCodeAnalyzer.php'); 231 $this->Analyzer =& new PHPCodeAnalyzer(); 232 } 233 return $this->Analyzer; 234 } 235 236 function AnalyzeCode($code) 237 { 238 $this->Analyzer =& $this->getCodeAnalyzerInstance(); 239 $this->Analyzer->source = '?>'.$code.'<?php'; 240 $this->Analyzer->analyze(); 241 return $this->Analyzer; 242 } 243 244 function _getFuntionsAsVariables($functions_array) 245 { 246 $result = array(); 247 foreach ((array)$functions_array as $function){ 248 if(isset($function[0]) && $function[0] == '$'){ 249 $result[] = $function; 250 } 251 } 252 return $result; 253 } 254 255 function getForbiddenMethods() 256 { 257 return !$this->secure_active_record_method_calls ? array() : array('init','setAccessibleAttributes','setProtectedAttributes','getConnection','setConnection','create','update','updateAttribute','updateAttributes','updateAll','delete','deleteAll','destroy','destroyAll','establishConnection','freeze','isFrozen','setInheritanceColumn','getColumnsWithRegexBoundaries','instantiate','getSubclasses','setAttribute','set','setAttributes','removeAttributesProtectedFromMassAssignment','cloneRecord','decrementAttribute','decrementAndSaveAttribute','incrementAttribute','incrementAndSaveAttribute','hasAttributesDefined','reload','save','createOrUpdate','toggleAttribute','toggleAttributeAndSave','setId','getAttributesBeforeTypeCast','getAttributeBeforeTypeCast','setPrimaryKey','resetColumnInformation','setSerializeAttribute','getSerializedAttributes','getAvailableCombinedAttributes','getAvailableAttributes','loadColumnsSettings','setColumnSettings','setAttributeByLocale','setAttributeLocales','initiateAttributeToNull','initiateColumnsToNull','getAkelosDataType','getClassForDatabaseTableMapping','setTableName','setDisplayField','debug','castAttributeForDatabase','castAttributeFromDatabase','isLockingEnabled','beforeCreate','beforeValidation','beforeValidationOnCreate','beforeValidationOnUpdate','beforeSave','beforeUpdate','afterUpdate','afterValidation','afterValidationOnCreate','afterValidationOnUpdate','afterCreate','afterDestroy','beforeDestroy','afterSave','transactionStart','transactionComplete','transactionFail','transactionHasFailed','validatesConfirmationOf','validatesAcceptanceOf','validatesAssociated','validatesPresenceOf','validatesLengthOf','validatesSizeOf','validatesUniquenessOf','validatesFormatOf','validatesInclusionOf','validatesExclusionOf','validatesNumericalityOf','validate','validateOnCreate','validateOnUpdate','notifyObservers','setObservableState','getObservableState','addObserver','getObservers','addErrorToBase','addError','addErrorOnEmpty','addErrorOnBlank','addErrorOnBoundaryBreaking','addErrorOnBoundryBreaking','clearErrors','actsAs','actsLike','dbug','sqlSelectOne','sqlSelectValue','sqlSelectValues','sqlSelectAll','sqlSelect'); 258 } 259 260 function getForbiddenFunctions() 261 { 262 return array('__halt_compiler','aggregate','aggregate_methods','aggregate_methods_by_list','aggregate_methods_by_regexp','aggregate_properties','aggregate_properties_by_list','aggregate_properties_by_regexp','aggregation_info','apache_child_terminate','apache_get_modules','apache_get_version','apache_getenv','apache_lookup_uri','apache_note','apache_request_headers','apache_reset_timeout','apache_response_headers','apache_setenv','ascii2ebcdic','basename','call_user_func','call_user_func_array','call_user_method','call_user_method_array','chdir','chgrp','chmod','chown','chroot','class_exists','clearstatcache','closedir','closelog','com_addref','com_event_sink','com_get','com_invoke','com_invoke_ex','com_isenum','com_load','com_load_typelib','com_message_pump','com_print_typeinfo','com_propget','com_propput','com_propset','com_release','com_set','compact','connection_aborted','connection_status','connection_timeout','constant','copy','crc32','create_function','deaggregate','debug_backtrace','debug_zval_dump','define','define_syslog_variables','defined','delete','dio_close','dio_fcntl','dio_open','dio_read','dio_seek','dio_stat','dio_tcsetattr','dio_truncate','dio_write','dir','dirname','disk_free_space','disk_total_space','diskfreespace','dl','ebcdic2ascii','error_log','error_reporting','escapeshellarg','escapeshellcmd','eval','exec','extension_loaded','extract','fclose','feof','fflush','fgetc','fgetcsv','fgets','fgetss','file','file_exists','file_get_contents','file_put_contents','fileatime','filectime','filegroup','fileinode','filemtime','fileowner','fileperms','filesize','filetype','flock','flush','fmod','fnmatch','fopen','fpassthru','fputcsv','fputs','fread','fscanf','fseek','fsockopen','fstat','ftell','ftruncate','func_get_arg','func_get_args','func_num_args','function_exists','fwrite','gd_info','get_browser','get_cfg_var','get_class','get_class_methods','get_class_vars','get_current_user','get_declared_classes','get_defined_constants','get_defined_functions','get_defined_vars','get_extension_funcs','get_include_path','get_included_files','get_loaded_extensions','get_magic_quotes_gpc','get_magic_quotes_runtime','get_meta_tags','get_object_vars','get_parent_class','get_required_files','get_resource_type','getallheaders','getcwd','getenv','getmygid','getmyinode','getmypid','getmyuid','glob','gzclose','gzcompress','gzdeflate','gzencode','gzeof','gzfile','gzgetc','gzgets','gzgetss','gzinflate','gzopen','gzpassthru','gzputs','gzread','gzrewind','gzseek','gztell','gzuncompress','gzwrite','header','headers_sent','highlight_file','html_doc','html_doc_file','ignore_user_abort','import_request_variables','ini_alter','ini_get','ini_get_all','ini_restore','ini_set','is_dir','is_executable','is_file','is_link','is_readable','is_uploaded_file','is_writable','is_writeable','link','linkinfo','log','log10','lstat','magic_quotes_runtime','mail','md5_file','mkdir','move_uploaded_file','ob_clean','ob_end_clean','ob_end_flush','ob_flush','ob_get_clean','ob_get_contents','ob_get_flush','ob_get_length','ob_get_level','ob_get_status','ob_gzhandler','ob_implicit_flush','ob_list_handlers','ob_start','opendir','openlog','output_add_rewrite_var','output_reset_rewrite_vars','overload','pack','parse_ini_file','parse_str','parse_url','passthru','pathinfo','pclose','pfsockopen','php_check_syntax','php_ini_scanned_files','php_logo_guid','php_sapi_name','php_strip_whitespace','php_uname','phpcredits','phpinfo','phpversion','png2wbmp','popen','preg_replace_callback','proc_close','proc_get_status','proc_nice','proc_open','proc_terminate','putenv','readdir','readfile','readgzfile','readlink','realpath','register_shutdown_function','register_tick_function','rename','restore_error_handler','restore_include_path','rewind','rewinddir','rmdir','scandir','session_cache_expire','session_cache_limiter','session_commit','session_decode','session_destroy','session_encode','session_get_cookie_params','session_id','session_is_registered','session_module_name','session_name','session_regenerate_id','session_register','session_save_path','session_set_cookie_params','session_set_save_handler','session_start','session_unregister','session_unset','session_write_close','set_error_handler','set_file_buffer','set_include_path','set_magic_quotes_runtime','set_socket_blocking','set_time_limit','setcookie','setlocale','settype','shell_exec','shmop_close','shmop_delete','shmop_open','shmop_read','shmop_size','shmop_write','show_source','similar_text','sleep','socket_accept','socket_bind','socket_clear_error','socket_close','socket_connect','socket_create','socket_create_listen','socket_create_pair','socket_get_option','socket_get_status','socket_getopt','socket_getpeername','socket_getsockname','socket_iovec_add','socket_iovec_alloc','socket_iovec_delete','socket_iovec_fetch','socket_iovec_free','socket_iovec_set','socket_last_error','socket_listen','socket_read','socket_readv','socket_recv','socket_recvfrom','socket_select','socket_send','socket_sendmsg','socket_sendto','socket_set_block','socket_set_blocking','socket_set_nonblock','socket_set_option','socket_set_timeout','socket_setopt','socket_shutdown','socket_strerror','socket_write','socket_writev','stat','stream_context_create','stream_context_get_options','stream_context_set_option','stream_context_set_params','stream_filter_append','stream_filter_prepend','stream_get_meta_data','stream_register_wrapper','stream_select','stream_set_blocking','stream_set_timeout','stream_set_write_buffer','stream_wrapper_register','symlink','syslog','system','tempnam','time_nanosleep','time_sleep_until','tmpfile','token_get_all','token_name','touch','trigger_error','umask','uniqid','unlink','unpack','unregister_tick_function','user_error','usleep','virtual','zend_get_cfg_var','zend_loader_current_file','zend_loader_enabled','zend_loader_file_encoded','zend_loader_file_licensed','zend_loader_install_license','zend_logo_guid','zend_version'); 263 } 264 } 265 266 267 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Oct 27 12:43:49 2008 | Cross-referenced by PHPXref 0.6 |