helper.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare(strict_types=1);
  12. //------------------------
  13. // ThinkPHP 助手函数
  14. //-------------------------
  15. use think\App;
  16. use think\Container;
  17. use think\exception\HttpException;
  18. use think\exception\HttpResponseException;
  19. use think\facade\Cache;
  20. use think\facade\Config;
  21. use think\facade\Cookie;
  22. use think\facade\Env;
  23. use think\facade\Event;
  24. use think\facade\Lang;
  25. use think\facade\Log;
  26. use think\facade\Request;
  27. use think\facade\Route;
  28. use think\facade\Session;
  29. use think\Response;
  30. use think\response\File;
  31. use think\response\Json;
  32. use think\response\Jsonp;
  33. use think\response\Redirect;
  34. use think\response\View;
  35. use think\response\Xml;
  36. use think\route\Url as UrlBuild;
  37. use think\Validate;
  38. if (!function_exists('abort')) {
  39. /**
  40. * 抛出HTTP异常
  41. * @param integer|Response $code 状态码 或者 Response对象实例
  42. * @param string $message 错误信息
  43. * @param array $header 参数
  44. */
  45. function abort($code, string $message = '', array $header = [])
  46. {
  47. if ($code instanceof Response) {
  48. throw new HttpResponseException($code);
  49. } else {
  50. throw new HttpException($code, $message, null, $header);
  51. }
  52. }
  53. }
  54. if (!function_exists('app')) {
  55. /**
  56. * 快速获取容器中的实例 支持依赖注入
  57. * @template T
  58. * @param string|class-string<T> $name 类名或标识 默认获取当前应用实例
  59. * @param array $args 参数
  60. * @param bool $newInstance 是否每次创建新的实例
  61. * @return T|object|App
  62. */
  63. function app(string $name = '', array $args = [], bool $newInstance = false)
  64. {
  65. return Container::getInstance()->make($name ?: App::class, $args, $newInstance);
  66. }
  67. }
  68. if (!function_exists('bind')) {
  69. /**
  70. * 绑定一个类到容器
  71. * @param string|array $abstract 类标识、接口(支持批量绑定)
  72. * @param mixed $concrete 要绑定的类、闭包或者实例
  73. * @return Container
  74. */
  75. function bind($abstract, $concrete = null)
  76. {
  77. return Container::getInstance()->bind($abstract, $concrete);
  78. }
  79. }
  80. if (!function_exists('cache')) {
  81. /**
  82. * 缓存管理
  83. * @param string $name 缓存名称
  84. * @param mixed $value 缓存值
  85. * @param mixed $options 缓存参数
  86. * @param string $tag 缓存标签
  87. * @return mixed
  88. */
  89. function cache(string $name = null, $value = '', $options = null, $tag = null)
  90. {
  91. if (is_null($name)) {
  92. return app('cache');
  93. }
  94. if ('' === $value) {
  95. // 获取缓存
  96. return str_starts_with($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name);
  97. } elseif (is_null($value)) {
  98. // 删除缓存
  99. return Cache::delete($name);
  100. }
  101. // 缓存数据
  102. if (is_array($options)) {
  103. $expire = $options['expire'] ?? null; //修复查询缓存无法设置过期时间
  104. } else {
  105. $expire = $options;
  106. }
  107. if (is_null($tag)) {
  108. return Cache::set($name, $value, $expire);
  109. } else {
  110. return Cache::tag($tag)->set($name, $value, $expire);
  111. }
  112. }
  113. }
  114. if (!function_exists('config')) {
  115. /**
  116. * 获取和设置配置参数
  117. * @param string|array $name 参数名
  118. * @param mixed $value 参数值
  119. * @return mixed
  120. */
  121. function config($name = '', $value = null)
  122. {
  123. if (is_array($name)) {
  124. return Config::set($name, $value);
  125. }
  126. return str_starts_with($name, '?') ? Config::has(substr($name, 1)) : Config::get($name, $value);
  127. }
  128. }
  129. if (!function_exists('cookie')) {
  130. /**
  131. * Cookie管理
  132. * @param string $name cookie名称
  133. * @param mixed $value cookie值
  134. * @param mixed $option 参数
  135. * @return mixed
  136. */
  137. function cookie(string $name, $value = '', $option = null)
  138. {
  139. if (is_null($value)) {
  140. // 删除
  141. Cookie::delete($name, $option ?: []);
  142. } elseif ('' === $value) {
  143. // 获取
  144. return str_starts_with($name, '?') ? Cookie::has(substr($name, 1)) : Cookie::get($name);
  145. } else {
  146. // 设置
  147. return Cookie::set($name, $value, $option);
  148. }
  149. }
  150. }
  151. if (!function_exists('download')) {
  152. /**
  153. * 获取\think\response\Download对象实例
  154. * @param string $filename 要下载的文件
  155. * @param string $name 显示文件名
  156. * @param bool $content 是否为内容
  157. * @param int $expire 有效期(秒)
  158. * @return \think\response\File
  159. */
  160. function download(string $filename, string $name = '', bool $content = false, int $expire = 180): File
  161. {
  162. return Response::create($filename, 'file')->name($name)->isContent($content)->expire($expire);
  163. }
  164. }
  165. if (!function_exists('dump')) {
  166. /**
  167. * 浏览器友好的变量输出
  168. * @param mixed $vars 要输出的变量
  169. * @return void
  170. */
  171. function dump(...$vars)
  172. {
  173. ob_start();
  174. var_dump(...$vars);
  175. $output = ob_get_clean();
  176. $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
  177. if (PHP_SAPI == 'cli') {
  178. $output = PHP_EOL . $output . PHP_EOL;
  179. } else {
  180. if (!extension_loaded('xdebug')) {
  181. $output = htmlspecialchars($output, ENT_SUBSTITUTE);
  182. }
  183. $output = '<pre>' . $output . '</pre>';
  184. }
  185. echo $output;
  186. }
  187. }
  188. if (!function_exists('env')) {
  189. /**
  190. * 获取环境变量值
  191. * @access public
  192. * @param string $name 环境变量名(支持二级 .号分割)
  193. * @param string $default 默认值
  194. * @return mixed
  195. */
  196. function env(string $name = null, $default = null)
  197. {
  198. return Env::get($name, $default);
  199. }
  200. }
  201. if (!function_exists('event')) {
  202. /**
  203. * 触发事件
  204. * @param mixed $event 事件名(或者类名)
  205. * @param mixed $args 参数
  206. * @return mixed
  207. */
  208. function event($event, $args = null)
  209. {
  210. return Event::trigger($event, $args);
  211. }
  212. }
  213. if (!function_exists('halt')) {
  214. /**
  215. * 调试变量并且中断输出
  216. * @param mixed $vars 调试变量或者信息
  217. */
  218. function halt(...$vars)
  219. {
  220. dump(...$vars);
  221. throw new HttpResponseException(Response::create());
  222. }
  223. }
  224. if (!function_exists('input')) {
  225. /**
  226. * 获取输入数据 支持默认值和过滤
  227. * @param string $key 获取的变量名
  228. * @param mixed $default 默认值
  229. * @param string|array|null $filter 过滤方法
  230. * @return mixed
  231. */
  232. function input(string $key = '', $default = null, $filter = '')
  233. {
  234. if (str_starts_with($key, '?')) {
  235. $key = substr($key, 1);
  236. $has = true;
  237. }
  238. if ($pos = strpos($key, '.')) {
  239. // 指定参数来源
  240. $method = substr($key, 0, $pos);
  241. if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
  242. $key = substr($key, $pos + 1);
  243. if ('server' == $method && is_null($default)) {
  244. $default = '';
  245. }
  246. } else {
  247. $method = 'param';
  248. }
  249. } else {
  250. // 默认为自动判断
  251. $method = 'param';
  252. }
  253. return isset($has) ?
  254. request()->has($key, $method) :
  255. request()->$method($key, $default, $filter);
  256. }
  257. }
  258. if (!function_exists('invoke')) {
  259. /**
  260. * 调用反射实例化对象或者执行方法 支持依赖注入
  261. * @param mixed $call 类名或者callable
  262. * @param array $args 参数
  263. * @return mixed
  264. */
  265. function invoke($call, array $args = [])
  266. {
  267. if (is_callable($call)) {
  268. return Container::getInstance()->invoke($call, $args);
  269. }
  270. return Container::getInstance()->invokeClass($call, $args);
  271. }
  272. }
  273. if (!function_exists('json')) {
  274. /**
  275. * 获取\think\response\Json对象实例
  276. * @param mixed $data 返回的数据
  277. * @param int $code 状态码
  278. * @param array $header 头部
  279. * @param array $options 参数
  280. * @return \think\response\Json
  281. */
  282. function json($data = [], $code = 200, $header = [], $options = []): Json
  283. {
  284. return Response::create($data, 'json', $code)->header($header)->options($options);
  285. }
  286. }
  287. if (!function_exists('jsonp')) {
  288. /**
  289. * 获取\think\response\Jsonp对象实例
  290. * @param mixed $data 返回的数据
  291. * @param int $code 状态码
  292. * @param array $header 头部
  293. * @param array $options 参数
  294. * @return \think\response\Jsonp
  295. */
  296. function jsonp($data = [], $code = 200, $header = [], $options = []): Jsonp
  297. {
  298. return Response::create($data, 'jsonp', $code)->header($header)->options($options);
  299. }
  300. }
  301. if (!function_exists('lang')) {
  302. /**
  303. * 获取语言变量值
  304. * @param string $name 语言变量名
  305. * @param array $vars 动态变量值
  306. * @param string $lang 语言
  307. * @return mixed
  308. */
  309. function lang(string $name, array $vars = [], string $lang = '')
  310. {
  311. return Lang::get($name, $vars, $lang);
  312. }
  313. }
  314. if (!function_exists('parse_name')) {
  315. /**
  316. * 字符串命名风格转换
  317. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  318. * @param string $name 字符串
  319. * @param int $type 转换类型
  320. * @param bool $ucfirst 首字母是否大写(驼峰规则)
  321. * @return string
  322. */
  323. function parse_name(string $name, int $type = 0, bool $ucfirst = true): string
  324. {
  325. if ($type) {
  326. $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
  327. return strtoupper($match[1]);
  328. }, $name);
  329. return $ucfirst ? ucfirst($name) : lcfirst($name);
  330. }
  331. return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $name), '_'));
  332. }
  333. }
  334. if (!function_exists('redirect')) {
  335. /**
  336. * 获取\think\response\Redirect对象实例
  337. * @param string $url 重定向地址
  338. * @param int $code 状态码
  339. * @return \think\response\Redirect
  340. */
  341. function redirect(string $url = '', int $code = 302): Redirect
  342. {
  343. return Response::create($url, 'redirect', $code);
  344. }
  345. }
  346. if (!function_exists('request')) {
  347. /**
  348. * 获取当前Request对象实例
  349. * @return Request
  350. */
  351. function request(): \think\Request
  352. {
  353. return app('request');
  354. }
  355. }
  356. if (!function_exists('response')) {
  357. /**
  358. * 创建普通 Response 对象实例
  359. * @param mixed $data 输出数据
  360. * @param int|string $code 状态码
  361. * @param array $header 头信息
  362. * @param string $type
  363. * @return Response
  364. */
  365. function response($data = '', $code = 200, $header = [], $type = 'html'): Response
  366. {
  367. return Response::create($data, $type, $code)->header($header);
  368. }
  369. }
  370. if (!function_exists('session')) {
  371. /**
  372. * Session管理
  373. * @param string $name session名称
  374. * @param mixed $value session值
  375. * @return mixed
  376. */
  377. function session($name = '', $value = '')
  378. {
  379. if (is_null($name)) {
  380. // 清除
  381. Session::clear();
  382. } elseif ('' === $name) {
  383. return Session::all();
  384. } elseif (is_null($value)) {
  385. // 删除
  386. Session::delete($name);
  387. } elseif ('' === $value) {
  388. // 判断或获取
  389. return str_starts_with($name, '?') ? Session::has(substr($name, 1)) : Session::get($name);
  390. } else {
  391. // 设置
  392. Session::set($name, $value);
  393. }
  394. }
  395. }
  396. if (!function_exists('token')) {
  397. /**
  398. * 获取Token令牌
  399. * @param string $name 令牌名称
  400. * @param mixed $type 令牌生成方法
  401. * @return string
  402. */
  403. function token(string $name = '__token__', string $type = 'md5'): string
  404. {
  405. return Request::buildToken($name, $type);
  406. }
  407. }
  408. if (!function_exists('token_field')) {
  409. /**
  410. * 生成令牌隐藏表单
  411. * @param string $name 令牌名称
  412. * @param mixed $type 令牌生成方法
  413. * @return string
  414. */
  415. function token_field(string $name = '__token__', string $type = 'md5'): string
  416. {
  417. $token = Request::buildToken($name, $type);
  418. return '<input type="hidden" name="' . $name . '" value="' . $token . '" />';
  419. }
  420. }
  421. if (!function_exists('token_meta')) {
  422. /**
  423. * 生成令牌meta
  424. * @param string $name 令牌名称
  425. * @param mixed $type 令牌生成方法
  426. * @return string
  427. */
  428. function token_meta(string $name = '__token__', string $type = 'md5'): string
  429. {
  430. $token = Request::buildToken($name, $type);
  431. return '<meta name="csrf-token" content="' . $token . '">';
  432. }
  433. }
  434. if (!function_exists('trace')) {
  435. /**
  436. * 记录日志信息
  437. * @param mixed $log log信息 支持字符串和数组
  438. * @param string $level 日志级别
  439. * @return array|void
  440. */
  441. function trace($log = '[think]', string $level = 'log')
  442. {
  443. if ('[think]' === $log) {
  444. return Log::getLog();
  445. }
  446. Log::record($log, $level);
  447. }
  448. }
  449. if (!function_exists('url')) {
  450. /**
  451. * Url生成
  452. * @param string $url 路由地址
  453. * @param array $vars 变量
  454. * @param bool|string $suffix 生成的URL后缀
  455. * @param bool|string $domain 域名
  456. * @return UrlBuild
  457. */
  458. function url(string $url = '', array $vars = [], $suffix = true, $domain = false): UrlBuild
  459. {
  460. return Route::buildUrl($url, $vars)->suffix($suffix)->domain($domain);
  461. }
  462. }
  463. if (!function_exists('validate')) {
  464. /**
  465. * 生成验证对象
  466. * @param string|array $validate 验证器类名或者验证规则数组
  467. * @param array $message 错误提示信息
  468. * @param bool $batch 是否批量验证
  469. * @param bool $failException 是否抛出异常
  470. * @return Validate
  471. */
  472. function validate($validate = '', array $message = [], bool $batch = false, bool $failException = true): Validate
  473. {
  474. if (is_array($validate) || '' === $validate) {
  475. $v = new Validate();
  476. if (is_array($validate)) {
  477. $v->rule($validate);
  478. }
  479. } else {
  480. if (str_contains($validate, '.')) {
  481. // 支持场景
  482. [$validate, $scene] = explode('.', $validate);
  483. }
  484. $class = str_contains($validate, '\\') ? $validate : app()->parseClass('validate', $validate);
  485. $v = new $class();
  486. if (!empty($scene)) {
  487. $v->scene($scene);
  488. }
  489. }
  490. return $v->message($message)->batch($batch)->failException($failException);
  491. }
  492. }
  493. if (!function_exists('view')) {
  494. /**
  495. * 渲染模板输出
  496. * @param string $template 模板文件
  497. * @param array $vars 模板变量
  498. * @param int $code 状态码
  499. * @param callable $filter 内容过滤
  500. * @return \think\response\View
  501. */
  502. function view(string $template = '', $vars = [], $code = 200, $filter = null): View
  503. {
  504. return Response::create($template, 'view', $code)->assign($vars)->filter($filter);
  505. }
  506. }
  507. if (!function_exists('display')) {
  508. /**
  509. * 渲染模板输出
  510. * @param string $content 渲染内容
  511. * @param array $vars 模板变量
  512. * @param int $code 状态码
  513. * @param callable $filter 内容过滤
  514. * @return \think\response\View
  515. */
  516. function display(string $content, $vars = [], $code = 200, $filter = null): View
  517. {
  518. return Response::create($content, 'view', $code)->isContent(true)->assign($vars)->filter($filter);
  519. }
  520. }
  521. if (!function_exists('xml')) {
  522. /**
  523. * 获取\think\response\Xml对象实例
  524. * @param mixed $data 返回的数据
  525. * @param int $code 状态码
  526. * @param array $header 头部
  527. * @param array $options 参数
  528. * @return \think\response\Xml
  529. */
  530. function xml($data = [], $code = 200, $header = [], $options = []): Xml
  531. {
  532. return Response::create($data, 'xml', $code)->header($header)->options($options);
  533. }
  534. }
  535. if (!function_exists('app_path')) {
  536. /**
  537. * 获取当前应用目录
  538. *
  539. * @param string $path
  540. * @return string
  541. */
  542. function app_path($path = '')
  543. {
  544. return app()->getAppPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
  545. }
  546. }
  547. if (!function_exists('base_path')) {
  548. /**
  549. * 获取应用基础目录
  550. *
  551. * @param string $path
  552. * @return string
  553. */
  554. function base_path($path = '')
  555. {
  556. return app()->getBasePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
  557. }
  558. }
  559. if (!function_exists('config_path')) {
  560. /**
  561. * 获取应用配置目录
  562. *
  563. * @param string $path
  564. * @return string
  565. */
  566. function config_path($path = '')
  567. {
  568. return app()->getConfigPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
  569. }
  570. }
  571. if (!function_exists('public_path')) {
  572. /**
  573. * 获取web根目录
  574. *
  575. * @param string $path
  576. * @return string
  577. */
  578. function public_path($path = '')
  579. {
  580. return app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . ($path ? ltrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $path);
  581. }
  582. }
  583. if (!function_exists('runtime_path')) {
  584. /**
  585. * 获取应用运行时目录
  586. *
  587. * @param string $path
  588. * @return string
  589. */
  590. function runtime_path($path = '')
  591. {
  592. return app()->getRuntimePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
  593. }
  594. }
  595. if (!function_exists('root_path')) {
  596. /**
  597. * 获取项目根目录
  598. *
  599. * @param string $path
  600. * @return string
  601. */
  602. function root_path($path = '')
  603. {
  604. return app()->getRootPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path);
  605. }
  606. }