php优秀框架codeigniter学习系列——common.php
文件位于system/core/common.php,是框架核心文件。
该文件中定义了一系列的函数,都是框架运行中经常需要用到的。下面逐一介绍。
is_php
1 /** 2 * Determines if the current version of PHP is equal to or greater than the supplied value 3 * 4 * @param string 5 * @return bool TRUE if the current version is $version or higher 6 */ 7 function is_php($version) 8 { 9 static $_is_php; 10 $version = (string) $version; 11 12 if ( ! isset($_is_php[$version])) 13 { 14 $_is_php[$version] = version_compare(PHP_VERSION, $version, \'>=\'); 15 } 16 17 return $_is_php[$version]; 18 } 19 }
该函数用于进行php版本比较,如果运行的php版本大于等于输入的php版本参数,则返回true。这里建立了一个$is_php静态数组,把新版本参数比较的结果存在数组里,如果再有类似的版本参数传入,不用比较,直接返回结果。是一种空间换时间的做法。
is_really_writable
1 /** 2 * Tests for file writability 3 * 4 * is_writable() returns TRUE on Windows servers when you really can\'t write to 5 * the file, based on the read-only attribute. is_writable() is also unreliable 6 * on Unix servers if safe_mode is on. 7 * 8 * @link https://bugs.php.net/bug.php?id=54709 9 * @param string 10 * @return bool 11 */ 12 function is_really_writable($file) 13 { 14 // If we\'re on a Unix server with safe_mode off we call is_writable 15 //用DIRECTORY_SEPARATOR === \'/\'来判断是unix系统, 16 if (DIRECTORY_SEPARATOR === \'/\' && (is_php(\'5.4\') OR ! ini_get(\'safe_mode\'))) 17 { 18 return is_writable($file); 19 } 20 21 /* For Windows servers and safe_mode "on" installations we\'ll actually 22 * write a file then read it. Bah... 23 * 对于windows操作系统和安全模式的处理方法 24 */ 25 if (is_dir($file))//对于目录 26 { 27 $file = rtrim($file, \'/\').\'/\'.md5(mt_rand()); 28 if (($fp = @fopen($file, \'ab\')) === FALSE) 29 { 30 return FALSE; 31 } 32 33 fclose($fp); 34 @chmod($file, 0777); 35 @unlink($file); 36 return TRUE; 37 } 38 elseif ( ! is_file($file) OR ($fp = @fopen($file, \'ab\')) === FALSE)//对于文件 39 { 40 return FALSE; 41 } 42 43 fclose($fp); 44 return TRUE; 45 }
该函数用于判断文件或目录是否可写。
对于linux系统未使用安全模式的情况,直接调用php函数is_writable($file)即可。
对于windows系统和使用安全模式的linux系统则根据是文件夹还是文件采取不同的方式:文件夹是 在看是否可在里面新建一个可读写的文件;文件是看是否可读写打开。
&load_class
1 /** 2 * Class registry 3 * 4 * This function acts as a singleton. If the requested class does not 5 * exist it is instantiated and set to a static variable. If it has 6 * previously been instantiated the variable is returned. 7 * 8 * @param string the class name being requested 9 * @param string the directory where the class should be found 10 * @param mixed an optional argument to pass to the class constructor 11 * @return object 12 */ 13 function &load_class($class, $directory = \'libraries\', $param = NULL) 14 { 15 static $_classes = array(); 16 17 // Does the class exist? If so, we\'re done... 18 if (isset($_classes[$class])) 19 { 20 return $_classes[$class]; 21 } 22 23 $name = FALSE; 24 25 // Look for the class first in the local application/libraries folder 26 // then in the native system/libraries folder 27 foreach (array(APPPATH, BASEPATH) as $path) 28 { 29 if (file_exists($path.$directory.\'/\'.$class.\'.php\')) 30 { 31 $name = \'CI_\'.$class; 32 33 if (class_exists($name, FALSE) === FALSE) 34 { 35 require_once($path.$directory.\'/\'.$class.\'.php\'); 36 } 37 38 break; 39 } 40 } 41 42 // Is the request a class extension? If so we load it too 43 if (file_exists(APPPATH.$directory.\'/\'.config_item(\'subclass_prefix\').$class.\'.php\')) 44 { 45 $name = config_item(\'subclass_prefix\').$class; 46 47 if (class_exists($name, FALSE) === FALSE) 48 { 49 require_once(APPPATH.$directory.\'/\'.$name.\'.php\'); 50 } 51 } 52 53 // Did we find the class? 54 if ($name === FALSE) 55 { 56 // Note: We use exit() rather than show_error() in order to avoid a 57 // self-referencing loop with the Exceptions class 58 set_status_header(503); 59 echo \'Unable to locate the specified class: \'.$class.\'.php\'; 60 exit(5); // EXIT_UNK_CLASS 61 } 62 63 // Keep track of what we just loaded 64 is_loaded($class); 65 66 $_classes[$class] = isset($param) 67 ? new $name($param) 68 : new $name(); 69 return $_classes[$class]; 70 } 71 }
该函数用于类的注册,核心函数。
这个函数维护一个单例模式,即如果请求注册的类$class已经被实例化过了,则把保存的实例化对象返回,如果没有实例化过,就实例化该类。这个做法避免新建大量的对象,减少内存消耗,也减少了框架使用对象的维护成本,避免使用的混乱。
在搜索类文件的时候,既会搜索系统的类文件,也会搜索用户自定义的类文件。用户自定义类名需要定义统一的前缀,这个前缀在application/config/config.php文件的subclass_prefix变量中定义。
该函数前面有一个&,表明是引用传递返回值。即返回的对象以后发生变化的时候,在这个函数中定义的$_classes[$class]也会发生变化。参考知乎上的解释。
&is_loaded($class = \'\')
/** * Keeps track of which libraries have been loaded. This function is * called by the load_class() function above * * @param string * @return array */ function &is_loaded($class = \'\') { static $_is_loaded = array(); if ($class !== \'\') { $_is_loaded[strtolower($class)] = $class; } return $_is_loaded; }
该函数可以获取已经在load_class函数中注册的类名数组,也可以往 类名数组中添加一个已经注册的类名。使用引用传递返回值。
&get_config(Array $replace = array())
1 /** 2 * Loads the main config.php file 3 * 4 * This function lets us grab the config file even if the Config class 5 * hasn\'t been instantiated yet 6 * 7 * @param array 8 * @return array 9 */ 10 function &get_config(Array $replace = array()) 11 { 12 static $config; 13 14 if (empty($config)) 15 { 16 $file_path = APPPATH.\'config/config.php\'; 17 $found = FALSE; 18 if (file_exists($file_path)) 19 { 20 $found = TRUE; 21 require($file_path); 22 } 23 24 // Is the config file in the environment folder? 25 if (file_exists($file_path = APPPATH.\'config/\'.ENVIRONMENT.\'/config.php\')) 26 { 27 require($file_path); 28 } 29 elseif ( ! $found) 30 { 31 set_status_header(503); 32 echo \'The configuration file does not exist.\'; 33 exit(3); // EXIT_CONFIG 34 } 35 36 // Does the $config array exist in the file? 37 if ( ! isset($config) OR ! is_array($config)) 38 { 39 set_status_header(503); 40 echo \'Your config file does not appear to be formatted correctly.\'; 41 exit(3); // EXIT_CONFIG 42 } 43 } 44 45 // Are any values being dynamically added or replaced? 46 foreach ($replace as $key => $val) 47 { 48 $config[$key] = $val; 49 } 50 51 return $config; 52 } 53 }
View Code
该函数用来加载application/config/config.php中的$config数组变量。当然,如果存在,也加载用户根据环境定义的config.php文件。
config.php文件中定义了一些系统和应用程序的设置,包括使用何种编码,是否采用csrf,自定义的类的类名前缀等等。
同时,使用该函数通过$replace也可以追加一些设置。
该函数使用静态局部变量数组$config来存储。使用引用传递返回值。
config_item($item)
1 /** 2 * Returns the specified config item 3 * 4 * @param string 5 * @return mixed 6 */ 7 function config_item($item) 8 { 9 static $_config; 10 11 if (empty($_config)) 12 { 13 // references cannot be directly assigned to static variables, so we use an array 14 $_config[0] =& get_config(); 15 } 16 17 return isset($_config[0][$item]) ? $_config[0][$item] : NULL; 18 }
该函数用于获取某一个具体的在get_config()中定义的$config数组的值。
&get_mimes()
1 /** 2 * Returns the MIME types array from config/mimes.php 3 * 4 * @return array 5 */ 6 function &get_mimes() 7 { 8 static $_mimes; 9 10 if (empty($_mimes)) 11 { 12 $_mimes = file_exists(APPPATH.\'config/mimes.php\') 13 ? include(APPPATH.\'config/mimes.php\') 14 : array(); 15 16 if (file_exists(APPPATH.\'config/\'.ENVIRONMENT.\'/mimes.php\')) 17 { 18 $_mimes = array_merge($_mimes, include(APPPATH.\'config/\'.ENVIRONMENT.\'/mimes.php\')); 19 } 20 } 21 22 return $_mimes; 23 }
该函数用于获取在application/config/mimes.php中定义的mime类型数组。主要用于文件上传时候的检测。
is_https()
1 /** 2 * Is HTTPS? 3 * 4 * Determines if the application is accessed via an encrypted 5 * (HTTPS) connection. 6 * 7 * @return bool 8 */ 9 function is_https() 10 { 11 if ( ! empty($_SERVER[\'HTTPS\']) && strtolower($_SERVER[\'HTTPS\']) !== \'off\') 12 { 13 return TRUE; 14 } 15 elseif (isset($_SERVER[\'HTTP_X_FORWARDED_PROTO\']) && strtolower($_SERVER[\'HTTP_X_FORWARDED_PROTO\']) === \'https\') 16 { 17 return TRUE; 18 } 19 elseif ( ! empty($_SERVER[\'HTTP_FRONT_END_HTTPS\']) && strtolower($_SERVER[\'HTTP_FRONT_END_HTTPS\']) !== \'off\') 20 { 21 return TRUE; 22 } 23 24 return FALSE; 25 }
该函数判断请求是否是http请求。
is_cli()
1 /** 2 * Is CLI? 3 * 4 * Test to see if a request was made from the command line. 5 * 6 * @return bool 7 */ 8 function is_cli() 9 { 10 return (PHP_SAPI === \'cli\' OR defined(\'STDIN\')); 11 }
该函数用于判断请求是否是命令行方式。
show_error($message, $status_code = 500, $heading = \'An Error Was Encountered\')
1 /** 2 * Error Handler 3 * 4 * This function lets us invoke the exception class and 5 * display errors using the standard error template located 6 * in application/views/errors/error_general.php 7 * This function will send the error page directly to the 8 * browser and exit. 9 * 10 * @param string 11 * @param int 12 * @param string 13 * @return void 14 */ 15 function show_error($message, $status_code = 500, $heading = \'An Error Was Encountered\') 16 { 17 $status_code = abs($status_code);//取绝对值 18 if ($status_code < 100) 19 { 20 $exit_status = $status_code + 9; // 9 is EXIT__AUTO_MIN 21 $status_code = 500; 22 } 23 else 24 { 25 $exit_status = 1; // EXIT_ERROR 26 } 27 28 $_error =& load_class(\'Exceptions\', \'core\'); 29 echo $_error->show_error($heading, $message, \'error_general\', $status_code); 30 exit($exit_status); 31 }
该函数用于主动显示一个错误提示给用户,无论是命令行模式还是浏览器显示。调用的是Exceptions类的show_error方法。
show_404($page = \'\', $log_error = TRUE)
1 /** 2 * 404 Page Handler 3 * 4 * This function is similar to the show_error() function above 5 * However, instead of the standard error template it displays 6 * 404 errors. 7 * 8 * @param string 9 * @param bool 10 * @return void 11 */ 12 function show_404($page = \'\', $log_error = TRUE) 13 { 14 $_error =& load_class(\'Exceptions\', \'core\'); 15 $_error->show_404($page, $log_error); 16 exit(4); // EXIT_UNKNOWN_FILE 17 }
该函数用于主动显示一个404错误给用户,无论是命令行模式还是浏览器显示。调用的是Exceptions类的show_404方法。
log_message($level, $message)
1 /** 2 * Error Logging Interface 3 * 4 * We use this as a simple mechanism to access the logging 5 * class and send messages to be logged. 6 * 7 * @param string the error level: \'error\', \'debug\' or \'info\' 8 * @param string the error message 9 * @return void 10 */ 11 function log_message($level, $message) 12 { 13 static $_log; 14 15 if ($_log === NULL) 16 { 17 // references cannot be directly assigned to static variables, so we use an array 18 $_log[0] =& load_class(\'Log\', \'core\'); 19 } 20 21 $_log[0]->write_log($level, $message); 22 }
该函数用于记录日志。常用的函数。日志分Error,Debug,Info三个级别。调用的是Log类的write_log方法。
set_status_header($code = 200, $text = \'\')
1 /** 2 * Set HTTP Status Header 3 * 4 * @param int the status code 5 * @param string 6 * @return void 7 */ 8 function set_status_header($code = 200, $text = \'\') 9 { 10 if (is_cli()) 11 { 12 return; 13 } 14 15 if (empty($code) OR ! is_numeric($code)) 16 { 17 show_error(\'Status codes must be numeric\', 500); 18 } 19 20 if (empty($text)) 21 { 22 is_int($code) OR $code = (int) $code; 23 $stati = array( 24 100 => \'Continue\', 25 101 => \'Switching Protocols\', 26 27 200 => \'OK\', 28 201 => \'Created\', 29 202 => \'Accepted\', 30 203 => \'Non-Authoritative Information\', 31 204 => \'No Content\', 32 205 => \'Reset Content\', 33 206 => \'Partial Content\', 34 35 300 => \'Multiple Choices\', 36 301 => \'Moved Permanently\', 37 302 => \'Found\', 38 303 => \'See Other\', 39 304 => \'Not Modified\', 40 305 => \'Use Proxy\', 41 307 => \'Temporary Redirect\', 42 43 400 => \'Bad Request\', 44 401 => \'Unauthorized\', 45 402 => \'Payment Required\', 46 403 => \'Forbidden\', 47 404 => \'Not Found\', 48 405 => \'Method Not Allowed\', 49 406 => \'Not Acceptable\', 50 407 => \'Proxy Authentication Required\', 51 408 => \'Request Timeout\', 52 409 => \'Conflict\', 53 410 => \'Gone\', 54 411 => \'Length Required\', 55 412 => \'Precondition Failed\', 56 413 => \'Request Entity Too Large\', 57 414 => \'Request-URI Too Long\', 58 415 => \'Unsupported Media Type\', 59 416 => \'Requested Range Not Satisfiable\', 60 417 => \'Expectation Failed\', 61 422 => \'Unprocessable Entity\', 62 426 => \'Upgrade Required\', 63 428 => \'Precondition Required\', 64 429 => \'Too Many Requests\', 65 431 => \'Request Header Fields Too Large\', 66 67 500 => \'Internal Server Error\', 68 501 => \'Not Implemented\', 69 502 => \'Bad Gateway\', 70 503 => \'Service Unavailable\', 71 504 => \'Gateway Timeout\', 72 505 => \'HTTP Version Not Supported\', 73 511 => \'Network Authentication Required\', 74 ); 75 76 if (isset($stati[$code])) 77 { 78 $text = $stati[$code]; 79 } 80 else 81 { 82 show_error(\'No status text available. Please check your status code number or supply your own message text.\', 500); 83 } 84 } 85 86 if (strpos(PHP_SAPI, \'cgi\') === 0) 87 { 88 header(\'Status: \'.$code.\' \'.$text, TRUE); 89 return; 90 } 91 92 $server_protocol = (isset($_SERVER[\'SERVER_PROTOCOL\']) && in_array($_SERVER[\'SERVER_PROTOCOL\'], array(\'HTTP/1.0\', \'HTTP/1.1\', \'HTTP/2\'), TRUE)) 93 ? $_SERVER[\'SERVER_PROTOCOL\'] : \'HTTP/1.1\'; 94 header($server_protocol.\' \'.$code.\' \'.$text, TRUE, $code); 95 }
手动设置返回的http头,如果设置的是“500”。那么浏览器解析的Status Code就是500。
_error_handler($severity, $message, $filepath, $line)
1 /** 2 * Error Handler 3 * 4 * This is the custom error handler that is declared at the (relative) 5 * top of CodeIgniter.php. The main reason we use this is to permit 6 * PHP errors to be logged in our own log files since the user may 7 * not have access to server logs. Since this function effectively 8 * intercepts PHP errors, however, we also need to display errors 9 * based on the current error_reporting level. 10 * We do that with the use of a PHP error template. 11 * 12 * @param int $severity 13 * @param string $message 14 * @param string $filepath 15 * @param int $line 16 * @return void 17 */ 18 function _error_handler($severity, $message, $filepath, $line) 19 { 20 $is_error = (((E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity); 21 22 // When an error occurred, set the status header to \'500 Internal Server Error\' 23 // to indicate to the client something went wrong. 24 // This can\'t be done within the $_error->show_php_error method because 25 // it is only called when the display_errors flag is set (which isn\'t usually 26 // the case in a production environment) or when errors are ignored because 27 // they are above the error_reporting threshold. 28 if ($is_error) 29 { 30 set_status_header(500); 31 } 32 33 // Should we ignore the error? We\'ll get the current error_reporting 34 // level and add its bits with the severity bits to find out. 35 if (($severity & error_reporting()) !== $severity) 36 { 37 return; 38 } 39 40 $_error =& load_class(\'Exceptions\', \'core\'); 41 $_error->log_exception($severity, $message, $filepath, $line); 42 43 // Should we display the error? 44 if (str_ireplace(array(\'off\', \'none\', \'no\', \'false\', \'null\'), \'\', ini_get(\'display_errors\'))) 45 { 46 $_error->show_php_error($severity, $message, $filepath, $line); 47 } 48 49 // If the error is fatal, the execution of the script should be stopped because 50 // errors can\'t be recovered from. Halting the script conforms with PHP\'s 51 // default error handling. See http://www.php.net/manual/en/errorfunc.constants.php 52 if ($is_error) 53 { 54 exit(1); // EXIT_ERROR 55 } 56 }
该函数是在CodeIgniter.php中使用set_error_handler设置的用户自定义错误处理函数。该函数用于处理脚本中出现的错误。值得说明的是,以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING。所以即使不小心进入了这个方法,也需要屏蔽掉。
对于在函数前加了@屏蔽warning的函数,也会进入这个方法。但是它的error_reporting()返回值是0,而不管系统设置的是什么。可以由此来判断直接返回,不做处理。
$severity包含了错误的级别,是一个 integer。
调用Exceptions类的show_php_error方法。
_exception_handler($exception)
1 /** 2 * Exception Handler 3 * 4 * Sends uncaught exceptions to the logger and displays them 5 * only if display_errors is On so that they don\'t show up in 6 * production environments. 7 * 8 * @param Exception $exception 9 * @return void 10 */ 11 function _exception_handler($exception) 12 { 13 $_error =& load_class(\'Exceptions\', \'core\'); 14 $_error->log_exception(\'error\', \'Exception: \'.$exception->getMessage(), $exception->getFile(), $exception->getLine()); 15 16 is_cli() OR set_status_header(500); 17 // Should we display the error? 18 if (str_ireplace(array(\'off\', \'none\', \'no\', \'false\', \'null\'), \'\', ini_get(\'display_errors\'))) 19 { 20 $_error->show_exception($exception); 21 } 22 23 exit(1); // EXIT_ERROR 24 }
该函数是在CodeIgniter.php中使用set_exception_handler设置的用户自定义异常处理函数。该函数是记录异常到日志中,并且展示给用户看到该异常。
set_error_handler和set_exception_handler的不同参见网上资料。
_shutdown_handler()
1 /** 2 * Shutdown Handler 3 * 4 * This is the shutdown handler that is declared at the top 5 * of CodeIgniter.php. The main reason we use this is to simulate 6 * a complete custom exception handler. 7 * 8 * E_STRICT is purposively neglected because such events may have 9 * been caught. Duplication or none? None is preferred for now. 10 * 11 * @link http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a 12 * @return void 13 */ 14 function _shutdown_handler() 15 { 16 $last_error = error_get_last(); 17 if (isset($last_error) && 18 ($last_error[\'type\'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING))) 19 { 20 _error_handler($last_error[\'type\'], $last_error[\'message\'], $last_error[\'file\'], $last_error[\'line\']); 21 } 22 }
该函数是在CodeIgniter.php中使用register_shutdown_function 注册的会在php中止时执行的函数。
remove_invisible_characters($str, $url_encoded = TRUE)
1 /** 2 * Remove Invisible Characters 3 * 4 * This prevents sandwiching null characters 5 * between ascii characters, like Java\0script. 6 * 7 * @param string 8 * @param bool 9 * @return string 10 */ 11 function remove_invisible_characters($str, $url_encoded = TRUE) 12 { 13 $non_displayables = array(); 14 15 // every control character except newline (dec 10), 16 // carriage return (dec 13) and horizontal tab (dec 09) 17 if ($url_encoded) 18 { 19 $non_displayables[] = \'/%0[0-8bcef]/i\'; // url encoded 00-08, 11, 12, 14, 15 20 $non_displayables[] = \'/%1[0-9a-f]/i\'; // url encoded 16-31 21 $non_displayables[] = \'/%7f/i\'; // url encoded 127 22 } 23 24 $non_displayables[] = \'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S\'; // 00-08, 11, 12, 14-31, 127 25 26 do 27 { 28 $str = preg_replace($non_displayables, \'\', $str, -1, $count); 29 } 30 while ($count); 31 32 return $str; 33 }
该函数用于清除字符串中的不可见字符。 $non_displayables[] = \'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S\'; 会匹配ascII中00-08, 11, 12, 14-31, 127的字符,这些字符都是不可见的。参见ascII字符表。
html_escape($var, $double_encode = TRUE)
1 /** 2 * Returns HTML escaped variable. 3 * 4 * @param mixed $var The input string or array of strings to be escaped. 5 * @param bool $double_encode $double_encode set to FALSE prevents escaping twice. 6 * @return mixed The escaped string or array of strings as a result. 7 */ 8 function html_escape($var, $double_encode = TRUE) 9 { 10 if (empty($var)) 11 { 12 return $var; 13 } 14 15 if (is_array($var)) 16 { 17 foreach (array_keys($var) as $key) 18 { 19 $var[$key] = html_escape($var[$key], $double_encode); 20 } 21 22 return $var; 23 } 24 25 return htmlspecialchars($var, ENT_QUOTES, config_item(\'charset\'), $double_encode); 26 }
该函数用于将字符串或者字符串数组转换为html实体。
_stringify_attributes($attributes, $js = FALSE)
1 /** 2 * Stringify attributes for use in HTML tags. 3 * 4 * Helper function used to convert a string, array, or object 5 * of attributes to a string. 6 * 7 * @param mixed string, array, object 8 * @param bool 9 * @return string 10 */ 11 function _stringify_attributes($attributes, $js = FALSE) 12 { 13 $atts = NULL; 14 15 if (empty($attributes)) 16 { 17 return $atts; 18 } 19 20 if (is_string($attributes)) 21 { 22 return \' \'.$attributes; 23 } 24 25 $attributes = (array) $attributes; 26 27 foreach ($attributes as $key => $val) 28 { 29 $atts .= ($js) ? $key.\'=\'.$val.\',\' : \' \'.$key.\'="\'.$val.\'"\'; 30 } 31 32 return rtrim($atts, \',\'); 33 }
View Code
将一个字符串属性,数组属性或者对象属性转换为一个字符串。主要用于在显示html页面的时候使用。
function_usable($function_name)
1 /** 2 * Function usable 3 * 4 * Executes a function_exists() check, and if the Suhosin PHP 5 * extension is loaded - checks whether the function that is 6 * checked might be disabled in there as well. 7 * 8 * This is useful as function_exists() will return FALSE for 9 * functions disabled via the *disable_functions* php.ini 10 * setting, but not for *suhosin.executor.func.blacklist* and 11 * *suhosin.executor.disable_eval*. These settings will just 12 * terminate script execution if a disabled function is executed. 13 * 14 * The above described behavior turned out to be a bug in Suhosin, 15 * but even though a fix was committed for 0.9.34 on 2012-02-12, 16 * that version is yet to be released. This function will therefore 17 * be just temporary, but would probably be kept for a few years. 18 * 19 * @link http://www.hardened-php.net/suhosin/ 20 * @param string $function_name Function to check for 21 * @return bool TRUE if the function exists and is safe to call, 22 * FALSE otherwise. 23 */ 24 function function_usable($function_name) 25 { 26 static $_suhosin_func_blacklist; 27 28 if (function_exists($function_name)) 29 { 30 if ( ! isset($_suhosin_func_blacklist)) 31 { 32 $_suhosin_func_blacklist = extension_loaded(\'suhosin\') 33 ? explode(\',\', trim(ini_get(\'suhosin.executor.func.blacklist\'))) 34 : array(); 35 } 36 37 return ! in_array($function_name, $_suhosin_func_blacklist, TRUE); 38 } 39 40 return FALSE; 41 }
函数功能类似于function_exist(),不过在外面包装了一层,还需要检查下函数是否在suhosin.executor.func.blacklist中(类似于黑名单?),如果在还是会返回false。