PHP简单写个日志文件的写入和读取功能。
代码如下:
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2023/7/11
* Time: 11:16
*/
class Log
{
private $conf = array(
"expire" => 0,
"suffix" => "log",
"key_split" => "◀", //字段分隔标记
"row_split" => "▟", //行尾分隔标记
"exp" => 7200, //默认2小时后过期
"replace" => array(),
"add_data" => "",
);
//字段列表
private $field_list = array("add_time");
//日志文件目录
private $dir_path = "";
public function __construct()
{
date_default_timezone_set("Asia/Shanghai");
}
/**
* @param array|string $key
* @param string $val
* @return $this
*/
public function set($key = '', $val = '')
{
$list = array("field_list", "dir_path");
if (self::is_string($key) && self::exist($val)) {
in_array($key, $list, true) ? $this->{$key} = $val : $this->conf[$key] = $val;
} else {
if (is_array($key)) {
foreach ($key as $k => $item) {
self::set($k, $item);
}
}
}
return $this;
}
public function get($key = '')
{
$list = array("field_list", "dir_path");
if (self::is_string($key)) {
return in_array($key, $list) ? $this->{$key} : $this->conf[$key];
}
return array("conf" => $this->conf, "field_list" => $this->field_list, "dir_path" => $this->dir_path);
}
public function init()
{
$this->conf['expire'] = time() + 3600;
$this->conf['suffix'] = 'log';
$this->conf['key_split'] = '◀';
$this->conf['row_split'] = '▟';
$this->conf['exp'] = 7200;
$this->conf['replace'] = array("key_split" => "[[ks]]", "row_split" => "[[rs]]", "br" => "[[br]]");
$this->conf['add_data'] = '';
$this->field_list = array('add_time', 'ip', 'url', 'method', 'protocol', 'user_agent', 'accept');
$this->dir_path = '';
return $this;
}
/**
* 设置日志目录路径
* @param string $path 绝对路径|‘/’开头路径
* @param string|null $root_dir 绝对路径
* @return $this
*/
public function set_dir_path($path = '', $root_dir = '')
{
self::is_string($path) && ($this->dir_path = $path);
$dir = $this->dir_path;
$is_relative = self::is_string($dir) && strpos($dir, '/') === 0;
if (self::is_string($root_dir)) {
$this->dir_path = $root_dir;
if (empty($dir)) {
$dir = $root_dir . '/log/';
} elseif ($is_relative) {
$dir = rtrim($root_dir, '\\/') . $dir;
}
} else {
if (empty($dir)) {
$dir = dirname(__FILE__) . "/../../log/";
} elseif ($is_relative) {
if ($_SERVER["DOCUMENT_ROOT"]) {
$dir = rtrim($_SERVER["DOCUMENT_ROOT"], '/\\') . $dir;
} else {
$dir = dirname(__FILE__) . "/../../" . $dir;
}
}
}
$dir = preg_replace("/[\\\\\/]{1,}/i", "/", $dir);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$this->dir_path = $dir;
return $this;
}
/**
* 设置字段列表
* @param array $list 数字下标一维数组
* @return $this
*/
public function set_field_list($list = array())
{
if (is_array($list) && count($list) > 0) {
if (self::is_assoc($list)) {
$temp = array();
foreach ($list as $k => $v) {
$temp[] = self::is_string($v) ? $v : $k;
}
$list = $temp;
}
$this->field_list = $list;
}
return $this;
}
/**
* 过期时间
* @param int $exp 多少秒后过期
* @return $this
*/
public function expire($exp = 0)
{
if (is_numeric($exp)) {
$exp = intval($exp);
($exp <= 0) && ($exp = 31622400); // 1年
$this->conf['exp'] = $exp;
$this->conf['expire'] = time() + $exp;
}
return $this;
}
/**
* 日志文件后缀
* @param string $name
* @return $this
*/
public function suffix($name = 'log')
{
self::is_string($name) && ($this->conf['suffix'] = $name);
return $this;
}
/**
* 构成写入日志的数据
* @param string|array $data
* @return $this
*/
public function data($data = '')
{
$split = array($this->conf['key_split'], $this->conf['row_split']);
if (empty($data)) {
$this->field_list = array('add_time', 'ip', 'url', 'method', 'protocol', 'user_agent', 'accept');
$data = array(
'ip' => self::ip(),
'url' => self::get_url('url'),
'add_time' => date('Y-m-d H:i:s'),
'method' => $_SERVER['REQUEST_METHOD'],
'protocol' => $_SERVER['SERVER_PROTOCOL'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'accept' => $_SERVER['HTTP_ACCEPT'],
);
}
if (is_array($data) && self::arrayLevel($data) == 1) {
$data = self::handle_data_string($this->field_list, [$data]);
}
$this->conf['add_data'] = $data;
return $this;
}
/**
* 设置日志文件头部信息
* @param array $data
* @param string $file_name
* @return string
*/
public function set_head_info($data = array(), $file_name = '')
{
$split = array($this->conf['key_split'], $this->conf['row_split']);
$t = time();
$conf = array(
"create_time" => array("time" => $t, "datetime" => date("Y-m-d H:i:s")),
"expire" => array("time" => $this->conf['expire'], "datetime" => date("Y-m-d H:i:s", $this->conf['expire']),),
"field_list" => $this->field_list,
);
if (is_array($data) && count($data) > 0) {
$conf = array_merge($conf, $data);
}
$temp = serialize($conf) . "{$split[0]}\n";
$temp .= "[field_list] " . join(',', $this->field_list) . "\n";
$temp .= "{$split[1]}\n";
return $temp;
}
/**
* 获取日志文件头部记录信息
* @param string $file_path
* @return bool|mixed
*/
public function get_head_data($file_path = '')
{
if (self::is_string($file_path)) {
$arr = self::file_rows($file_path, 1, 1);
$str = rtrim($arr[0], $this->conf['key_split']);
return unserialize($str);
}
return false;
}
/**
* 数组转换维字符串
* @param array $key_list 一维数组
* @param array $data 一维数组或者二维数组
* @return array|bool|string
*/
public function handle_data_string($key_list = array(), $data = array())
{
if (is_array($key_list) && count($key_list) > 0) {
if (self::is_assoc($key_list)) {
foreach ($key_list as $k => $v) {
$temp[] = self::is_string($v) ? $v : $k;
}
$key_list = $temp;
unset($temp);
}
if (is_array($data) && count($data) > 0) {
$split = array($this->conf['key_split'], $this->conf['row_split']);
$lv = self::arrayLevel($data);
if ($lv == 1) {
if (self::is_assoc($data)) {
foreach ($data as $key => $val) {
$sk = array_search($key, $key_list);
is_numeric($sk) && ($temp[$sk] = self::text_in($val));
}
ksort($temp);
$data = $temp;
$temp = join($split[0], $data);
return $temp;
}
return join($split[0], self::text_in($data));
} elseif ($lv == 2) {
$temp = "";
foreach ($data as $index => $val) {
$temp .= self::handle_data_string($key_list, $val) . "{$split[1]}\n";
}
return $temp;
}
}
}
return false;
}
/**
* 字符串转数组,返回一维或二维数组
* @param array $key_list 一维数组
* @param string $str
* @param bool $assoc
* @return array|bool
*/
public function handle_string_data($key_list = array(), $str = '', $assoc = true)
{
if (is_array($key_list) && count($key_list) > 0) {
$split = array($this->conf['key_split'], $this->conf['row_split']);
if (self::is_assoc($key_list)) {
foreach ($key_list as $k => $v) {
$temp[] = self::is_string($v) ? $v : $k;
}
$key_list = $temp;
unset($temp);
}
if (preg_match("/{$split[1]}/i", $str)) {
$data = explode($split[1], $str);
if (!self::is_string(trim($data[count($data)-1]))) {
unset($data[count($data) - 1]);
}
$temp = array();
foreach ($data as $index => $v) {
$temp[] = self::handle_string_data($key_list, $v, $assoc);
}
return $temp;
} elseif (preg_match("/{$split[0]}/i", $str)) {
$data = explode($split[0], $str);
foreach ($data as $index => $v) {
$v = self::text_out(trim($v));
$data[$index] = $v;
$data[$key_list[$index]] = $v; //使用键值访问
if ($assoc) {
unset($data[$index]);
}
}
return $data;
}
}
return false;
}
/**
* 历史过期日志文件信息列表
* @param string $file_name
* @param array|string $data
* @return array|bool
*/
public function history_link($file_name = '', $data = '', $write = false)
{
$key_list = array("expire_file_name", "expire_file_path");
$dir_path = rtrim($this->dir_path, '/');
$name = "history_link_data_{$file_name}.{$this->conf['suffix']}";
$file_path = "$dir_path/$name";
if (file_exists($file_path) && $write === false) {
//读取数据和更新数据
$str = file_get_contents($file_path);
$temp = self::handle_string_data($key_list, $str);
return $temp;
} else {
//创建文件和写入数据
if (is_array($data) && count($data) > 0) {
$lv = self::arrayLevel($data);
if ($lv < 3) {
($lv === 1) && ($data = array($data));
$data = self::handle_data_string($key_list, $data);
$f = fopen($file_path, "a+");
fwrite($f, $data);
return fclose($f);
}
}
}
return false;
}
/**
* 日志文件过期时的操作
* @param string $file_name
* @param int $expire
* @return bool
*/
public function file_expire($file_name = '', $expire = 3600)
{
$t = time();
$dir_path = rtrim($this->dir_path, '/');
$suffix = $this->conf['suffix'];
$head = self::get_head_data($file_name);
if ($t > $head['expire']['time']) {
//到期code
$c_dt = date("Y-m-d+H-i-s", $head['create_time']['time']);
$file_path = "$dir_path/$file_name.{$suffix}";
$re_name = "expire_{$head['create_time']['time']}_{$c_dt}_$file_name"; //重命名,保存创建时间信息
$new_file_path = "$dir_path/$re_name.$suffix";
if (file_exists($file_path)) {
self::history_link($file_name, array("expire_file_name" => "$re_name.$suffix", "expire_file_path" => $new_file_path), true);//创建过期历史文件记录文件
$ok = rename($file_path, $new_file_path);
if ($ok) {
self::expire($expire);
}
return $ok;
}
}
return false;
}
/**
* 添加日志
* @param string $file_name
* @param array|string $data
* @return $this
*/
public function add($file_name = '', $data = '')
{
self::file_expire($file_name, $this->conf['exp']);
$file_path = rtrim($this->dir_path, '/') . '/';
if (self::is_string($file_name)) {
$file_path .= "$file_name.{$this->conf['suffix']}";
$data = self::data($data)->conf['add_data'];
if (file_exists($file_path)) {
$f = fopen($file_path, 'a+');
fwrite($f, $data);
} else {
$top = self::set_head_info('', $file_name);
$f = fopen($file_path, 'w+');
fwrite($f, $top . $data);
}
fclose($f);
}
return $this;
}
/**
* 读取日志数据
* @param string $file_name
* @return array|bool
*/
public function read($file_name = '', $assoc = false)
{
$split = array($this->conf['key_split'], $this->conf['row_split']);
$file_path = trim($this->dir_path, '/') . '/';
if (self::is_string($file_name)) {
$file_path .= "$file_name.{$this->conf['suffix']}";
if (file_exists($file_path)) {
$str = file_get_contents($file_path);
$data = explode($split[1], $str);
$top_data = array_slice($data, 0, 1);
unset($data[count($data) - 1], $data[0]);
//读取构造日志数据
foreach ($data as $k => $v) {
$data[$k] = explode($split[0], $v);
foreach ($data[$k] as $k1 => $v1) {
$v1 = self::text_out(trim($v1));
$data[$k][$k1] = $v1;
$data[$k][$this->field_list[$k1]] = $v1; // 使用键值访问
if ($assoc) {
unset($data[$k][$k1]);
}
}
}
$top_data = explode($split[0], $top_data[0]);
return array("top_data" => unserialize(trim($top_data[0])), "data" => $data);
}
}
return false;
}
/**
* 读取日志主体信息,返回二维数组
* @param string $file_path
* @param int $start
* @param int $leng
* @param bool $assoc 是否只返回关联数组
* @return array|bool
*/
public function get_body_data($file_path = '', $start = 0, $leng = 10, $assoc = false)
{
$split = array($this->conf['key_split'], $this->conf['row_split']);
$start = is_numeric($start) ? intval($start) + 4 : 4;
$leng = is_numeric($leng) ? intval($leng) : 10;
$end = $start + $leng - 1;
$arr = self::file_rows($file_path, $start, $end);
if (is_array($arr)) {
foreach ($arr as $index => $item) {
$item = rtrim($item, $split[1]);
$item = explode($split[0], $item);
foreach ($item as $k1 => $v1) {
$v1 = self::text_out(trim($v1));
$item[$k1] = $v1;
$item[$this->field_list[$k1]] = $v1; //使用键值访问
if($assoc){
unset($item[$k1]);
}
}
$arr[$index] = $item;
}
}
return $arr;
}
/**
* 读取日志主体列表,返回二维关联数组
* @param string $file_path
* @param int $start
* @param int $leng
* @return mixed
*/
public function get_body_data_assoc($file_path = '', $start = 0, $leng = 10)
{
$args = func_get_args();
return call_user_func_array(array($this, "get_body_data"), array($args[0], $args[1], $args[2], true));
}
/**
* 读取文件部分内容,行数从1开始
* @param string $file_path 文件路径
* @param int $start 开始行 $start>=1
* @param int $end 结束行 $end<=0 读完整个文件
* @param null|int $len 每行读取最大字节数
*/
public function file_rows($file_path = '', $start = 1, $end = -1, $len = 4096)
{
if (self::is_string($file_path)) {
if (!file_exists($file_path)) {
$file_path = trim($this->dir_path, '/') . "/$file_path.{$this->conf['suffix']}";
}
if (file_exists($file_path)) {
$row = array();
$f = fopen($file_path, 'r');
$line = 1;
if ($f) {
while (!feof($f)) {
$str = rtrim(fgets($f, $len));
if ($line >= $start) {
$str && ($row[] = $str);
}
if ($end > 0 && $line >= $end) {
break;
}
$line++;
}
}
fclose($f);
return $row;
}
}
return false;
}
public function str_filter($str, $preg = '')
{
$preg || ($preg = "/(^[\r\n\t\s]+|[\r\n\t\s]+$)/i");
if (is_array($str)) {
foreach ($str as $index => $item) {
$str[$index] = preg_replace($preg, '', $item);
}
} else {
$str = preg_replace($preg, '', $str);
}
return $str;
}
/**
* @param string|array $data
* @return array|mixed|string
*/
public function text_in($data = '')
{
if (self::is_string($data)) {
$re = $this->conf['replace'];
$data = str_replace(array("\n", $this->conf['key_split'], $this->conf['row_split']), array($re['br'], $re['key_split'], $re['row_split']), $data);
return $data;
} elseif (is_array($data)) {
foreach ($data as $k => $v) {
$data[$k] = self::text_in($v);
}
return $data;
} else {
return $data;
}
}
/**
* @param string|array $data
* @return array|mixed|string
*/
public function text_out($data = '')
{
if (self::is_string($data)) {
$re = $this->conf['replace'];
$data = str_replace(array($re['br'], $re['key_split'], $re['row_split']), array("\n", $this->conf['key_split'], $this->conf['row_split']), $data);
return $data;
} elseif (is_array($data)) {
foreach ($data as $k => $v) {
$data[$k] = self::text_out($v);
}
return $data;
} else {
return $data;
}
}
/**
* 递归浏览目录
* @param string $dir
* @param string $root_dir
* @param bool $previous_dir
* @return array|bool
*/
public function read_dir_list($dir = '', $root_dir = '', $previous_dir = false)
{
//static $arr = array();
return self::dir_read($arr, $dir, $root_dir, $previous_dir);
}
/**
* 递归浏览目录
* @param array $arr
* @param string $dir 相对路径和以‘/’开头的路径,路径里尽量不要包含 ‘../’
* @param string $root_dir 根目录,绝对路径,可以忽略
* @param boolean $previous_dir $dir里路径是否允许包含‘../’
* @return array|bool
*/
final private function dir_read(&$arr = array(), $dir = '', $root_dir = '', $previous_dir = false)
{
if (self::is_string($dir)) {
$is_relative = strpos($dir, '/') === 0; //以‘/’开头的路径
$no_absolute = preg_match("/^(?!([A-Za-z]{1,3}\:))/i", $dir); //不是绝对路径(window系统下)
if (self::is_string($root_dir) && ($root_dir = realpath($root_dir))) {
if ($is_relative) {
$dir = rtrim($root_dir, '\\/') . $dir;
} elseif ($no_absolute) {
$dir = rtrim($root_dir, '\\/') . "/$dir";
}
$self_dir = $root_dir;
} else {
if ($is_relative) {
if ($_SERVER['DOCUMENT_ROOT']) {
$dir = ($self_dir = rtrim($_SERVER['DOCUMENT_ROOT'], '\\/')) . $dir;
} else {
$dir = ($self_dir = getcwd()) . $dir;
}
} elseif ($no_absolute) {
$dir = ($self_dir = getcwd()) . "/$dir";
}
}
} else {
$self_dir = $dir = self::is_string($root_dir) ? $root_dir : getcwd();
}
$previous_dir || ($dir = str_replace(array('../', '..\\'), array('', ''), $dir)); //不允许路径包含‘../’
$dir = realpath($dir);
if ($dir) {
$dir = rtrim(preg_replace("/[\/\\\\]{1,}/", "/", $dir), '/') . '/';
$self_dir = rtrim(preg_replace("/[\/\\\\]{1,}/", "/", $self_dir), '/'); //相对目录的根目录
$_dir = rtrim(str_replace($self_dir, '/', $dir), '/') . '/'; //以‘/’开头的相对路径
$dir_handle = opendir($dir);
$preg = array("a" => "/[\/\\\\]{1,10}/i");
while (false !== $list = readdir($dir_handle)) {
if ($list == '.' || $list == '..') continue;
$file_path = preg_replace($preg['a'], "/", $dir . $list, -1);
$relative_path = preg_replace($preg['a'], '/', $_dir . $list, -1);
if (is_file($file_path)) {
$arr['file'][] = array(
/*绝对路径(完整的文件路径)*/
"path" => $file_path,
/*相对路径*/
"relative" => $relative_path,
/*文件名*/
"fileName" => $list,
/*文件创建或修改时间*/
"filectime" => filectime($file_path),
"fctime" => date("Y-m-d H:i:s", filectime($file_path)),
/*文件的上次访问时间*/
"fileatime" => fileatime($file_path),
"fatime" => date("Y-m-d H:i:s", fileatime($file_path)),
/*文件的内容上次被修改的时间*/
"filemtime" => filemtime($file_path),
"fmtime" => date("Y-m-d H:i:s", filemtime($file_path)),
/*文件的所有者*/
"fileowner" => fileowner($file_path),
/*文件的大小 byte(字节)*/
"filesize" => filesize($file_path),
);
}
//判断当前是否为目录
if (is_dir($file_path)) {
//是目录
$arr["dir"][] = array(
/*完整目录路径(决对路径)*/
"path" => $file_path,
/*相对路径*/
"relative" => $relative_path,
/*文件夹(目录)名称*/
"dirName" => $list,
);
self::dir_read($arr, $_dir . '/' . $list, $root_dir);
}
}
closedir($dir_handle);
return $arr;
} else {
return false;
}
}
/**
* 自定义目录扫描
* @param string $path
* @return array|bool
*/
final public function scandir($path = '')
{
if (self::is_string($path) && ($path = realpath($path))) {
$list = scandir($path);
$path = rtrim(str_replace('\\', '/', $path), '/') . '/';
if (is_array($list)) {
$temp = array("file" => array(), "dir" => array());
foreach ($list as $val) {
if ($val != "." && $val != "..") {
$link = $path . $val;
$od = array(
'path' => $link, 'fileowner' => fileowner($link), 'filesize' => filesize($link), 'filectime' => date('Y-m-d H:i:s', filectime($link)),
'fileatime' => date('Y-m-d H:i:s', fileatime($link)), 'filemtime' => date('Y-m-d H:i:s', filemtime($link)),
);
if (is_dir($link)) {
unset($od['fileowner'], $od['filesize']);
$temp['dir'][] = array_merge(array('dirName' => $val), $od);
}
if (is_file($link)) {
$temp['file'][] = array_merge(array('fileName' => $val), $od);
}
}
}
return $temp;
}
}
return false;
}
/**
* 判断是否存在
* @param $var
* @param array $opt 这里的值代表了不存在的意思
* @return bool
*/
static public function exist($var, $opt = array("", null, false))
{
isset($var) || ($var = false);
if (in_array($var, $opt, true)) {
return false;
}
return true;
}
/**
* 判断是否是字符串
* @param $var
* @return bool
*/
static public function is_string($var)
{
return self::exist($var) && (is_string($var) || is_numeric($var) || is_double($var));
}
/**
* 浏览器友好的变量输出
* @param mixed $var 变量
* @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
* @param string $label 标签 默认为空
* @param boolean $strict 是否严谨 默认为true
* @return void|string
*/
public function dump($var, $echo = true, $label = null, $strict = true)
{
$label = ($label === null) ? '' : rtrim($label) . ' ';
if (!$strict) {
if (ini_get('html_errors')) {
$output = print_r($var, true);
$output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
} else {
$output = $label . print_r($var, true);
}
} else {
ob_start();
var_dump($var);
$output = ob_get_clean();
if (!extension_loaded('xdebug')) {
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
$output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
}
}
if ($echo) {
echo($output);
return null;
} else
return $output;
}
/**
* @param int $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
* @return mixed
*/
public function ip($type = 0)
{
$type = $type ? 1 : 0;
static $ip = NULL;
if ($ip !== NULL) return $ip[$type];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown', $arr);
if (false !== $pos) unset($arr[$pos]);
$ip = trim($arr[0]);
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$long = sprintf("%u", ip2long($ip));
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
return $ip[$type];
}
/**
* 页面跳转
* @param string $url 页面链接
* @param int $code 状态码
*/
final public function url($url = '', $code = 302)
{
if (self::is_string($url)) {
preg_match('/^\//i', $url) && ($url = self::get_url() . $url);
header('Location: ' . $url, true, $code);
exit();
}
}
final public function get_url($name = '')
{
$data = [];
$scheme = self::is_ssl() ? 'https://' : 'http://';
$uri = $_SERVER['PHP_SELF'] . $_SERVER['QUERY_STRING'];
if ($_SERVER['REQUEST_URI']) {
$uri = $_SERVER['REQUEST_URI'];
}
//首页链接
$data['host'] = $scheme . $_SERVER['HTTP_HOST'];
//当前链接
$data['url'] = $scheme . $_SERVER['HTTP_HOST'] . $uri;
return $name ? $data[$name] : $data['host'];
}
/**
* 判断是否SSL协议
* @return boolean
*/
final private function is_ssl()
{
if (isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))) {
return true;
} elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
return true;
}
return false;
}
public function encode64($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
public function decode64($data)
{
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}
public function is_assoc($arr)
{
return array_keys($arr) !== range(0, count($arr) - 1);
}
/**
* 返回毫秒
* @return float
*/
public function m_second()
{
$t = strval(microtime());
$l = explode(' ', $t);
$s = $l[1];
$ms = ~~(floatval($l[0]) * 1000);
$v = strval($s) . str_pad(strval($ms), 3, '0', STR_PAD_LEFT);
return (float)$v;
}
/**
* 返回微秒
* @return string
*/
public function u_second()
{
$t = strval(microtime());
$l = explode(' ', $t);
$s = $l[1];
$us = ~~(floatval($l[0]) * 1000000);
$v = strval($s) . str_pad(strval($us), 6, '0', STR_PAD_LEFT);
return $v;
}
/**
* 返回数组的维度
* @param $arr
* @return mixed
*/
final public function arrayLevel($arr)
{
$al = array(0);
self::aL($arr, $al);
return max($al);
}
static final private function aL($arr, &$al, $level = 0)
{
if (is_array($arr)) {
$level++;
$al[] = $level;
foreach ($arr as $k => $v) {
self::aL($v, $al, $level);
}
}
}
}
测试文件代码如下:
<?php
include_once dirname(__FILE__)."/Log.php";
$l = new Log();
/*$lv1_str = $l->handle_data_string(['abc','bbb','ccc'],['abc'=>'abc1','ccc'=>'ccc1','bbb'=>'bbb1']);
$lv2_str = $l->handle_data_string(['x1'=>'abc','x2'=>'ddd','x0'=>'ccc'],[
['abc'=>'abc1','ddd'=>'ddd1','ccc'=>'ccc1'],
['abc'=>'abc2','ddd'=>'ddd2','ccc'=>'ccc2'],
]);
my_dump($l->handle_string_data(['abc','bbb','ccc'],$lv1_str));
my_dump($l->handle_string_data(['abc','ddd','ccc'],$lv2_str));*/
$log_file = date("Ymd");
//$l->init()->set_dir_path('/log-01/','G:\web\log2233')->data()->add($log_file);
//$l->init()->set('exp', 10)->expire(20)->set_dir_path('/log111')->data()->add($log_file);
$l->init()->set('exp', 20)->expire(20)->set_dir_path('/log111')->data()->add($log_file);
$log_file_path = rtrim($l->get('dir_path'),'/')."/$log_file.log";
$read = $l->read($log_file);
//$l->dump($l->read_dir_list('/','G:\virtual_machine'));exit();
?>
<!DOCTYPE html>
<html>
<head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="Keywords" content="关键词1,关键词2"><!--关键词--> <meta name="Description" content="描述"><!--描述--> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximun-scale=1.0"><!--宽度为设备宽度,初始缩放为1.0倍,最小缩放为1.0倍,最大缩放为1.0倍--> <!-- 设置浏览器不缓存 begin --> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-control" content="no-cache"> <meta http-equiv="Cache" content="no-cache"> <!-- 设置浏览器不缓存 end --> <title></title>
<style>
/*表格样式部分 start */
.table_box{margin:10px 0 0 0;width:100%;border-collapse:collapse;}
.table_box > thead > tr{height:40px;border:0.5px solid #d5d5d5;box-sizing:border-box;}
.table_box > thead > tr > th{text-align:center;border:0.5px solid #e2e2e2;box-sizing:border-box;}
.table_box > tbody > tr{height:35px;}
.table_box > tbody > tr:nth-of-type(odd){background:#fafafa;}
.table_box > tbody > tr:hover{background:#f1f1f1;}
.table_box > tbody > tr > td{padding:0 0 0 5px;border:0.5px solid #e2e2e2;box-sizing:border-box;}
/*表格样式部分 end */
</style>
</head>
<body>
<table class="table_box">
<thead>
<tr>
<th>ip</th>
<th>添加时间</th>
<th>地址链接</th>
<th>请求方式</th>
<th>http版本</th>
<th>用户信息(user_gent)</th>
<th>accept</th>
</tr>
</thead>
<tbody>
<?php foreach ( $read['data'] as $k => $v): ?>
<tr>
<td><?php echos($v['ip']); ?></td>
<td><?php echos($v['add_time']/*$v[0]*/); ?></td>
<td><?php echos($v['url']); ?></td>
<td><?php echos($v['method']); ?></td>
<td><?php echos($v['protocol']); ?></td>
<td><?php echos($v['user_agent']); ?></td>
<td><?php echos($v['accept']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php
//$l->dump($l->get_body_data_assoc($log_file,0,3));
$l->dump($l->history_link($log_file));
?>
</body>
</html>
图片:
详细代码在我的giee,链接:
https://gitee.com/fang_wen_feng/my_php_plugCode/blob/phpcode/phpCode/log/Log.php
https://gitee.com/fang_wen_feng/my_php_plugCode/blob/phpcode/phpCode/public_functions.php