xss_clean($value) : $value; } // post解析 public function post($name, $xss = true) { $value = isset($_POST[$name]) ? $_POST[$name] : false; return $xss ? $this->xss_clean($value, true) : $value; } // get解析 public function get($name = '', $xss = true) { $value = !$name ? $_GET : (isset($_GET[$name]) ? $_GET[$name] : false); return $xss ? $this->xss_clean($value, true) : $value; } // 通过post格式化ids public function get_post_ids($name = 'ids') { $in = []; $ids = self::post($name); if (!$ids) { return $in; } foreach ($ids as $i) { $i && $in[] = (int)$i; } return $in; } public function set_cookie($name, $value = '', $expire = '') { return \Frame\set_cookie($name, $value, $expire); } public function get_cookie($name) { return \Frame\get_cookie($name); } // inputip存储信息 public function ip_info() { return $this->ip_address().'-'.(int)$_SERVER['REMOTE_PORT']; } // 获取访客ip地址 public function ip_address() { if ($this->ip_address) { return $this->ip_address; } if (defined('IS_CDN_IP') && IS_CDN_IP && getenv(IS_CDN_IP)) { $client_ip = getenv(IS_CDN_IP); } elseif (getenv('HTTP_TRUE_CLIENT_IP')) { $client_ip = getenv('HTTP_TRUE_CLIENT_IP'); } elseif (getenv('HTTP_ALI_CDN_REAL_IP')) { $client_ip = getenv('HTTP_ALI_CDN_REAL_IP'); } elseif (getenv('HTTP_CLIENT_IP')) { $client_ip = getenv('HTTP_CLIENT_IP'); } elseif(getenv('HTTP_X_FORWARDED_FOR')) { $client_ip = getenv('HTTP_X_FORWARDED_FOR'); } elseif(getenv('REMOTE_ADDR', true)) { $client_ip = getenv('REMOTE_ADDR', true); } else { $client_ip = $_SERVER['REMOTE_ADDR']; } if ($client_ip && strpos($client_ip, ',') !== false) { $client_ip = trim(explode(',', $client_ip)[0]); } // 验证规范 if (!$this->is_ip($client_ip)) { $client_ip = ''; } $this->ip_address = (string)$client_ip; $this->ip_address = str_replace([",", '(', ')', ',', chr(13), PHP_EOL], '', $this->ip_address); $this->ip_address = trim($this->ip_address); return $this->ip_address; } /** * 检测是否是合法的IP地址 */ public function is_ip($ip, $type = '') { switch (strtolower($type)) { case 'ipv4': $flag = FILTER_FLAG_IPV4; break; case 'ipv6': $flag = FILTER_FLAG_IPV6; break; default: $flag = 0; break; } return boolval(filter_var($ip, FILTER_VALIDATE_IP, $flag)); } // ip转为实际地址 public function ip2address($ip) { return \Phpcmf\Service::L('ip')->address($ip); } // 当前ip实际地址 public function ip_address_info() { return \Phpcmf\Service::L('ip')->address($this->ip_address()); } // 安全过滤 public function get_user_agent() { return dr_safe_replace(str_replace(['"', "'", '<', '>'], '', \Phpcmf\Service::L('Security')->xss_clean((string)$_SERVER['HTTP_USER_AGENT'], true))); } /** * 系统错误日志 */ public function log($level, $message, $context = []) { $message = $this->interpolate($message, $context); if (! is_string($message)) { $message = print_r($message, true); } $message = strtoupper($level) . ' - '.date('Y-m-d H:i:s'). ' --> '.$message; $file = WRITEPATH . 'error/log-'.date('Y-m-d').'.php'; if (!is_file($file)) { file_put_contents($file, "".PHP_EOL.$message); } else { file_put_contents($file, $message.PHP_EOL, FILE_APPEND); } return true; } /** * Replaces any placeholders in the message with variables * from the context, as well as a few special items like: * * {session_vars} * {post_vars} * {get_vars} * {env} * {env:foo} * {file} * {line} * * @param mixed $message * * @return mixed */ protected function interpolate($message, array $context = []) { if (! is_string($message)) { return $message; } // build a replacement array with braces around the context keys $replace = []; foreach ($context as $key => $val) { // Verify that the 'exception' key is actually an exception // or error, both of which implement the 'Throwable' interface. if ($key === 'exception' && $val instanceof Throwable) { $val = $val->getMessage() . ' ' . $val->getFile() . ':' . $val->getLine(); } // todo - sanitize input before writing to file? $replace['{' . $key . '}'] = $val; } // Add special placeholders $replace['{post_vars}'] = '$_POST: ' . print_r($_POST, true); $replace['{get_vars}'] = '$_GET: ' . print_r($_GET, true); // Allow us to log the file/line that we are logging from if (strpos($message, '{file}') !== false) { [$file, $line] = $this->determineFile(); $replace['{file}'] = $file; $replace['{line}'] = $line; } // Match up environment variables in {env:foo} tags. if (strpos($message, 'env:') !== false) { preg_match('/env:[^}]+/', $message, $matches); if ($matches) { foreach ($matches as $str) { $key = str_replace('env:', '', $str); $replace["{{$str}}"] = $_ENV[$key] ?? 'n/a'; } } } if (isset($_SESSION)) { $replace['{session_vars}'] = '$_SESSION: ' . print_r($_SESSION, true); } // interpolate replacement values into the message and return return strtr($message, $replace); } /** * Determines the file and line that the logging call * was made from by analyzing the backtrace. * Find the earliest stack frame that is part of our logging system. */ public function determineFile(): array { $logFunctions = [ 'log_message', 'log', 'error', 'debug', 'info', 'warning', 'critical', 'emergency', 'alert', 'notice', ]; // Generate Backtrace info $trace = \debug_backtrace(0); // So we search from the bottom (earliest) of the stack frames $stackFrames = \array_reverse($trace); // Find the first reference to a Logger class method foreach ($stackFrames as $frame) { if (\in_array($frame['function'], $logFunctions, true)) { $file = isset($frame['file']) ? ($frame['file']) : 'unknown'; $line = $frame['line'] ?? 'unknown'; return [ $file, $line, ]; } } return [ 'unknown', 'unknown', ]; } /** * 后台日志 */ public function system_log($action, $insert = 0, $param = [], $username = '') { if (!$insert && (!SYS_ADMIN_LOG || !IS_ADMIN)) { // 是否开启日志 return NULL; } $data = [ 'ip' => $this->ip_address(), 'uid' => (int)\Phpcmf\Service::C()->admin['uid'], 'url' => dr_safe_url(FC_NOW_URL), 'time' => SYS_TIME, 'param' => $param, 'action' => addslashes(dr_safe_replace($action)), 'username' => $username ? $username : (\Phpcmf\Service::C()->admin['username'] ? \Phpcmf\Service::C()->admin['username'] : '未登录'), ]; $path = WRITEPATH.'log/'.date('Ym', SYS_TIME).'/'; $file = $path.date('d', SYS_TIME).'.php'; if (!is_dir($path)) { dr_mkdirs($path); } if (!is_file($file)) { file_put_contents($file, "".PHP_EOL.dr_array2string($data)); } else { file_put_contents($file, PHP_EOL.dr_array2string($data), FILE_APPEND); } } /** * 密码错误日志 */ public function password_log($post) { $data = [ 'ip' => $this->ip_address(), 'time' => SYS_TIME, 'username' => $post['username'], ]; $file = WRITEPATH.'password_log.php'; if (!is_file($file)) { file_put_contents($file, "".PHP_EOL.dr_array2string($data)); } else { file_put_contents($file, PHP_EOL.dr_array2string($data), FILE_APPEND); } } // 服务器ip地址 public function server_ip() { if (isset($_SERVER['SERVER_ADDR']) && $_SERVER['SERVER_ADDR'] && $_SERVER['SERVER_ADDR'] != '127.0.0.1') { return $_SERVER['SERVER_ADDR']; } return gethostbyname($_SERVER['HTTP_HOST']); } // 后台分页 public function page($url, $total, $dir = '') { $config = require CMSPATH.'Config/Apage.php'; $config['base_url'] = $url.'&page={page}'; $config['per_page'] = SYS_ADMIN_PAGESIZE; $config['total_rows'] = $total; return \Phpcmf\Service::L('page')->initialize($config)->create_links(); } // Ftable分页 public function table_page($url, $total, $config, $size) { $config['base_url'] = $url; $config['per_page'] = $size; $config['total_rows'] = $total; return \Phpcmf\Service::L('page')->initialize($config)->create_links(); } /** * XSS Clean */ public function xss_clean($str, $is = FALSE) { return \Phpcmf\Service::L('Security')->xss_clean($str, $is); } }