
CodeIgniter 全局公共函数完全指南从 is_php 到 function_usable 的源码级解析【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniterCodeIgniter本仓库为 EllisLab 起源的开源 PHP 框架内置了一组全局定义的公共函数它们在框架启动时随system/core/Common.php一并加载不需要加载任何库或 Helper 即可在应用任何位置直接调用。本文以官方文档 common_functions.rst 为主线逐一对 13 个核心公共函数进行参数说明、代码示例与底层源码剖析并穿插本仓库的真实测试用例帮助你彻底掌握这些隐形基础设施写出更健壮、更安全的 CodeIgniter 3 应用。一、公共函数概览它们从哪来、何时可用CodeIgniter 的公共函数与类库不同它们不是通过$this-load-library()加载的对象方法而是全局命名空间下的过程式函数。其唯一实现文件位于仓库的 system/core/Common.php由前端控制器 index.php 引导时引入经由system/core/CodeIgniter.php初始化流程因此从框架入口到应用退出整个生命周期内随处可调用。从源码结构看Common.php中几乎每个函数都用if ( ! function_exists(xxx))包裹定义这意味着你可以放心地在application/core/下覆盖这些函数框架不会产生重复定义冲突——这为高级定制留下了明确的扩展口。官方文档将公共函数分为三大用途用途分类函数环境与运行时检测is_php()、is_cli()、is_https()文件与配置访问is_really_writable()、config_item()、get_mimes()安全消毒与输入处理remove_invisible_characters()、html_escape()、function_usable()错误处理与日志show_error()、show_404()、log_message()HTTP 响应控制set_status_header()下文逐一展开。二、环境与运行时检测函数1.is_php($version)判断当前 PHP 版本参数string $version—— 要比较的版本号字符串例如5.5返回值bool—— 当前 PHP 版本大于等于指定版本时返回TRUE否则返回FALSE官方示例if (is_php(5.5)) { echo json_last_error_msg(); }源码剖析Common.phpfunction is_php($version) { static $_is_php; $version (string) $version; if ( ! isset($_is_php[$version])) { $_is_php[$version] version_compare(PHP_VERSION, $version, ); } return $_is_php[$version]; }两个关键实现细节值得注意底层基于 PHP 原生version_compare(..., )做语义化版本比较5.5可正确匹配5.5.x使用static静态数组缓存比较结果同一版本号只计算一次避免在循环中反复调用时产生性能开销。测试用例 Common_test.php 验证了其边界行为$this-assertTrue(is_php(1.2.0)); // 当前版本必然 1.2.0 $this-assertFalse(is_php(9999.9.9)); // 未来版本必然不满足实战场景当你的代码需要调用仅在特定 PHP 版本才存在的函数如json_last_error_msg()需 PHP 5.5时用它做特性探测是最稳妥的写法。2.is_cli()判断是否运行于命令行返回值bool—— 应用通过命令行运行时返回TRUE否则返回FALSE官方文档特别注明该函数同时检查PHP_SAPI值是否为cli以及STDIN常量是否已定义。源码实现Common.php与之一一对应function is_cli() { return (PHP_SAPI cli OR defined(STDIN)); }STDIN是 PHP CLI 模式下预定义的常量defined(STDIN)这一判断是为了兼容某些把php-cli包装为其他 SAPI 名如phpdbg、cli-server的运行环境。实战场景编写定时任务脚本、自定义 CLI 命令时用它区分 Web 请求与命令行调用决定输出 HTML 还是纯文本。3.is_https()判断是否运行于 HTTPS返回值bool—— 当前为 HTTP-over-SSLHTTPS连接时返回TRUE其他任何情况包括非 HTTP 请求返回FALSE源码实现Common.php依次检查三类服务器变量function is_https() { if ( ! empty($_SERVER[HTTPS]) strtolower($_SERVER[HTTPS]) ! off) { return TRUE; } elseif (isset($_SERVER[HTTP_X_FORWARDED_PROTO]) strtolower($_SERVER[HTTP_X_FORWARDED_PROTO]) https) { return TRUE; } elseif ( ! empty($_SERVER[HTTP_FRONT_END_HTTPS]) strtolower($_SERVER[HTTP_FRONT_END_HTTPS]) ! off) { return TRUE; } return FALSE; }可以看出它兼顾了三种常见部署形态标准 HTTPSHTTPS变量、反向代理/负载均衡透传HTTP_X_FORWARDED_PROTO: https、以及某些前端 Web 服务器如部分 IIS 配置使用的HTTP_FRONT_END_HTTPS。实战场景强制跳转 HTTPS、生成安全 Cookie、判断是否应启用加密传输等逻辑的入口判断。三、文件与配置访问函数4.is_really_writable($file)真实可写性检测参数string $file—— 文件或目录路径返回值bool—— 路径确实可写返回TRUE否则FALSE官方文档明确指出该函数存在的意义在 Windows 服务器上is_writable()可能返回TRUE但实际上无法写入——因为操作系统只在设置了只读属性时才向 PHP 报告FALSE。因此该函数通过实际尝试写入来判定可写性官方建议仅在平台信息可能不可靠时使用。源码实现Common.php清晰展示了两种平台的分支处理function is_really_writable($file) { // UNIX-like 服务器直接用 is_writable() if (DIRECTORY_SEPARATOR /) { return is_writable($file); } /* Windows 服务器或 safe_mode 开启时 * 实际写入一个文件再读取验证 */ if (is_dir($file)) { $file rtrim($file, /)./.md5(mt_rand()); if (($fp fopen($file, ab)) FALSE) { return FALSE; } fclose($fp); chmod($file, 0777); unlink($file); return TRUE; } elseif ( ! is_file($file) OR ($fp fopen($file, ab)) FALSE) { return FALSE; } fclose($fp); return TRUE; }注意实现细节对目录它会在目录内用md5(mt_rand())生成一个随机临时文件尝试以追加模式fopen成功后删除对文件则直接尝试打开追加。实战场景安装向导、缓存目录检查、上传目录权限校验等场景中用它比裸调is_writable()更可靠。5.config_item($key)读取单个配置项参数string $key—— 配置项键名返回值mixed—— 配置值键不存在时返回NULL官方文档提醒访问配置信息的首选方式是 Config 库参见 Config 库文档但config_item()可用于快速获取单个键值。源码实现Common.phpfunction config_item($item) { static $_config; if (empty($_config)) { // 静态变量不能直接保存引用因此包一层数组 $_config[0] get_config(); } return isset($_config[0][$item]) ? $_config[0][$item] : NULL; }它依赖同为公共函数的get_config()Common.php完成主配置加载优先加载application/config/config.php再合并环境目录application/config/ENVIRONMENT/config.php的覆盖项ENVIRONMENT由 index.php 定义并支持通过$replace参数动态追加/覆盖配置值。整个加载过程同样使用static缓存整个请求周期只解析一次配置文件。实战示例$charset config_item(charset); // 默认 UTF-8 $prefix config_item(subclass_prefix); // 默认 MY_以上两个默认值均可在 application/config/config.php 中查证charset见第 94 行subclass_prefix见第 119 行。6.get_mimes()获取 MIME 类型映射表返回值array—— 文件类型关联数组的引用官方文档明确该函数返回的是application/config/mimes.php中 MIME 数组的引用。源码实现Common.phpfunction get_mimes() { static $_mimes; if (empty($_mimes)) { $_mimes file_exists(APPPATH.config/mimes.php) ? include(APPPATH.config/mimes.php) : array(); if (file_exists(APPPATH.config/.ENVIRONMENT./mimes.php)) { $_mimes array_merge($_mimes, include(APPPATH.config/.ENVIRONMENT./mimes.php)); } } return $_mimes; }它同样支持环境级覆盖application/config/ENVIRONMENT/mimes.php中的条目会通过array_merge合并到默认表之上。MIME 表本体位于 application/config/mimes.php。实战场景Upload库校验上传文件类型、自定义下载响应时判断Content-Type。四、安全消毒与输入处理函数7.remove_invisible_characters($str, $url_encoded TRUE)清除不可见字符参数string $str—— 输入字符串bool $url_encoded—— 是否同时清除 URL 编码形式默认TRUE返回值string—— 消毒后的字符串官方文档指出该函数用于防止在 ASCII 字符之间夹入 NULL 字符例如把Java\0script这类输入还原为Javascript从而阻断基于空字节注入的绕过攻击。官方示例remove_invisible_characters(Java\\0script); // 返回: Javascript源码实现Common.php通过一组正则表达式完成清洗function remove_invisible_characters($str, $url_encoded TRUE) { $non_displayables array(); // 除换行(dec 10)、回车(dec 13)、水平制表(dec 09)外的所有控制字符 if ($url_encoded) { $non_displayables[] /%0[0-8bcef]/i; // url 编码的 00-08, 11, 12, 14, 15 $non_displayables[] /%1[0-9a-f]/i; // url 编码的 16-31 $non_displayables[] /%7f/i; // url 编码的 127 } $non_displayables[] /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/S; // 00-08, 11, 12, 14-31, 127 do { $str preg_replace($non_displayables, , $str, -1, $count); } while ($count); return $str; }值得强调的细节\x0A换行、\x0D回车、\x09水平制表被有意保留因为它们是合法文本格式字符do...while($count)循环确保嵌套/重复编码的字符也能被逐层清除。测试用例 Common_test.php 同时覆盖了 URL 编码开关两种模式$raw_string Here is a string containing invisible.chr(0x08). text %0e.; // 传入 FALSE 时仅清除原始控制字符保留 %0e $this-assertEquals($removed_string, remove_invisible_characters($raw_string, FALSE)); // 默认模式下连 %0e、%1F 等 URL 编码字符也一并清除该函数是 Input 库过滤流程的底层组成部分也是你处理用户输入、日志内容时的通用消毒利器。8.html_escape($var)HTML 转义防 XSS参数mixed $var—— 字符串或数组可嵌套返回值mixed—— 转义后的字符串或等结构数组官方文档该函数是 PHP 原生htmlspecialchars()的别名式封装优势在于能够接受字符串数组包括多维数组用于防范跨站脚本XSS。源码实现Common.php值得逐行拆解function html_escape($var, $double_encode TRUE) { if (empty($var)) { return $var; } if (is_array($var)) { foreach (array_keys($var) as $key) { $var[$key] html_escape($var[$key], $double_encode); } return $var; } return htmlspecialchars($var, ENT_QUOTES, config_item(charset), $double_encode); }三个关键点数组递归遍历数组键对每个值递归调用自身天然支持多维数组且保留键名不变ENT_QUOTES标志同时转义单引号和双引号比默认行为更严格字符集取自配置使用config_item(charset)默认UTF-8见 application/config/config.php作为htmlspecialchars的字符集参数保证与全局配置一致第二个参数$double_encode FALSE可防止对已转义内容二次转义。测试用例Common_test.php验证了引号转义与数组递归$this-assertEquals( html_escape(Here is a string containing quoted text.), Here is a string containing quot;quotedquot; text. ); // 多维数组原样递归转义实战场景在视图中输出用户提交的数据前统一转义是 CodeIgniter 应用防 XSS 的最便捷手段。9.function_usable($function_name)函数可用性检测参数string $function_name—— 待检测的函数名返回值bool—— 函数存在且可用返回TRUE否则FALSE官方文档该函数执行function_exists()检查若服务器加载了 Suhosin 扩展还会进一步检查函数是否被 Suhosin 禁用。它特别适合检测eval()、exec()这类高危函数在严格安全策略服务器上是否可调用。源码实现Common.phpfunction function_usable($function_name) { static $_suhosin_func_blacklist; if (function_exists($function_name)) { if ( ! isset($_suhosin_func_blacklist)) { $_suhosin_func_blacklist extension_loaded(suhosin) ? explode(,, trim(ini_get(suhosin.executor.func.blacklist))) : array(); } return ! in_array($function_name, $_suhosin_func_blacklist, TRUE); } return FALSE; }实现要点Suhosin 黑名单配置项suhosin.executor.func.blacklist是以逗号分隔的字符串这里将其拆分为数组并做严格类型比较TRUE第三个参数黑名单结果用static缓存只解析一次。官方文档同时说明其历史背景Suhosin 在函数被黑名单命中时不是返回错误而是直接终止脚本执行这曾是 Suhosin 的一个 bug修复版本 0.9.34 迟迟未发布因此框架提供了这一临时但长期保留的防护函数。五、错误处理与日志函数本节三个函数都是对system/core/Exceptions.php与system/core/Log.php中类方法的过程式封装完整行为说明见官方 错误处理文档。10.show_error($message, $status_code, $heading An Error Was Encountered)参数mixed $message错误消息可为字符串或数组int $status_codeHTTP 状态码string $heading错误页标题返回值void直接输出错误页并终止脚本源码实现Common.phpfunction show_error($message, $status_code 500, $heading An Error Was Encountered) { $status_code abs($status_code); if ($status_code 100) { $exit_status $status_code 9; // 9 即 EXIT__AUTO_MIN $status_code 500; } else { $exit_status 1; // EXIT_ERROR } $_error load_class(Exceptions, core); echo $_error-show_error($heading, $message, error_general, $status_code); exit($exit_status); }实现要点与官方错误文档完全吻合实际渲染由CI_Exceptions::show_error()Exceptions.php完成模板为application/views/errors/html/error_general.php或 CLI 版application/views/errors/cli/error_general.php两套模板在仓库 application/views/errors 下退出状态码的巧妙设计当$status_code 100时HTTP 状态固定为 500而进程退出码取$status_code EXIT__AUTO_MIN9否则退出码为EXIT_ERROR1。这些退出码常量定义于 application/config/constants.php供 CLI 下外部进程监控脚本健康状态使用。11.show_404($page , $log_error TRUE)参数string $page—— 未找到的 URI 字符串bool $log_error—— 是否写入日志默认TRUE返回值void源码实现Common.phpfunction show_404($page , $log_error TRUE) { $_error load_class(Exceptions, core); $_error-show_404($page, $log_error); exit(4); // EXIT_UNKNOWN_FILE }它调用CI_Exceptions::show_404()Exceptions.php渲染application/views/errors/html/error_404.php或 CLI 对应模板随后以EXIT_UNKNOWN_FILE4退出进程。注意当控制器找不到时CodeIgniter 的 Router 会自动触发 404 展示第二个参数设为FALSE可跳过 404 的日志记录例如某些爬虫频繁触发 404 的场景。12.log_message($level, $message)写入日志参数string $level—— 日志级别error、debug或infostring $message—— 日志内容返回值void源码实现Common.phpfunction log_message($level, $message) { static $_log; if ($_log NULL) { // 静态变量不能直接保存引用因此包一层数组 $_log[0] load_class(Log, core); } $_log[0]-write_log($level, $message); }它是CI_Log::write_log()的别名首次调用时通过load_class(Log, core)懒加载日志类之后复用静态实例。官方错误文档给出了完整用法示例if ($some_var ) { log_message(error, Some variable did not contain a value.); } else { log_message(debug, Some variable was correctly set); } log_message(info, The purpose of some variable is to provide some value.);三种级别按优先级排列Error真实错误如 PHP 错误或用户错误Debug辅助调试信息Info最低优先级的信息类消息。重要前提日志要真正落盘需要满足两个条件——application/logs/目录可写并且在 application/config/config.php 中正确设置log_threshold默认值为0即日志被完全禁用设为 1 只记 error2 记 debug3 记 info4 记全部。这正是is_really_writable()派上用场的场景写日志前先校验目录可写性。六、HTTP 状态头控制set_status_header($code, $text )参数int $code—— HTTP 状态码string $text—— 自定义状态文本可选返回值void官方示例set_status_header(401); // 设置响应头为: Unauthorized源码实现Common.php内含值得深入讲解的完整逻辑CLI 下直接返回is_cli()为真时不输出任何头命令行无 HTTP 语义参数校验$code必须为非空数字否则触发show_error(Status codes must be numeric, 500)状态文本映射不传$text时从一个内置的完整状态码-文本映射表覆盖 100 到 511 的 50 余个标准状态码中查取如200 OK、301 Moved Permanently、404 Not Found、500 Internal Server Error等查不到时触发错误提示要求自查状态码或显式传入文本CGI 兼容分支PHP_SAPI以cgi开头时使用header(Status: ...)语法FastCGI 环境需要协议协商根据$_SERVER[SERVER_PROTOCOL]在HTTP/1.0、HTTP/1.1、HTTP/2、HTTP/2.0中选取未知则回退HTTP/1.1最终调用header($server_protocol. .$code. .$text, TRUE, $code)。实战场景在控制器或钩子中手动控制响应状态码如 API 返回 201 Created、403 Forbidden、429 Too Many Requests比依赖http_response_code()更契合框架的 CLI/CGI 兼容需求。七、公共函数背后的隐形基础设施官方文档只列出上述 13 个函数但从 Common.php 的完整源码看还有几个不直接面向业务、却支撑整个框架运转的同级函数理解它们能加深你对公共函数体系的认识load_class()与is_loaded()单例类注册表load_class($class, $directory libraries, $param NULL)Common.php是框架的核心单例机制按application/优先、system/其次的顺序查找类文件支持subclass_prefix默认MY_扩展类覆盖实例化后存入静态数组供后续调用复用找不到类时输出 503 并以EXIT_UNKNOWN_CLASS5退出。is_loaded()Common.php则维护已加载类的登记表供 Loader 等组件查询。get_config()配置文件的原始读取器前文已述它负责加载并缓存application/config/config.php与环境覆盖文件是config_item()的底层依赖在 Config 类实例化之前即可工作。_stringify_attributes()HTML 属性字符串化_stringify_attributes($attributes, $js FALSE)Common.php将字符串/数组/对象形式的属性列表转换为classfoo idbar格式$js TRUE时输出width800,height600的 JS 参数风格。它在表单、HTML Helper 中广泛使用测试用例 Common_test.php 对两种模式均有断言。三个错误处理器_error_handler()、_exception_handler()、_shutdown_handler()Common.php分别通过set_error_handler、set_exception_handler、register_shutdown_function注册负责把 PHP 错误/未捕获异常/致命错误统一转入框架日志与错误模板并在致命错误时设置 500 状态头、以EXIT_ERROR1退出。它们与 CodeIgniter.php 的引导流程配合构成了完整的错误处理闭环。八、实践建议与调用规范无需加载即可用这些函数不依赖任何库或 Helper控制器、模型、视图、钩子、甚至application/config之外的任意业务文件中都可直接调用无需$this-load。可安全覆盖由于function_exists()保护如需定制行为例如让show_error()输出 JSON可在application/core/Common.php或通过application/config/autoload.php引入的扩展文件中重新定义同名函数。组合使用更佳日志落盘前用is_really_writable()校验目录输出用户数据前用html_escape()调用高危函数前用function_usable()判断运行环境用is_cli()/is_https()。配置联动html_escape()的字符集、config_item()的数据源、log_message()的开关阈值均与 application/config/config.php 中的charset、log_threshold等配置项直接联动理解配置与函数的关系是排查问题的关键。以测试为行为契约本仓库 tests/codeigniter/core/Common_test.php 对is_php()、html_escape()、remove_invisible_characters()、_stringify_attributes()的行为做了可复现的断言是理解这些函数边界行为如数组递归、URL 编码开关、严格比较最直观的参考。这套全局公共函数是 CodeIgniter 一切组件协作的基石——理解了它们你就理解了框架开箱即用背后的设计哲学极小的核心、全局可用的过程式接口、可覆盖的扩展点。【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考