<?php// id: ecffe70d3af54df9bad97b61918ace7dglobal $ct_path, $ct_log_path;$log_path ="test_php.txt";// 是否先log到buffer,再通過CT_flush()一次性寫入文件$ct_log_buffer =true;$CT_off =true;$request_num =uniqid();$CT_format ="";if ($ct_path) { $dir =dirname($ct_path);if (!file_exists($dir)) {mkdir($dir, 0777,true); } $file =fopen($ct_path,"a+"); $file_ct_log = $file;}if ($ct_log_path) { $dir =dirname($ct_log_path);if (!file_exists($dir)) {mkdir($dir, 0777,true); } $file_ct_log =fopen($ct_log_path,"a+");}$ct_buffer = [];$path_my =__DIR__ ."/common.my.php";if (is_file($path_my)) {require $path_my;}function clear_log() {Global $log_path;unlink($log_path);}function clog($content, $with_lf =true) {Global $log_path; $file =fopen($log_path,"a+");fwrite($file, $content); CT_log($content);if($with_lf) {fwrite($file,"\n"); CT_log("\n"); }fclose($file);}function get_safe($obj, $key, $def =NULL) {if(isset($obj[$key])) {return $obj[$key]; }return $def;}function get_stack_trace($title ="") { $html ="=================stack trace:".$title."\n"; $array =debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);foreach($arrayas $row) { $html .=sprintf("file:%s, line:%d, class:%s, function:%s\n", get_safe($row,'file'), get_safe($row,'line'), get_safe($row,'class'), get_safe($row,'function')); }return $html;}function log_stack_trace($title ="") { clog(get_stack_trace($title));}// error handler function with stack trace.
// use like this:
// $old_error_handler = set_error_handler("err_handler");function err_handler($errno, $errstr, $errfile, $errline){? $errno_map =array(1 =>"E_ERROR", 2 =>"E_WARNING", 4 =>"E_PARSE", 8 =>"E_NOTICE",? ? ? 16 =>"E_CORE_ERROR", 32 =>"E_CORE_WARNING", 64 =>"E_COMPILE_ERROR",? ? ? 128 =>"E_COMPILE_WARNING", 256 =>"E_USER_ERROR", 512 =>"E_USER_WARNING",? ? ? 1024 =>"E_USER_NOTICE", 2048 =>"E_STRICT", 4096 =>"E_RECOVERABLE_ERROR",? ? ? 8192 =>"E_DEPRECATED", 16384 =>"E_USER_DEPRECATED", 32767 =>"E_ALL");? clog(sprintf("------------ %s(%d), msg:%s", $errno_map[$errno], $errno, $errstr));? log_stack_trace("");/* Don't execute PHP internal error handler */
? return true;}// 獲取當(dāng)前系統(tǒng)時間,返回float格式,單位:秒function get_time() {date_default_timezone_set('Asia/Shanghai');list($usec, $sec) =explode(" ",microtime());return ((float)$usec + (float)$sec);}function get_prefix() {return "";Global $ip, $pid;if(!isset($ip)) {? ? ? ? $pid =getmypid();? ? ? ? $ip = $_SERVER['REMOTE_ADDR'];? ? }return $pid.' '.$ip.' '.date("m-d H:i:s ");}function CT($content) {Global $CT_off, $file;if($CT_off || !$file)return;Global $last_time, $first_time, $is_first, $ct_log_buffer, $ct_buffer, $request_num, $CT_format;if ($CT_format =="raw") {? ? ? ? $all_out = $content ."\n";? ? }else {// 通過stack trace計算縮進(jìn)
? ? ? ? $array =debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);? ? ? ? $ignore_count = 0;? ? ? ? $count =count($array);? ? ? ? $ignore_names = ["call_user_func_array","call_user_func","spl_autoload_call"];? ? ? ? $ignore_classes = ["ReflectionClass"];for ($i = 2; $i < $count; $i++) {? ? ? ? ? ? $frame = $array[$i];if (in_array($frame["function"], $ignore_names) ||isset($frame["class"]) &&in_array($frame["class"], $ignore_classes)) {? ? ? ? ? ? ? ? $ignore_count++;? ? ? ? ? ? }? ? ? ? }? ? ? ? $all_out = get_prefix() .str_pad("", $count - 2 - $ignore_count," ") . $request_num ." " . $content;? ? ? ? $cur_time=get_time();if(!$is_first) {? ? ? ? ? ? $is_first =true;? ? ? ? ? ? $last_time = $first_time = $cur_time;? ? ? ? }? ? ? ? $total_time=$cur_time-$first_time;? ? ? ? $delta_time=$cur_time-$last_time;? ? ? ? $overtime_flag ="";// 添加超時標(biāo)記
? ? ? ? if($delta_time * 1000 > 10)? ? ? ? ? ? $overtime_flag ="----overtime";? ? ? ? $all_out = $all_out." cur_time: $cur_time, total_time: $total_time, delta_time: $delta_time $overtime_flag\n";? ? ? ? $last_time=$cur_time;? ? }if ($ct_log_buffer ===true) {? ? ? ? $ct_buffer[] = $all_out;? ? }else {fwrite($file, $all_out);? ? }}/**
* 將buffer的CT內(nèi)容寫入文件
* @param boolean turn_off_buffer, 完成后是否關(guān)閉buffer,以保證通過register_shutdown_function等調(diào)用的函數(shù)能夠被輸出
*/function CT_flush($turn_off_buffer){global $file, $ct_buffer, $ct_log_buffer;if (!$file) {return;? ? }fwrite($file,join("", $ct_buffer));? ? $ct_buffer = [];? ? $ct_log_buffer = !$turn_off_buffer;}function CT_log($content ="", $path =NULL) {Global $file_ct_log;if (!$file_ct_log && !$path) {return;? ? }? ? $content = get_prefix().print_r($content,true)."\n";if($path) {? ? ? ? file_create_path($path);? ? ? ? $file =fopen($path,"a+");if($file) {fwrite($file, $content);fclose($file);? ? ? ? }? ? }else {fwrite($file_ct_log, $content);? ? }}/**
* 日志輸出,使用info level
* @param $content
* @param array $params
* @param string $logger
*/function slog($content, $params = [], $logger ="default"){? ? SeasLog::info($content, $params, $logger);}/**
* 日志輸出,使用debug level
* @param $content
* @param array $params
* @param string $logger
*/function slog_debug($content, $params = [], $logger ="default"){? ? SeasLog::debug($content, $params, $logger);}/**
* 日志輸出,使用error level
* @param $content
* @param array $params
* @param string $logger
*/function slog_error($content, $params = [], $logger ="default"){? ? SeasLog::error($content, $params, $logger);}/**
* 日志輸出,使用warning level
* @param $content
* @param array $params
* @param string $logger
*/function slog_warning($content, $params = [], $logger ="default"){? ? SeasLog::warning($content, $params, $logger);}/*
? ? 獲取指定的http response header 值。
? ? eg:
? ? HTTP/1.1 200 OK
? ? Server: Tengine/2.1.2
? ? Date: Sun, 02 Apr 2017 02:49:34 GMT
? ? Content-Type: text/html; charset=gb2312
? ? Content-Length: 124378
? ? Connection: keep-alive
? ? Cache-Control: private
? ? X-AspNetMvc-Version: 4.0
? ? X-AspNet-Version: 4.0.30319
*/function curl_get_header($ch, $response, $key){? ? $header_size =curl_getinfo($ch,CURLINFO_HEADER_SIZE);? ? $header =substr($response, 0, $header_size);// header processing
? ? $header_arr =explode("\r\n", $header);? ? $value ="";? ? $key .=":";foreach ($header_arras $entry) {if (!strncmp($entry, $key,strlen($key))) {? ? ? ? ? ? $value =trim(substr($entry,strlen($key)));break;? ? ? ? }? ? }return $value;}// 獲取response狀態(tài)碼function curl_get_status($ch, $response){? ? $header_size =curl_getinfo($ch,CURLINFO_HEADER_SIZE);? ? $header =substr($response, 0, $header_size);? ? $header_arr =explode("\r\n", $header);return explode(" ", $header_arr[0])[1];}function startsWith($haystack, $needle){// search backwards starting from haystack length characters from the end
? ? return $needle ==="" ||strrpos($haystack, $needle, -strlen($haystack)) !==FALSE;}// http 301 is handled.function http_get_core($url, &$status =null){? ? CT_log("-----------http_get:" . $url);? ? $ch =curl_init();? ? $status = -1;// 301 最多嵌套3次。
? ? for ($i = 0; $i < 3; $i++) {? ? ? ? $options =array(CURLOPT_HEADER => 1,CURLOPT_POST => 0,// 請求方式為POST
? ? ? ? ? ? CURLOPT_URL => $url,// 請求URL
? ? ? ? ? ? CURLOPT_RETURNTRANSFER => 1,// 獲取請求結(jié)果
? ? ? ? ? ? CURLOPT_TIMEOUT_MS => 30000,// 超時時間(ms)
? ? ? ? ? ? CURLOPT_POSTFIELDS =>http_build_query(array()),// 注入接口參數(shù)
? ? ? ? ? ? CURLOPT_SSL_VERIFYPEER => 0,// 不驗(yàn)證證書
? ? ? ? );curl_setopt_array($ch, $options);curl_setopt($ch,CURLOPT_ENCODING,"gzip,deflate");// 百度不支持
? ? ? ? curl_setopt($ch,CURLOPT_CUSTOMREQUEST,'GET');if (($response =curl_exec($ch))) {// 有的網(wǎng)站header、<head>指定的編碼不一致,會導(dǎo)致亂碼。因此如果有編碼信息,將其轉(zhuǎn)送到client。
? ? ? ? ? ? $content_type = curl_get_header($ch, $response,"Content-Type");if($content_type) {header("Content-Type: " . $content_type);? ? ? ? ? ? }? ? ? ? ? ? $header_size =curl_getinfo($ch,CURLINFO_HEADER_SIZE);? ? ? ? ? ? $status = $code = curl_get_status($ch, $response);if ($code == 301 || $code == 302) {? ? ? ? ? ? ? ? $redirect_url = curl_get_header($ch, $response,"Location");? ? ? ? ? ? ? ? $parsed_re =parse_url($redirect_url);if(isset($parsed_re["host"])) {? ? ? ? ? ? ? ? ? ? $url = $redirect_url;? ? ? ? ? ? ? ? }else {? ? ? ? ? ? ? ? ? ? $parsed =parse_url($url);if(startsWith($redirect_url,"/")) {? ? ? ? ? ? ? ? ? ? ? ? $url = $parsed["schema"]."://" . $parsed["host"] . $redirect_url;? ? ? ? ? ? ? ? ? ? }else {// TODO 相對路徑拼接
? ? ? ? ? ? ? ? ? ? ? ? $content ="relative path TODO";curl_close($ch);return $content;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }continue;? ? ? ? ? ? }else if ($code == 404) {header("Status: 404 Not Found");? ? ? ? ? ? ? ? $msg =array("status" => 404? ? ? ? ? ? ? ? );? ? ? ? ? ? ? ? $content ="<p id='http_util_message_block' style='display: none'>" .json_encode($msg) ."</p>";? ? ? ? ? ? ? ? $content .="404, not found!";? ? ? ? ? ? }else if ($code == 200) {? ? ? ? ? ? ? ? $content =substr($response, $header_size);? ? ? ? ? ? }else {? ? ? ? ? ? ? ? $content ="http error, code=" . $code ."\n" .substr($response, $header_size);? ? ? ? ? ? }? ? ? ? }else {? ? ? ? ? ? $msg =array("status" => -1? ? ? ? ? ? );? ? ? ? ? ? $content ="<p id='http_util_message_block' style='display: none'>" .json_encode($msg) ."</p>";? ? ? ? ? ? $content .="invoke error[" .curl_error($ch) ."]";? ? ? ? }curl_close($ch);return $content;? ? }}// 遞歸為path創(chuàng)建必要的路徑function file_create_path($path){? ? $dir =dirname($path);if ($dir && !file_exists($dir)) {mkdir($dir, 0755,true);? ? }}// $save_path 需要gbk編碼function file_save($content, $save_path, $append){? ? file_create_path($save_path);if ($append) {? ? ? ? $file =fopen($save_path,"a+");if ($file) {fwrite($file, $content);fclose($file);? ? ? ? }? ? }else {file_put_contents($save_path, $content);? ? }}// 默認(rèn)的curl封裝function curl_do($url, $close_after_use =true){? ? CT_log("curl_do: " . $url);? ? $ch =curl_init();? ? $options =array(CURLOPT_HEADER => 0,CURLOPT_POST => 0,// 請求方式為POST
? ? ? ? CURLOPT_URL => $url,// 請求URL
? ? ? ? CURLOPT_RETURNTRANSFER => 1,// 獲取請求結(jié)果
? ? ? ? CURLOPT_TIMEOUT_MS => 30000,// 超時時間(ms)
? ? ? ? CURLOPT_POSTFIELDS =>http_build_query(array()),// 注入接口參數(shù)
? ? ? ? CURLOPT_SSL_VERIFYPEER => 0,// 不驗(yàn)證證書
? ? );curl_setopt_array($ch, $options);curl_setopt($ch,CURLOPT_ENCODING,"gzip");? ? $response =curl_exec($ch);? ? $err =curl_error($ch);if ($err) {? ? ? ? CT_log("curl error: " . $err);? ? }if ($close_after_use) {curl_close($ch);? ? }return array("handle" => $ch,"response" => $response,"err" => $err);}/**
* url拼接,沒有處理user,pass兩個components
* 詳細(xì)定義參見單元測試
* @param $url
* @param $base
* @return string
*/function get_absolute_url($url, $base){// 兩種情況直接返回$url:
? ? if (!$base)return $url;? ? $url_host =parse_url($url,PHP_URL_HOST);if ($url_host) {return $url;? ? }? ? $base_parsed =parse_url($base);? ? $base_scheme = get_safe($base_parsed,"scheme","");? ? $base_host = get_safe($base_parsed,"host","");? ? $base_port =isset($base_parsed["port"]) ?":" . $base_parsed["port"] :"";? ? $base_path = get_safe($base_parsed,"path");if ($base_host) {? ? ? ? $base_calc = $base_scheme ."://" . $base_host . $base_port;if (startsWith($url,"/")) {return $base_calc . $url;? ? ? ? }else if ($base_path) {? ? ? ? ? ? $pos =strrpos($base_path,"/");if ($pos !==false) {? ? ? ? ? ? ? ? $dir =substr($base_path, 0, $pos + 1);// with last "/"
? ? ? ? ? ? ? ? return $base_calc . $dir . $url;? ? ? ? ? ? }else {return $base_calc ."/" . $url;? ? ? ? ? ? }? ? ? ? }else {return $base_calc ."/" . $url;? ? ? ? }? ? }else {if (startsWith($url,"/")) {return $url;? ? ? ? }else if ($base_path) {? ? ? ? ? ? $pos =strrpos($base_path,"/");if ($pos !==false) {? ? ? ? ? ? ? ? $dir =substr($base_path, 0, $pos + 1);// with last "/"
? ? ? ? ? ? ? ? return $dir . $url;? ? ? ? ? ? }else {return $url;? ? ? ? ? ? }? ? ? ? }else {return $url;? ? ? ? }? ? }}function get_absolute_url_tests(){// empty tests
? ? $tests[] = [null,null,null];? ? $tests[] = ["",null,""];? ? $tests[] = [null,"",null];? ? $tests[] = ["","",""];? ? $tests[] = [null,"/","/"];? ? $tests[] = [null,"/a","/"];? ? $tests[] = [null,"/a/","/a/"];? ? $tests[] = ["a.html","b","a.html"];? ? $tests[] = ["a.html","","a.html"];? ? $tests[] = ["a.html","/","/a.html"];? ? $tests[] = ["a/b/c/a.html","http://1.1.1.1","http://1.1.1.1/a/b/c/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83","http://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83/","http://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83/a/b","http://1.1.1.1:83/a/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83/?","http://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83?","http://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","http://1.1.1.1:83?a=b","http://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","https://1.1.1.1:83?a=b#1","https://1.1.1.1:83/a.html"];? ? $tests[] = ["a.html","www.baidu.com?a=b#1","a.html"];// www被認(rèn)為是path
? ? // starts with "/"
? ? $tests[] = ["/a.html","b","/a.html"];? ? $tests[] = ["/a.html","","/a.html"];? ? $tests[] = ["/a.html","/","/a.html"];? ? $tests[] = ["/a/b/c/a.html","http://1.1.1.1","http://1.1.1.1/a/b/c/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83/","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83/a/b","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83/?","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83?","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","http://1.1.1.1:83?a=b","http://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","https://1.1.1.1:83?a=b#1","https://1.1.1.1:83/a.html"];? ? $tests[] = ["/a.html","www.baidu.com?a=b#1","/a.html"];// www被認(rèn)為是path
? ? $r =true;foreach ($testsas $test) {? ? ? ? $abs = get_absolute_url($test[0], $test[1]);echo $abs ."\n";if ($abs !== $test[2]) {? ? ? ? ? ? $r =false;break;? ? ? ? }? ? }echo "pass: " . $r ."\n";// return self tests
? ? $tests_self = [];? ? $tests_self[] = ["http://test.com/a.html","b",""];? ? $tests_self[] = ["http://test.com/a.html","",""];? ? $tests_self[] = ["http://test.com/a.html","/",""];? ? $tests_self[] = ["http://test.com/a/b/c/a.html","http://1.1.1.1",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83/",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83/a/b",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83/?",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83?",""];? ? $tests_self[] = ["http://test.com/a.html","http://1.1.1.1:83?a=b",""];? ? $tests_self[] = ["http://test.com/a.html","https://1.1.1.1:83?a=b#1",""];? ? $tests_self[] = ["http://test.com/a.html","www.baidu.com?a=b#1",""];// www被認(rèn)為是path
? ? echo "-------------------return self test--------:\n";? ? $r =true;foreach ($tests_selfas $test) {? ? ? ? $abs = get_absolute_url($test[0], $test[1]);echo $abs ."\n";if ($abs !== $test[0]) {? ? ? ? ? ? $r =false;break;? ? ? ? }? ? }echo "pass: " . $r ."\n";}/**
* 路徑規(guī)范化。
* eg:
* a/../b => b
* ../a/../../b => ../b
* ./a/../b => ./b
* @param $path
* @return mixed|string
*/function normalize_path($path){if (!$path) {return $path;? ? }? ? $path =str_replace("\\","/", $path);? ? $dotdotCount = 0;// 以".."開頭的處理
? ? $arr =explode("/", $path);? ? $pathStack = [];foreach ($arras $ele) {if ($ele !=="..") {array_push($pathStack, $ele);? ? ? ? }else {if (count($pathStack) === 0) {? ? ? ? ? ? ? ? $dotdotCount++;? ? ? ? ? ? }else {array_pop($pathStack);? ? ? ? ? ? }? ? ? ? }? ? }unset($ele);? ? $r =str_pad("", $dotdotCount,"../");foreach ($pathStackas $path) {if ($r ==="") {? ? ? ? ? ? $r = $path;? ? ? ? }else {? ? ? ? ? ? $r .="/" . $path;? ? ? ? }? ? }return $r;}// 嘗試gbk、utf-8兩種編碼;優(yōu)先嘗試傳入編碼function is_file_ex($path){if (is_file($path)) {return true;? ? }? ? $enc =mb_detect_encoding($path,"gb2312",true);if ($enc ==='EUC-CN') {? ? ? ? $path2 =iconv("gbk","utf-8", $path);? ? }else {? ? ? ? $path2 =iconv("utf-8","gbk", $path);? ? }return is_file($path2);}// 嘗試gbk、utf-8兩種編碼;優(yōu)先嘗試傳入編碼function file_get_contents_ex($path){if (is_file($path)) {return file_get_contents($path);? ? }? ? $enc =mb_detect_encoding($path,"gb2312",true);if ($enc ==='EUC-CN') {? ? ? ? $path2 =iconv("gbk","utf-8", $path);? ? }else {? ? ? ? $path2 =iconv("utf-8","gbk", $path);? ? }if (is_file($path2)) {return file_get_contents($path2);? ? }return false;}// 創(chuàng)建文件lock,如果路徑不存在則創(chuàng)建之function create_file_lock($path, &$output =null){? ? file_create_path($path);? ? $f =null;// 不使用"@",這樣忽略文件存在的報錯,其他異常返回(如權(quán)限問題)
? ? try {? ? ? ? $f =fopen($path,"x");? ? }catch (Exception $e) {? ? ? ? $msg = $e->getMessage();if (strpos($msg,"File exists") ===false &&strpos($msg,"文件已存在") ===false) {? ? ? ? ? ? $output = $e->getMessage() ."\n" . $e->getTraceAsString();? ? ? ? }? ? }return $f;}// 關(guān)閉、釋放文件lockfunction release_file_lock($f, $path){if ($f) {fclose($f);unlink($path);? ? }}/**
* echo udate('Y-m-d H:i:s.u T');
* @param string $format
* @param null $utimestamp
* @return false|string
*/function udate ($format ='u', $utimestamp =null){if (is_null($utimestamp))? ? ? ? $utimestamp =microtime(true);? ? $timestamp =floor($utimestamp);? ? $milliseconds =round(($utimestamp - $timestamp) * 1000000);return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format), $timestamp);}?>