common.php 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkCMF [ WE CAN DO IT MORE SIMPLE ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2013-2019 http://www.thinkcmf.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +---------------------------------------------------------------------
  9. // | Author: Dean <zxxjjforever@163.com>
  10. // +----------------------------------------------------------------------
  11. use think\Db;
  12. use think\facade\Env;
  13. use think\facade\Url;
  14. use dir\Dir;
  15. use think\facade\Route;
  16. use think\Loader;
  17. use cmf\lib\Storage;
  18. use think\facade\Hook;
  19. // 应用公共文件
  20. if (PHP_SAPI == 'cli') {
  21. $apps = cmf_scan_dir(APP_PATH . '*', GLOB_ONLYDIR);
  22. foreach ($apps as $app) {
  23. $commandFile = APP_PATH . $app . '/command.php';
  24. if (file_exists($commandFile)) {
  25. $commands = include $commandFile;
  26. // 注册命令行指令
  27. \think\Console::addDefaultCommands($commands);
  28. }
  29. }
  30. }
  31. /**
  32. * 获取当前登录的管理员ID
  33. * @return int
  34. */
  35. function cmf_get_current_admin_id()
  36. {
  37. return session('ADMIN_ID');
  38. }
  39. /**
  40. * 判断前台用户是否登录
  41. * @return boolean
  42. */
  43. function cmf_is_user_login()
  44. {
  45. $sessionUser = session('user');
  46. return !empty($sessionUser);
  47. }
  48. /**
  49. * 获取当前登录的前台用户的信息,未登录时,返回false
  50. * @return array|boolean
  51. */
  52. function cmf_get_current_user()
  53. {
  54. $sessionUser = session('user');
  55. if (!empty($sessionUser)) {
  56. unset($sessionUser['user_pass']); // 销毁敏感数据
  57. return $sessionUser;
  58. } else {
  59. return false;
  60. }
  61. }
  62. /**
  63. * 更新当前登录前台用户的信息
  64. * @param array $user 前台用户的信息
  65. */
  66. function cmf_update_current_user($user)
  67. {
  68. session('user', $user);
  69. }
  70. /**
  71. * 获取当前登录前台用户id
  72. * @return int
  73. */
  74. function cmf_get_current_user_id()
  75. {
  76. $sessionUserId = session('user.id');
  77. if (empty($sessionUserId)) {
  78. return 0;
  79. }
  80. return $sessionUserId;
  81. }
  82. /**
  83. * 返回带协议的域名
  84. */
  85. function cmf_get_domain()
  86. {
  87. return request()->domain();
  88. }
  89. /**
  90. * 获取网站根目录
  91. * @return string 网站根目录
  92. */
  93. function cmf_get_root()
  94. {
  95. $root = request()->root();
  96. $root = str_replace("//", '/', $root);
  97. $root = str_replace('/index.php', '', $root);
  98. if (defined('APP_NAMESPACE') && APP_NAMESPACE == 'api') {
  99. $root = preg_replace('/\/api(.php)$/', '', $root);
  100. }
  101. $root = rtrim($root, '/');
  102. return $root;
  103. }
  104. /**
  105. * 获取当前主题名
  106. * @return string
  107. */
  108. function cmf_get_current_theme()
  109. {
  110. if (PHP_SAPI != 'cli') {
  111. static $_currentTheme;
  112. if (!empty($_currentTheme)) {
  113. return $_currentTheme;
  114. }
  115. }
  116. $t = 't';
  117. $theme = config('template.cmf_default_theme');
  118. $cmfDetectTheme = config('template.cmf_detect_theme');
  119. if ($cmfDetectTheme) {
  120. if (isset($_GET[$t])) {
  121. $theme = $_GET[$t];
  122. cookie('cmf_template', $theme, 864000);
  123. } elseif (cookie('cmf_template')) {
  124. $theme = cookie('cmf_template');
  125. }
  126. }
  127. $hookTheme = hook_one('switch_theme');
  128. if ($hookTheme) {
  129. $theme = $hookTheme;
  130. }
  131. $designT = '_design_theme';
  132. if (isset($_GET[$designT])) {
  133. $theme = $_GET[$designT];
  134. cookie('cmf_design_theme', $theme, 4);
  135. } elseif (cookie('cmf_design_theme')) {
  136. $theme = cookie('cmf_design_theme');
  137. }
  138. $_currentTheme = $theme;
  139. return $theme;
  140. }
  141. /**
  142. * 获取当前后台主题名
  143. * @return string
  144. */
  145. function cmf_get_current_admin_theme()
  146. {
  147. if (PHP_SAPI != 'cli') {
  148. static $_currentAdminTheme;
  149. if (!empty($_currentAdminTheme)) {
  150. return $_currentAdminTheme;
  151. }
  152. }
  153. $t = '_at';
  154. $theme = config('template.cmf_admin_default_theme');
  155. $cmfDetectTheme = true;
  156. if ($cmfDetectTheme) {
  157. if (isset($_GET[$t])) {
  158. $theme = $_GET[$t];
  159. cookie('cmf_admin_theme', $theme, 864000);
  160. } elseif (cookie('cmf_admin_theme')) {
  161. $theme = cookie('cmf_admin_theme');
  162. }
  163. }
  164. $hookTheme = hook_one('switch_admin_theme');
  165. if ($hookTheme) {
  166. $theme = $hookTheme;
  167. }
  168. $_currentAdminTheme = $theme;
  169. return $theme;
  170. }
  171. /**
  172. * 获取前台模板根目录
  173. * @param string $theme
  174. * @return string 前台模板根目录
  175. */
  176. function cmf_get_theme_path($theme = null)
  177. {
  178. $themePath = config('template.cmf_theme_path');
  179. if ($theme === null) {
  180. // 获取当前主题名称
  181. $theme = cmf_get_current_theme();
  182. }
  183. return WEB_ROOT . $themePath . $theme;
  184. }
  185. /**
  186. * 获取用户头像地址
  187. * @param $avatar 用户头像文件路径,相对于 upload 目录
  188. * @return string
  189. */
  190. function cmf_get_user_avatar_url($avatar)
  191. {
  192. if (!empty($avatar)) {
  193. if (strpos($avatar, "http") === 0) {
  194. return $avatar;
  195. } else {
  196. return cmf_get_image_url($avatar, 'avatar');
  197. }
  198. } else {
  199. return $avatar;
  200. }
  201. }
  202. /**
  203. * CMF密码加密方法
  204. * @param string $pw 要加密的原始密码
  205. * @param string $authCode 加密字符串
  206. * @return string
  207. */
  208. function cmf_password($pw, $authCode = '')
  209. {
  210. if (empty($authCode)) {
  211. $authCode = config('database.authcode');
  212. }
  213. $result = "###" . md5(md5($authCode . $pw));
  214. return $result;
  215. }
  216. /**
  217. * CMF密码加密方法 (X2.0.0以前的方法)
  218. * @param string $pw 要加密的原始密码
  219. * @return string
  220. */
  221. function cmf_password_old($pw)
  222. {
  223. $decor = md5(config('database.prefix'));
  224. $mi = md5($pw);
  225. return substr($decor, 0, 12) . $mi . substr($decor, -4, 4);
  226. }
  227. /**
  228. * CMF密码比较方法,所有涉及密码比较的地方都用这个方法
  229. * @param string $password 要比较的密码
  230. * @param string $passwordInDb 数据库保存的已经加密过的密码
  231. * @return boolean 密码相同,返回true
  232. */
  233. function cmf_compare_password($password, $passwordInDb)
  234. {
  235. if (strpos($passwordInDb, "###") === 0) {
  236. return cmf_password($password) == $passwordInDb;
  237. } else {
  238. return cmf_password_old($password) == $passwordInDb;
  239. }
  240. }
  241. /**
  242. * 文件日志
  243. * @param $content 要写入的内容
  244. * @param string $file 日志文件,在web 入口目录
  245. */
  246. function cmf_log($content, $file = "log.txt")
  247. {
  248. file_put_contents($file, $content, FILE_APPEND);
  249. }
  250. /**
  251. * 随机字符串生成
  252. * @param int $len 生成的字符串长度
  253. * @return string
  254. */
  255. function cmf_random_string($len = 6)
  256. {
  257. $chars = [
  258. "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
  259. "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
  260. "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
  261. "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
  262. "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
  263. "3", "4", "5", "6", "7", "8", "9"
  264. ];
  265. $charsLen = count($chars) - 1;
  266. shuffle($chars); // 将数组打乱
  267. $output = "";
  268. for ($i = 0; $i < $len; $i++) {
  269. $output .= $chars[mt_rand(0, $charsLen)];
  270. }
  271. return $output;
  272. }
  273. /**
  274. * 清空系统缓存
  275. */
  276. function cmf_clear_cache()
  277. {
  278. // 清除 opcache缓存
  279. if (function_exists("opcache_reset")) {
  280. opcache_reset();
  281. }
  282. $dirs = [];
  283. $rootDirs = cmf_scan_dir(Env::get('runtime_path') . "*");
  284. //$noNeedClear=array(".","..","Data");
  285. $noNeedClear = ['.', '..', 'log'];
  286. $rootDirs = array_diff($rootDirs, $noNeedClear);
  287. foreach ($rootDirs as $dir) {
  288. if ($dir != "." && $dir != "..") {
  289. $dir = Env::get('runtime_path') . $dir;
  290. if (is_dir($dir)) {
  291. //array_push ( $dirs, $dir );
  292. $tmpRootDirs = cmf_scan_dir($dir . "/*");
  293. foreach ($tmpRootDirs as $tDir) {
  294. if ($tDir != "." && $tDir != "..") {
  295. $tDir = $dir . '/' . $tDir;
  296. if (is_dir($tDir)) {
  297. array_push($dirs, $tDir);
  298. } else {
  299. // @unlink($tDir);
  300. }
  301. }
  302. }
  303. } else {
  304. // @unlink($dir);
  305. }
  306. }
  307. }
  308. $dirTool = new Dir("");
  309. foreach ($dirs as $dir) {
  310. $dirTool->delDir($dir);
  311. }
  312. }
  313. /**
  314. * 保存数组变量到php文件
  315. * @param string $path 保存路径
  316. * @param mixed $var 要保存的变量
  317. * @return boolean 保存成功返回true,否则false
  318. */
  319. function cmf_save_var($path, $var)
  320. {
  321. $result = file_put_contents($path, "<?php\treturn " . var_export($var, true) . ";?>");
  322. return $result;
  323. }
  324. /**
  325. * 设置动态配置
  326. * @param array $data <br>如:['template' => ['cmf_default_theme' => 'default']];
  327. * @return boolean
  328. */
  329. function cmf_set_dynamic_config($data)
  330. {
  331. if (!is_array($data)) {
  332. return false;
  333. }
  334. foreach ($data as $key => $value) {
  335. if (is_array($value)) {
  336. $configFile = CMF_DATA . "config/{$key}.php";
  337. if (file_exists($configFile)) {
  338. $configs = include $configFile;
  339. } else {
  340. $configs = [];
  341. }
  342. $configs = array_merge($configs, $value);
  343. try {
  344. file_put_contents($configFile, "<?php\treturn " . var_export($configs, true) . ";");
  345. } catch (\Exception $e) {
  346. return false;
  347. }
  348. }
  349. }
  350. cmf_clear_cache();
  351. return true;
  352. }
  353. /**
  354. * 转化格式化的字符串为数组
  355. * @param string $tag 要转化的字符串,格式如:"id:2;cid:1;order:post_date desc;"
  356. * @return array 转化后字符串<pre>
  357. * array(
  358. * 'id'=>'2',
  359. * 'cid'=>'1',
  360. * 'order'=>'post_date desc'
  361. * )
  362. */
  363. function cmf_param_lable($tag = '')
  364. {
  365. $param = [];
  366. $array = explode(';', $tag);
  367. foreach ($array as $v) {
  368. $v = trim($v);
  369. if (!empty($v)) {
  370. list($key, $val) = explode(':', $v);
  371. $param[trim($key)] = trim($val);
  372. }
  373. }
  374. return $param;
  375. }
  376. /**
  377. * 获取后台管理设置的网站信息,此类信息一般用于前台
  378. * @return array
  379. */
  380. function cmf_get_site_info()
  381. {
  382. $siteInfo = cmf_get_option('site_info');
  383. if (isset($siteInfo['site_analytics'])) {
  384. $siteInfo['site_analytics'] = htmlspecialchars_decode($siteInfo['site_analytics']);
  385. }
  386. return $siteInfo;
  387. }
  388. /**
  389. * 获取CMF系统的设置,此类设置用于全局
  390. * @return array
  391. */
  392. function cmf_get_cmf_setting()
  393. {
  394. return cmf_get_option('cmf_setting');
  395. }
  396. /**
  397. * 更新CMF系统的设置,此类设置用于全局
  398. * @param $data
  399. * @return bool
  400. * @throws \think\Exception
  401. * @throws \think\db\exception\DataNotFoundException
  402. * @throws \think\db\exception\ModelNotFoundException
  403. * @throws \think\exception\DbException
  404. * @throws \think\exception\PDOException
  405. */
  406. function cmf_set_cmf_setting($data)
  407. {
  408. if (!is_array($data) || empty($data)) {
  409. return false;
  410. }
  411. return cmf_set_option('cmf_setting', $data);
  412. }
  413. /**
  414. * 设置系统配置,通用
  415. * @param string $key 配置键值,都小写
  416. * @param array $data 配置值,数组
  417. * @param bool $replace 是否完全替换
  418. * @return bool 是否成功
  419. * @throws \think\Exception
  420. * @throws \think\db\exception\DataNotFoundException
  421. * @throws \think\db\exception\ModelNotFoundException
  422. * @throws \think\exception\DbException
  423. * @throws \think\exception\PDOException
  424. */
  425. function cmf_set_option($key, $data, $replace = false)
  426. {
  427. if (!is_array($data) || empty($data) || !is_string($key) || empty($key)) {
  428. return false;
  429. }
  430. $key = strtolower($key);
  431. $option = [];
  432. $findOption = Db::name('option')->where('option_name', $key)->find();
  433. if ($findOption) {
  434. if (!$replace) {
  435. $oldOptionValue = json_decode($findOption['option_value'], true);
  436. if (!empty($oldOptionValue)) {
  437. $data = array_merge($oldOptionValue, $data);
  438. }
  439. }
  440. $option['option_value'] = json_encode($data);
  441. Db::name('option')->where('option_name', $key)->update($option);
  442. // echo Db::name('option')->getLastSql() . "\n";
  443. } else {
  444. $option['option_name'] = $key;
  445. $option['option_value'] = json_encode($data);
  446. Db::name('option')->insert($option);
  447. }
  448. cache('cmf_options_' . $key, null);//删除缓存
  449. return true;
  450. }
  451. /**
  452. * 获取系统配置,通用
  453. * @param string $key 配置键值,都小写
  454. * @return array
  455. */
  456. function cmf_get_option($key)
  457. {
  458. if (!is_string($key) || empty($key)) {
  459. return [];
  460. }
  461. if (PHP_SAPI != 'cli') {
  462. static $cmfGetOption;
  463. if (empty($cmfGetOption)) {
  464. $cmfGetOption = [];
  465. } else {
  466. if (!empty($cmfGetOption[$key])) {
  467. return $cmfGetOption[$key];
  468. }
  469. }
  470. }
  471. $optionValue = cache('cmf_options_' . $key);
  472. if (empty($optionValue)) {
  473. $optionValue = Db::name('option')->where('option_name', $key)->value('option_value');
  474. if (!empty($optionValue)) {
  475. $optionValue = json_decode($optionValue, true);
  476. cache('cmf_options_' . $key, $optionValue);
  477. }
  478. }
  479. $cmfGetOption[$key] = $optionValue;
  480. return $optionValue;
  481. }
  482. /**
  483. * 获取CMF上传配置
  484. */
  485. function cmf_get_upload_setting()
  486. {
  487. $uploadSetting = cmf_get_option('upload_setting');
  488. if (empty($uploadSetting) || empty($uploadSetting['file_types'])) {
  489. $uploadSetting = [
  490. 'file_types' => [
  491. 'image' => [
  492. 'upload_max_filesize' => '10240',//单位KB
  493. 'extensions' => 'jpg,jpeg,png,gif,bmp4'
  494. ],
  495. 'video' => [
  496. 'upload_max_filesize' => '10240',
  497. 'extensions' => 'mp4,avi,wmv,rm,rmvb,mkv'
  498. ],
  499. 'audio' => [
  500. 'upload_max_filesize' => '10240',
  501. 'extensions' => 'mp3,wma,wav'
  502. ],
  503. 'file' => [
  504. 'upload_max_filesize' => '10240',
  505. 'extensions' => 'txt,pdf,doc,docx,xls,xlsx,ppt,pptx,zip,rar'
  506. ]
  507. ],
  508. 'chunk_size' => 512,//单位KB
  509. 'max_files' => 20 //最大同时上传文件数
  510. ];
  511. }
  512. if (empty($uploadSetting['upload_max_filesize'])) {
  513. $uploadMaxFileSizeSetting = [];
  514. foreach ($uploadSetting['file_types'] as $setting) {
  515. $extensions = explode(',', trim($setting['extensions']));
  516. if (!empty($extensions)) {
  517. $uploadMaxFileSize = intval($setting['upload_max_filesize']) * 1024;//转化成B
  518. foreach ($extensions as $ext) {
  519. if (!isset($uploadMaxFileSizeSetting[$ext]) || $uploadMaxFileSize > $uploadMaxFileSizeSetting[$ext]) {
  520. $uploadMaxFileSizeSetting[$ext] = $uploadMaxFileSize;
  521. }
  522. }
  523. }
  524. }
  525. $uploadSetting['upload_max_filesize'] = $uploadMaxFileSizeSetting;
  526. }
  527. return $uploadSetting;
  528. }
  529. /**
  530. * 获取html文本里的img
  531. * @param string $content html 内容
  532. * @return array 图片列表 数组item格式<pre>
  533. * [
  534. * "src"=>'图片链接',
  535. * "title"=>'图片标签的 title 属性',
  536. * "alt"=>'图片标签的 alt 属性'
  537. * ]
  538. * </pre>
  539. */
  540. function cmf_get_content_images($content)
  541. {
  542. //import('phpQuery.phpQuery', EXTEND_PATH);
  543. \phpQuery::newDocumentHTML($content);
  544. $pq = pq(null);
  545. $images = $pq->find("img");
  546. $imagesData = [];
  547. if ($images->length) {
  548. foreach ($images as $img) {
  549. $img = pq($img);
  550. $image = [];
  551. $image['src'] = $img->attr("src");
  552. $image['title'] = $img->attr("title");
  553. $image['alt'] = $img->attr("alt");
  554. array_push($imagesData, $image);
  555. }
  556. }
  557. \phpQuery::$documents = null;
  558. return $imagesData;
  559. }
  560. /**
  561. * 去除字符串中的指定字符
  562. * @param string $str 待处理字符串
  563. * @param string $chars 需去掉的特殊字符
  564. * @return string
  565. */
  566. function cmf_strip_chars($str, $chars = '?<*.>\'\"')
  567. {
  568. return preg_replace('/[' . $chars . ']/is', '', $str);
  569. }
  570. /**
  571. * 发送邮件
  572. * @param string $address 收件人邮箱
  573. * @param string $subject 邮件标题
  574. * @param string $message 邮件内容
  575. * @return array<br>
  576. * 返回格式:<br>
  577. * array(<br>
  578. * "error"=>0|1,//0代表出错<br>
  579. * "message"=> "出错信息"<br>
  580. * );
  581. * @throws phpmailerException
  582. */
  583. function cmf_send_email($address, $subject, $message)
  584. {
  585. $smtpSetting = cmf_get_option('smtp_setting');
  586. $mail = new \PHPMailer\PHPMailer\PHPMailer();
  587. // 设置PHPMailer使用SMTP服务器发送Email
  588. $mail->IsSMTP();
  589. $mail->IsHTML(true);
  590. //$mail->SMTPDebug = 3;
  591. // 设置邮件的字符编码,若不指定,则为'UTF-8'
  592. $mail->CharSet = 'UTF-8';
  593. // 添加收件人地址,可以多次使用来添加多个收件人
  594. $mail->AddAddress($address);
  595. // 设置邮件正文
  596. $mail->Body = $message;
  597. // 设置邮件头的From字段。
  598. $mail->From = $smtpSetting['from'];
  599. // 设置发件人名字
  600. $mail->FromName = $smtpSetting['from_name'];
  601. // 设置邮件标题
  602. $mail->Subject = $subject;
  603. // 设置SMTP服务器。
  604. $mail->Host = $smtpSetting['host'];
  605. //by Rainfer
  606. // 设置SMTPSecure。
  607. $Secure = $smtpSetting['smtp_secure'];
  608. $mail->SMTPSecure = empty($Secure) ? '' : $Secure;
  609. // 设置SMTP服务器端口。
  610. $port = $smtpSetting['port'];
  611. $mail->Port = empty($port) ? "25" : $port;
  612. // 设置为"需要验证"
  613. $mail->SMTPAuth = true;
  614. $mail->SMTPAutoTLS = false;
  615. $mail->Timeout = 10;
  616. // 设置用户名和密码。
  617. $mail->Username = $smtpSetting['username'];
  618. $mail->Password = $smtpSetting['password'];
  619. // 发送邮件。
  620. if (!$mail->Send()) {
  621. $mailError = $mail->ErrorInfo;
  622. return ["error" => 1, "message" => $mailError];
  623. } else {
  624. return ["error" => 0, "message" => "success"];
  625. }
  626. }
  627. /**
  628. * 转化数据库保存的文件路径,为可以访问的url
  629. * @param string $file
  630. * @param mixed $style 图片样式,支持各大云存储
  631. * @return string
  632. */
  633. function cmf_get_asset_url($file, $style = '')
  634. {
  635. if (strpos($file, "http") === 0) {
  636. return $file;
  637. } else if (strpos($file, "/") === 0) {
  638. return $file;
  639. } else {
  640. // $storage = cmf_get_option('storage');
  641. // if (empty($storage['type'])) {
  642. // $storage['type'] = 'Local';
  643. // }
  644. // if ($storage['type'] != 'Local') {
  645. // $watermark = cmf_get_plugin_config($storage['type']);
  646. // $style = empty($style) ? $watermark['styles_watermark'] : $style;
  647. // }
  648. $storage = Storage::instance();
  649. return $storage->getUrl($file, $style);
  650. }
  651. }
  652. /**
  653. * 转化数据库保存图片的文件路径,为可以访问的url
  654. * @param string $file 文件路径,数据存储的文件相对路径
  655. * @param string $style 图片样式,支持各大云存储
  656. * @return string 图片链接
  657. */
  658. function cmf_get_image_url($file, $style = 'watermark')
  659. {
  660. if (empty($file)) {
  661. return '';
  662. }
  663. if (strpos($file, "http") === 0) {
  664. return $file;
  665. } else if (strpos($file, "/") === 0) {
  666. return cmf_get_domain() . $file;
  667. } else {
  668. // $storage = cmf_get_option('storage');
  669. // if (empty($storage['type'])) {
  670. // $storage['type'] = 'Local';
  671. // }
  672. // if ($storage['type'] != 'Local') {
  673. // $watermark = cmf_get_plugin_config($storage['type']);
  674. // $style = empty($style) ? $watermark['styles_watermark'] : $style;
  675. // }
  676. $storage = Storage::instance();
  677. return $storage->getImageUrl($file, $style);
  678. }
  679. }
  680. /**
  681. * 获取图片预览链接
  682. * @param string $file 文件路径,相对于upload
  683. * @param string $style 图片样式,支持各大云存储
  684. * @return string
  685. */
  686. function cmf_get_image_preview_url($file, $style = 'watermark')
  687. {
  688. if (empty($file)) {
  689. return '';
  690. }
  691. if (strpos($file, "http") === 0) {
  692. return $file;
  693. } else if (strpos($file, "/") === 0) {
  694. return $file;
  695. } else {
  696. // $storage = cmf_get_option('storage');
  697. // if (empty($storage['type'])) {
  698. // $storage['type'] = 'Local';
  699. // }
  700. // if ($storage['type'] != 'Local') {
  701. // $watermark = cmf_get_plugin_config($storage['type']);
  702. // $style = empty($style) ? $watermark['styles_watermark'] : $style;
  703. // }
  704. $storage = Storage::instance();
  705. return $storage->getPreviewUrl($file, $style);
  706. }
  707. }
  708. /**
  709. * 获取文件下载链接
  710. * @param string $file 文件路径,数据库里保存的相对路径
  711. * @param int $expires 过期时间,单位 s
  712. * @return string 文件链接
  713. */
  714. function cmf_get_file_download_url($file, $expires = 3600)
  715. {
  716. if (empty($file)) {
  717. return '';
  718. }
  719. if (strpos($file, "http") === 0) {
  720. return $file;
  721. } else if (strpos($file, "/") === 0) {
  722. return $file;
  723. } else if(strpos($file, "#") === 0) {
  724. return $file;
  725. } else {
  726. $storage = Storage::instance();
  727. return $storage->getFileDownloadUrl($file, $expires);
  728. }
  729. }
  730. /**
  731. * 解密用cmf_str_encode加密的字符串
  732. * @param $string 要解密的字符串
  733. * @param string $key 加密时salt
  734. * @param int $expiry 多少秒后过期
  735. * @param string $operation 操作,默认为DECODE
  736. * @return bool|string
  737. */
  738. function cmf_str_decode($string, $key = '', $expiry = 0, $operation = 'DECODE')
  739. {
  740. $ckey_length = 4;
  741. $key = md5($key ? $key : config("database.authcode"));
  742. $keya = md5(substr($key, 0, 16));
  743. $keyb = md5(substr($key, 16, 16));
  744. $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
  745. $cryptkey = $keya . md5($keya . $keyc);
  746. $key_length = strlen($cryptkey);
  747. $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
  748. $string_length = strlen($string);
  749. $result = '';
  750. $box = range(0, 255);
  751. $rndkey = [];
  752. for ($i = 0; $i <= 255; $i++) {
  753. $rndkey[$i] = ord($cryptkey[$i % $key_length]);
  754. }
  755. for ($j = $i = 0; $i < 256; $i++) {
  756. $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  757. $tmp = $box[$i];
  758. $box[$i] = $box[$j];
  759. $box[$j] = $tmp;
  760. }
  761. for ($a = $j = $i = 0; $i < $string_length; $i++) {
  762. $a = ($a + 1) % 256;
  763. $j = ($j + $box[$a]) % 256;
  764. $tmp = $box[$a];
  765. $box[$a] = $box[$j];
  766. $box[$j] = $tmp;
  767. $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  768. }
  769. if ($operation == 'DECODE') {
  770. if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
  771. return substr($result, 26);
  772. } else {
  773. return '';
  774. }
  775. } else {
  776. return $keyc . str_replace('=', '', base64_encode($result));
  777. }
  778. }
  779. /**
  780. * 加密字符串
  781. * @param $string 要加密的字符串
  782. * @param string $key salt
  783. * @param int $expiry 多少秒后过期
  784. * @return bool|string
  785. */
  786. function cmf_str_encode($string, $key = '', $expiry = 0)
  787. {
  788. return cmf_str_decode($string, $key, $expiry, "ENCODE");
  789. }
  790. /**
  791. * 获取文件相对路径
  792. * @param string $assetUrl 文件的URL
  793. * @return string
  794. */
  795. function cmf_asset_relative_url($assetUrl)
  796. {
  797. if (strpos($assetUrl, "http") === 0) {
  798. return $assetUrl;
  799. } else {
  800. return str_replace('/upload/', '', $assetUrl);
  801. }
  802. }
  803. /**
  804. * 检查用户对某个url内容的可访问性,用于记录如是否赞过,是否访问过等等;开发者可以自由控制,对于没有必要做的检查可以不做,以减少服务器压力
  805. * @param string $object 访问对象的id,格式:不带前缀的表名+id;如post1表示xx_post表里id为1的记录;如果object为空,表示只检查对某个url访问的合法性
  806. * @param int $countLimit 访问次数限制,如1,表示只能访问一次
  807. * @param boolean $ipLimit ip限制,false为不限制,true为限制
  808. * @param int $expire 距离上次访问的最小时间单位s,0表示不限制,大于0表示最后访问$expire秒后才可以访问
  809. * @return true 可访问,false不可访问
  810. * @throws \think\Exception
  811. * @throws \think\db\exception\DataNotFoundException
  812. * @throws \think\db\exception\ModelNotFoundException
  813. * @throws \think\exception\DbException
  814. * @throws \think\exception\PDOException
  815. */
  816. function cmf_check_user_action($object = "", $countLimit = 1, $ipLimit = false, $expire = 0)
  817. {
  818. $request = request();
  819. $action = $request->module() . "/" . $request->controller() . "/" . $request->action();
  820. if (is_array($object)) {
  821. $userId = $object['user_id'];
  822. $object = $object['object'];
  823. } else {
  824. $userId = cmf_get_current_user_id();
  825. }
  826. $ip = get_client_ip(0, true);//修复ip获取
  827. $where = ["user_id" => $userId, "action" => $action, "object" => $object];
  828. if ($ipLimit) {
  829. $where['ip'] = $ip;
  830. }
  831. $findLog = Db::name('user_action_log')->where($where)->find();
  832. $time = time();
  833. if ($findLog) {
  834. Db::name('user_action_log')->where($where)->update([
  835. "count" => Db::raw("count+1"),
  836. "last_visit_time" => $time,
  837. "ip" => $ip
  838. ]);
  839. if ($findLog['count'] >= $countLimit) {
  840. return false;
  841. }
  842. if ($expire > 0 && ($time - $findLog['last_visit_time']) < $expire) {
  843. return false;
  844. }
  845. } else {
  846. Db::name('user_action_log')->insert([
  847. "user_id" => $userId,
  848. "action" => $action,
  849. "object" => $object,
  850. "count" => Db::raw("count+1"),
  851. "last_visit_time" => $time, "ip" => $ip
  852. ]);
  853. }
  854. return true;
  855. }
  856. /**
  857. * 判断是否为手机访问
  858. * @return boolean
  859. */
  860. function cmf_is_mobile()
  861. {
  862. if (PHP_SAPI != 'cli') {
  863. static $cmf_is_mobile;
  864. if (isset($cmf_is_mobile))
  865. return $cmf_is_mobile;
  866. }
  867. $cmf_is_mobile = request()->isMobile();
  868. return $cmf_is_mobile;
  869. }
  870. /**
  871. * 判断是否为微信访问
  872. * @return boolean
  873. */
  874. function cmf_is_wechat()
  875. {
  876. if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
  877. return true;
  878. }
  879. return false;
  880. }
  881. /**
  882. * 判断是否为Android访问
  883. * @return boolean
  884. */
  885. function cmf_is_android()
  886. {
  887. if (strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false) {
  888. return true;
  889. }
  890. return false;
  891. }
  892. /**
  893. * 判断是否为ios访问
  894. * @return boolean
  895. */
  896. function cmf_is_ios()
  897. {
  898. if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strpos($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
  899. return true;
  900. }
  901. return false;
  902. }
  903. /**
  904. * 判断是否为iPhone访问
  905. * @return boolean
  906. */
  907. function cmf_is_iphone()
  908. {
  909. if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone')) {
  910. return true;
  911. }
  912. return false;
  913. }
  914. /**
  915. * 判断是否为iPad访问
  916. * @return boolean
  917. */
  918. function cmf_is_ipad()
  919. {
  920. if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
  921. return true;
  922. }
  923. return false;
  924. }
  925. /**
  926. * 添加钩子
  927. * @param string $hook 钩子名称
  928. * @param mixed $params 传入参数
  929. * @return void
  930. */
  931. function hook($hook, $params = null)
  932. {
  933. return Hook::listen($hook, $params);
  934. }
  935. /**
  936. * 添加钩子,只执行一个
  937. * @param string $hook 钩子名称
  938. * @param mixed $params 传入参数
  939. * @return mixed
  940. */
  941. function hook_one($hook, $params = null)
  942. {
  943. return Hook::listen($hook, $params, true);
  944. }
  945. /**
  946. * 获取插件类名
  947. * @param string $name 插件名
  948. * @return string
  949. */
  950. function cmf_get_plugin_class($name)
  951. {
  952. $name = ucwords($name);
  953. $pluginDir = cmf_parse_name($name);
  954. $class = "plugins\\{$pluginDir}\\{$name}Plugin";
  955. return $class;
  956. }
  957. /**
  958. * 获取插件配置
  959. * @param string $name 插件名,大驼峰格式
  960. * @return array
  961. */
  962. function cmf_get_plugin_config($name)
  963. {
  964. $class = cmf_get_plugin_class($name);
  965. if (class_exists($class)) {
  966. $plugin = new $class();
  967. return $plugin->getConfig();
  968. } else {
  969. return [];
  970. }
  971. }
  972. /**
  973. * 替代scan_dir的方法
  974. * @param string $pattern 检索模式 搜索模式 *.txt,*.doc; (同glog方法)
  975. * @param int $flags
  976. * @param $pattern
  977. * @return array
  978. */
  979. function cmf_scan_dir($pattern, $flags = null)
  980. {
  981. $files = glob($pattern, $flags);
  982. if (empty($files)) {
  983. $files = [];
  984. } else {
  985. $files = array_map('basename', $files);
  986. }
  987. return $files;
  988. }
  989. /**
  990. * 获取某个目录下所有子目录
  991. * @param $dir
  992. * @return array
  993. */
  994. function cmf_sub_dirs($dir)
  995. {
  996. $dir = ltrim($dir, "/");
  997. $dirs = [];
  998. $subDirs = cmf_scan_dir("$dir/*", GLOB_ONLYDIR);
  999. if (!empty($subDirs)) {
  1000. foreach ($subDirs as $subDir) {
  1001. $subDir = "$dir/$subDir";
  1002. array_push($dirs, $subDir);
  1003. $subDirSubDirs = cmf_sub_dirs($subDir);
  1004. if (!empty($subDirSubDirs)) {
  1005. $dirs = array_merge($dirs, $subDirSubDirs);
  1006. }
  1007. }
  1008. }
  1009. return $dirs;
  1010. }
  1011. /**
  1012. * 生成访问插件的url
  1013. * @param string $url url格式:插件名://控制器名/方法
  1014. * @param array $vars 参数
  1015. * @param bool $domain 是否显示域名 或者直接传入域名
  1016. * @return string
  1017. */
  1018. function cmf_plugin_url($url, $vars = [], $domain = false)
  1019. {
  1020. global $CMF_GV_routes;
  1021. if (empty($CMF_GV_routes)) {
  1022. $routeModel = new \app\admin\model\RouteModel();
  1023. $CMF_GV_routes = $routeModel->getRoutes();
  1024. }
  1025. $url = parse_url($url);
  1026. $case_insensitive = true;
  1027. $plugin = $case_insensitive ? Loader::parseName($url['scheme']) : $url['scheme'];
  1028. $controller = $case_insensitive ? Loader::parseName($url['host']) : $url['host'];
  1029. $action = trim($case_insensitive ? strtolower($url['path']) : $url['path'], '/');
  1030. /* 解析URL带的参数 */
  1031. if (isset($url['query'])) {
  1032. parse_str($url['query'], $query);
  1033. $vars = array_merge($query, $vars);
  1034. }
  1035. /* 基础参数 */
  1036. $params = [
  1037. '_plugin' => $plugin,
  1038. '_controller' => $controller,
  1039. '_action' => $action,
  1040. ];
  1041. $pluginUrl = '\\cmf\\controller\\PluginController@index?' . http_build_query($params);
  1042. if (!empty($vars) && !empty($CMF_GV_routes[$pluginUrl])) {
  1043. foreach ($CMF_GV_routes[$pluginUrl] as $actionRoute) {
  1044. $sameVars = array_intersect_assoc($vars, $actionRoute['vars']);
  1045. if (count($sameVars) == count($actionRoute['vars'])) {
  1046. ksort($sameVars);
  1047. $pluginUrl = $pluginUrl . '&' . http_build_query($sameVars);
  1048. $vars = array_diff_assoc($vars, $sameVars);
  1049. break;
  1050. }
  1051. }
  1052. }
  1053. return url($pluginUrl, $vars, true, $domain);
  1054. }
  1055. /**
  1056. * 检查权限
  1057. * @param $userId int 要检查权限的用户 ID
  1058. * @param $name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
  1059. * @param $relation string 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
  1060. * @return boolean 通过验证返回true;失败返回false
  1061. */
  1062. function cmf_auth_check($userId, $name = null, $relation = 'or')
  1063. {
  1064. if (empty($userId)) {
  1065. return false;
  1066. }
  1067. if ($userId == 1) {
  1068. return true;
  1069. }
  1070. $authObj = new \cmf\lib\Auth();
  1071. if (empty($name)) {
  1072. $request = request();
  1073. $module = $request->module();
  1074. $controller = $request->controller();
  1075. $action = $request->action();
  1076. $name = strtolower($module . "/" . $controller . "/" . $action);
  1077. }
  1078. return $authObj->check($userId, $name, $relation);
  1079. }
  1080. function cmf_alpha_id($in, $to_num = false, $pad_up = 4, $passKey = null)
  1081. {
  1082. $index = "aBcDeFgHiJkLmNoPqRsTuVwXyZAbCdEfGhIjKlMnOpQrStUvWxYz0123456789";
  1083. if ($passKey !== null) {
  1084. // Although this function's purpose is to just make the
  1085. // ID short - and not so much secure,
  1086. // with this patch by Simon Franz (http://blog.snaky.org/)
  1087. // you can optionally supply a password to make it harder
  1088. // to calculate the corresponding numeric ID
  1089. for ($n = 0; $n < strlen($index); $n++) $i[] = substr($index, $n, 1);
  1090. $passhash = hash('sha256', $passKey);
  1091. $passhash = (strlen($passhash) < strlen($index)) ? hash('sha512', $passKey) : $passhash;
  1092. for ($n = 0; $n < strlen($index); $n++) $p[] = substr($passhash, $n, 1);
  1093. array_multisort($p, SORT_DESC, $i);
  1094. $index = implode($i);
  1095. }
  1096. $base = strlen($index);
  1097. if ($to_num) {
  1098. // Digital number <<-- alphabet letter code
  1099. $in = strrev($in);
  1100. $out = 0;
  1101. $len = strlen($in) - 1;
  1102. for ($t = 0; $t <= $len; $t++) {
  1103. $bcpow = pow($base, $len - $t);
  1104. $out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
  1105. }
  1106. if (is_numeric($pad_up)) {
  1107. $pad_up--;
  1108. if ($pad_up > 0) $out -= pow($base, $pad_up);
  1109. }
  1110. $out = sprintf('%F', $out);
  1111. $out = substr($out, 0, strpos($out, '.'));
  1112. } else {
  1113. // Digital number -->> alphabet letter code
  1114. if (is_numeric($pad_up)) {
  1115. $pad_up--;
  1116. if ($pad_up > 0) $in += pow($base, $pad_up);
  1117. }
  1118. $out = "";
  1119. for ($t = floor(log($in, $base)); $t >= 0; $t--) {
  1120. $bcp = pow($base, $t);
  1121. $a = floor($in / $bcp) % $base;
  1122. $out = $out . substr($index, $a, 1);
  1123. $in = $in - ($a * $bcp);
  1124. }
  1125. $out = strrev($out); // reverse
  1126. }
  1127. return $out;
  1128. }
  1129. /**
  1130. * 验证码检查,验证完后销毁验证码
  1131. * @param string $value 要验证的字符串
  1132. * @param string $id 验证码的ID
  1133. * @param bool $reset 验证成功后是否重置
  1134. * @return bool
  1135. */
  1136. function cmf_captcha_check($value, $id = "", $reset = true)
  1137. {
  1138. $captcha = new \think\captcha\Captcha();
  1139. $captcha->reset = $reset;
  1140. return $captcha->check($value, $id);
  1141. }
  1142. /**
  1143. * 切分SQL文件成多个可以单独执行的sql语句
  1144. * @param $file string sql文件路径
  1145. * @param $tablePre string 表前缀
  1146. * @param string $charset 字符集
  1147. * @param string $defaultTablePre 默认表前缀
  1148. * @param string $defaultCharset 默认字符集
  1149. * @return array
  1150. */
  1151. function cmf_split_sql($file, $tablePre, $charset = 'utf8mb4', $defaultTablePre = 'cmf_', $defaultCharset = 'utf8mb4')
  1152. {
  1153. if (file_exists($file)) {
  1154. //读取SQL文件
  1155. $sql = file_get_contents($file);
  1156. $sql = str_replace("\r", "\n", $sql);
  1157. $sql = str_replace("BEGIN;\n", '', $sql);//兼容 navicat 导出的 insert 语句
  1158. $sql = str_replace("COMMIT;\n", '', $sql);//兼容 navicat 导出的 insert 语句
  1159. $sql = str_replace($defaultCharset, $charset, $sql);
  1160. $sql = trim($sql);
  1161. //替换表前缀
  1162. $sql = str_replace(" `{$defaultTablePre}", " `{$tablePre}", $sql);
  1163. $sqls = explode(";\n", $sql);
  1164. return $sqls;
  1165. }
  1166. return [];
  1167. }
  1168. /**
  1169. * 判断当前的语言包,并返回语言包名
  1170. * @return string 语言包名
  1171. */
  1172. function cmf_current_lang()
  1173. {
  1174. return request()->langset();
  1175. }
  1176. /**
  1177. * 获取惟一订单号
  1178. * @return string
  1179. */
  1180. function cmf_get_order_sn()
  1181. {
  1182. return date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  1183. }
  1184. /**
  1185. * 获取文件扩展名
  1186. * @param string $filename 文件名
  1187. * @return string 文件扩展名
  1188. */
  1189. function cmf_get_file_extension($filename)
  1190. {
  1191. $pathinfo = pathinfo($filename);
  1192. return strtolower($pathinfo['extension']);
  1193. }
  1194. /**
  1195. * 检查手机或邮箱是否还可以发送验证码,并返回生成的验证码
  1196. * @param string $account 手机或邮箱
  1197. * @param integer $length 验证码位数,支持4,6,8
  1198. * @return string 数字验证码
  1199. * @throws \think\db\exception\DataNotFoundException
  1200. * @throws \think\db\exception\ModelNotFoundException
  1201. * @throws \think\exception\DbException
  1202. */
  1203. function cmf_get_verification_code($account, $length = 6)
  1204. {
  1205. if (empty($account)) return false;
  1206. $verificationCodeQuery = Db::name('verification_code');
  1207. $currentTime = time();
  1208. $maxCount = 5;
  1209. $findVerificationCode = $verificationCodeQuery->where('account', $account)->find();
  1210. $result = false;
  1211. if (empty($findVerificationCode)) {
  1212. $result = true;
  1213. } else {
  1214. $sendTime = $findVerificationCode['send_time'];
  1215. $todayStartTime = strtotime(date('Y-m-d', $currentTime));
  1216. if ($sendTime < $todayStartTime) {
  1217. $result = true;
  1218. } else if ($findVerificationCode['count'] < $maxCount) {
  1219. $result = true;
  1220. }
  1221. }
  1222. if ($result) {
  1223. switch ($length) {
  1224. case 4:
  1225. $result = rand(1000, 9999);
  1226. break;
  1227. case 6:
  1228. $result = rand(100000, 999999);
  1229. break;
  1230. case 8:
  1231. $result = rand(10000000, 99999999);
  1232. break;
  1233. default:
  1234. $result = rand(100000, 999999);
  1235. }
  1236. }
  1237. return $result;
  1238. }
  1239. /**
  1240. * 更新手机或邮箱验证码发送日志
  1241. * @param string $account 手机或邮箱
  1242. * @param string $code 验证码
  1243. * @param int $expireTime 过期时间
  1244. * @return int|string
  1245. * @throws \think\Exception
  1246. * @throws \think\db\exception\DataNotFoundException
  1247. * @throws \think\db\exception\ModelNotFoundException
  1248. * @throws \think\exception\DbException
  1249. * @throws \think\exception\PDOException
  1250. */
  1251. function cmf_verification_code_log($account, $code, $expireTime = 0)
  1252. {
  1253. $currentTime = time();
  1254. $expireTime = $expireTime > $currentTime ? $expireTime : $currentTime + 30 * 60;
  1255. $findVerificationCode = Db::name('verification_code')->where('account', $account)->find();
  1256. if ($findVerificationCode) {
  1257. $todayStartTime = strtotime(date("Y-m-d"));//当天0点
  1258. if ($findVerificationCode['send_time'] <= $todayStartTime) {
  1259. $count = 1;
  1260. } else {
  1261. $count = Db::raw('count+1');
  1262. }
  1263. $result = Db::name('verification_code')
  1264. ->where('account', $account)
  1265. ->update([
  1266. 'send_time' => $currentTime,
  1267. 'expire_time' => $expireTime,
  1268. 'code' => $code,
  1269. 'count' => $count
  1270. ]);
  1271. } else {
  1272. $result = Db::name('verification_code')
  1273. ->insert([
  1274. 'account' => $account,
  1275. 'send_time' => $currentTime,
  1276. 'code' => $code,
  1277. 'count' => 1,
  1278. 'expire_time' => $expireTime
  1279. ]);
  1280. }
  1281. return $result;
  1282. }
  1283. /**
  1284. * 手机或邮箱验证码检查,验证完后销毁验证码增加安全性,返回true验证码正确,false验证码错误
  1285. * @param string $account 手机或邮箱
  1286. * @param string $code 验证码
  1287. * @param boolean $clear 是否验证后销毁验证码
  1288. * @return string 错误消息,空字符串代码验证码正确
  1289. * @return string
  1290. * @throws \think\Exception
  1291. * @throws \think\db\exception\DataNotFoundException
  1292. * @throws \think\db\exception\ModelNotFoundException
  1293. * @throws \think\exception\DbException
  1294. * @throws \think\exception\PDOException
  1295. */
  1296. function cmf_check_verification_code($account, $code, $clear = false)
  1297. {
  1298. $findVerificationCode = Db::name('verification_code')->where('account', $account)->find();
  1299. if ($findVerificationCode) {
  1300. if ($findVerificationCode['expire_time'] > time()) {
  1301. if ($code == $findVerificationCode['code']) {
  1302. if ($clear) {
  1303. Db::name('verification_code')->where('account', $account)->update(['code' => '']);
  1304. }
  1305. } else {
  1306. return "验证码不正确!";
  1307. }
  1308. } else {
  1309. return "验证码已经过期,请先获取验证码!";
  1310. }
  1311. } else {
  1312. return "请先获取验证码!";
  1313. }
  1314. return "";
  1315. }
  1316. /**
  1317. * 清除某个手机或邮箱的数字验证码,一般在验证码验证正确完成后
  1318. * @param string $account 手机或邮箱
  1319. * @return boolean true:手机验证码正确,false:手机验证码错误
  1320. * @throws \think\Exception
  1321. * @throws \think\exception\PDOException
  1322. */
  1323. function cmf_clear_verification_code($account)
  1324. {
  1325. $verificationCodeQuery = Db::name('verification_code');
  1326. $result = $verificationCodeQuery->where('account', $account)->update(['code' => '']);
  1327. return $result;
  1328. }
  1329. /**
  1330. * 区分大小写的文件存在判断
  1331. * @param string $filename 文件地址
  1332. * @return boolean
  1333. */
  1334. function file_exists_case($filename)
  1335. {
  1336. if (is_file($filename)) {
  1337. if (APP_DEBUG) {
  1338. if (basename(realpath($filename)) != basename($filename))
  1339. return false;
  1340. }
  1341. return true;
  1342. }
  1343. return false;
  1344. }
  1345. /**
  1346. * 生成用户 token
  1347. * @param $userId
  1348. * @param $deviceType
  1349. * @return string 用户 token
  1350. * @throws \think\Exception
  1351. * @throws \think\db\exception\DataNotFoundException
  1352. * @throws \think\db\exception\ModelNotFoundException
  1353. * @throws \think\exception\DbException
  1354. * @throws \think\exception\PDOException
  1355. */
  1356. function cmf_generate_user_token($userId, $deviceType)
  1357. {
  1358. $userTokenQuery = Db::name("user_token")
  1359. ->where('user_id', $userId)
  1360. ->where('device_type', $deviceType);
  1361. $findUserToken = $userTokenQuery->find();
  1362. $currentTime = time();
  1363. $expireTime = $currentTime + 24 * 3600 * 180;
  1364. $token = md5(uniqid()) . md5(uniqid());
  1365. if (empty($findUserToken)) {
  1366. Db::name("user_token")->insert([
  1367. 'token' => $token,
  1368. 'user_id' => $userId,
  1369. 'expire_time' => $expireTime,
  1370. 'create_time' => $currentTime,
  1371. 'device_type' => $deviceType
  1372. ]);
  1373. } else {
  1374. if ($findUserToken['expire_time'] > time() && !empty($findUserToken['token'])) {
  1375. $token = $findUserToken['token'];
  1376. } else {
  1377. Db::name("user_token")
  1378. ->where('user_id', $userId)
  1379. ->where('device_type', $deviceType)
  1380. ->update([
  1381. 'token' => $token,
  1382. 'expire_time' => $expireTime,
  1383. 'create_time' => $currentTime
  1384. ]);
  1385. }
  1386. }
  1387. return $token;
  1388. }
  1389. /**
  1390. * 字符串命名风格转换
  1391. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  1392. * @param string $name 字符串
  1393. * @param integer $type 转换类型
  1394. * @param bool $ucfirst 首字母是否大写(驼峰规则)
  1395. * @return string
  1396. */
  1397. function cmf_parse_name($name, $type = 0, $ucfirst = true)
  1398. {
  1399. return Loader::parseName($name, $type, $ucfirst);
  1400. }
  1401. /**
  1402. * 判断字符串是否为已经序列化过
  1403. * @param $str
  1404. * @return bool
  1405. */
  1406. function cmf_is_serialized($str)
  1407. {
  1408. return ($str == serialize(false) || @unserialize($str) !== false);
  1409. }
  1410. /**
  1411. * 判断是否SSL协议
  1412. * @return boolean
  1413. */
  1414. function cmf_is_ssl()
  1415. {
  1416. if (isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))) {
  1417. return true;
  1418. } elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
  1419. return true;
  1420. }
  1421. return false;
  1422. }
  1423. /**
  1424. * 获取CMF系统的设置,此类设置用于全局
  1425. * @param string $key 设置key,为空时返回所有配置信息
  1426. * @return array|bool|mixed
  1427. * @throws \think\db\exception\DataNotFoundException
  1428. * @throws \think\db\exception\ModelNotFoundException
  1429. * @throws \think\exception\DbException
  1430. */
  1431. function cmf_get_cmf_settings($key = "")
  1432. {
  1433. $cmfSettings = cache("cmf_settings");
  1434. if (empty($cmfSettings)) {
  1435. $objOptions = new \app\admin\model\OptionModel();
  1436. $objResult = $objOptions->where("option_name", 'cmf_settings')->find();
  1437. $arrOption = $objResult ? $objResult->toArray() : [];
  1438. if ($arrOption) {
  1439. $cmfSettings = json_decode($arrOption['option_value'], true);
  1440. } else {
  1441. $cmfSettings = [];
  1442. }
  1443. cache("cmf_settings", $cmfSettings);
  1444. }
  1445. if (!empty($key)) {
  1446. if (isset($cmfSettings[$key])) {
  1447. return $cmfSettings[$key];
  1448. } else {
  1449. return false;
  1450. }
  1451. }
  1452. return $cmfSettings;
  1453. }
  1454. /**
  1455. * @deprecated
  1456. * 判读是否sae环境
  1457. * @return bool
  1458. */
  1459. function cmf_is_sae()
  1460. {
  1461. if (function_exists('saeAutoLoader')) {
  1462. return true;
  1463. } else {
  1464. return false;
  1465. }
  1466. }
  1467. /**
  1468. * 获取客户端IP地址
  1469. * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
  1470. * @param boolean $adv 是否进行高级模式获取(有可能被伪装)
  1471. * @return string
  1472. */
  1473. function get_client_ip($type = 0, $adv = true)
  1474. {
  1475. return request()->ip($type, $adv);
  1476. }
  1477. /**
  1478. * 生成base64的url,用于数据库存放 url
  1479. * @param $url 路由地址,如 控制器/方法名,应用/控制器/方法名
  1480. * @param $params url参数
  1481. * @return string
  1482. */
  1483. function cmf_url_encode($url, $params)
  1484. {
  1485. // 解析参数
  1486. if (is_string($params)) {
  1487. // aaa=1&bbb=2 转换成数组
  1488. parse_str($params, $params);
  1489. }
  1490. return base64_encode(json_encode(['action' => $url, 'param' => $params]));
  1491. }
  1492. /**
  1493. * CMF Url生成
  1494. * @param string $url 路由地址
  1495. * @param string|array $vars 变量
  1496. * @param bool|string $suffix 生成的URL后缀
  1497. * @param bool|string $domain 域名
  1498. * @return string
  1499. * @throws \think\db\exception\DataNotFoundException
  1500. * @throws \think\db\exception\ModelNotFoundException
  1501. * @throws \think\exception\DbException
  1502. */
  1503. function cmf_url($url = '', $vars = '', $suffix = true, $domain = false)
  1504. {
  1505. global $CMF_GV_routes;
  1506. if (empty($CMF_GV_routes)) {
  1507. $routeModel = new \app\admin\model\RouteModel();
  1508. $CMF_GV_routes = $routeModel->getRoutes();
  1509. }
  1510. if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {
  1511. $info = parse_url($url);
  1512. $url = !empty($info['path']) ? $info['path'] : '';
  1513. if (isset($info['fragment'])) {
  1514. // 解析锚点
  1515. $anchor = $info['fragment'];
  1516. if (false !== strpos($anchor, '?')) {
  1517. // 解析参数
  1518. list($anchor, $info['query']) = explode('?', $anchor, 2);
  1519. }
  1520. if (false !== strpos($anchor, '@')) {
  1521. // 解析域名
  1522. list($anchor, $domain) = explode('@', $anchor, 2);
  1523. }
  1524. } elseif (strpos($url, '@') && false === strpos($url, '\\')) {
  1525. // 解析域名
  1526. list($url, $domain) = explode('@', $url, 2);
  1527. }
  1528. }
  1529. // 解析参数
  1530. if (is_string($vars)) {
  1531. // aaa=1&bbb=2 转换成数组
  1532. parse_str($vars, $vars);
  1533. }
  1534. if (isset($info['query'])) {
  1535. // 解析地址里面参数 合并到vars
  1536. parse_str($info['query'], $params);
  1537. $vars = array_merge($params, $vars);
  1538. }
  1539. if (!empty($vars) && !empty($CMF_GV_routes[$url])) {
  1540. foreach ($CMF_GV_routes[$url] as $actionRoute) {
  1541. $sameVars = array_intersect_assoc($vars, $actionRoute['vars']);
  1542. if (count($sameVars) == count($actionRoute['vars'])) {
  1543. ksort($sameVars);
  1544. $url = $url . '?' . http_build_query($sameVars);
  1545. $vars = array_diff_assoc($vars, $sameVars);
  1546. break;
  1547. }
  1548. }
  1549. }
  1550. if (!empty($anchor)) {
  1551. $url = $url . '#' . $anchor;
  1552. }
  1553. // if (!empty($domain)) {
  1554. // $url = $url . '@' . $domain;
  1555. // }
  1556. return Url::build($url, $vars, $suffix, $domain);
  1557. }
  1558. /**
  1559. * 判断 cmf 核心是否安装
  1560. * @return bool
  1561. */
  1562. function cmf_is_installed()
  1563. {
  1564. static $cmfIsInstalled;
  1565. if (empty($cmfIsInstalled)) {
  1566. $cmfIsInstalled = file_exists(CMF_DATA . 'install.lock');
  1567. }
  1568. return $cmfIsInstalled;
  1569. }
  1570. /**
  1571. * 替换编辑器内容中的文件地址
  1572. * @param string $content 编辑器内容
  1573. * @param boolean $isForDbSave true:表示把绝对地址换成相对地址,用于数据库保存,false:表示把相对地址换成绝对地址用于界面显示
  1574. * @return string
  1575. */
  1576. function cmf_replace_content_file_url($content, $isForDbSave = false)
  1577. {
  1578. //import('phpQuery.phpQuery', EXTEND_PATH);
  1579. \phpQuery::newDocumentHTML($content);
  1580. $pq = pq(null);
  1581. $storage = Storage::instance();
  1582. $localStorage = new cmf\lib\storage\Local([]);
  1583. $storageDomain = $storage->getDomain();
  1584. $domain = request()->host();
  1585. $images = $pq->find("img");
  1586. if ($images->length) {
  1587. foreach ($images as $img) {
  1588. $img = pq($img);
  1589. $imgSrc = $img->attr("src");
  1590. if ($isForDbSave) {
  1591. if (preg_match("/^\/upload\//", $imgSrc)) {
  1592. $img->attr("src", preg_replace("/^\/upload\//", '', $imgSrc));
  1593. } elseif (preg_match("/^http(s)?:\/\/$domain\/upload\//", $imgSrc)) {
  1594. $img->attr("src", $localStorage->getFilePath($imgSrc));
  1595. } elseif (preg_match("/^http(s)?:\/\/$storageDomain\//", $imgSrc)) {
  1596. $img->attr("src", $storage->getFilePath($imgSrc));
  1597. }
  1598. } else {
  1599. $img->attr("src", cmf_get_image_url($imgSrc));
  1600. }
  1601. }
  1602. }
  1603. $links = $pq->find("a");
  1604. if ($links->length) {
  1605. foreach ($links as $link) {
  1606. $link = pq($link);
  1607. $href = $link->attr("href");
  1608. if ($isForDbSave) {
  1609. if (preg_match("/^\/upload\//", $href)) {
  1610. $link->attr("href", preg_replace("/^\/upload\//", '', $href));
  1611. } elseif (preg_match("/^http(s)?:\/\/$domain\/upload\//", $href)) {
  1612. $link->attr("href", $localStorage->getFilePath($href));
  1613. } elseif (preg_match("/^http(s)?:\/\/$storageDomain\//", $href)) {
  1614. $link->attr("href", $storage->getFilePath($href));
  1615. }
  1616. } else {
  1617. if (!(preg_match("/^\//", $href) || preg_match("/^http/", $href))) {
  1618. $link->attr("href", cmf_get_file_download_url($href));
  1619. }
  1620. }
  1621. }
  1622. }
  1623. $content = $pq->html();
  1624. \phpQuery::$documents = null;
  1625. return $content;
  1626. }
  1627. /**
  1628. * 获取后台风格名称
  1629. * @return string
  1630. */
  1631. function cmf_get_admin_style()
  1632. {
  1633. $adminSettings = cmf_get_option('admin_settings');
  1634. return empty($adminSettings['admin_style']) ? 'simpleadmin' : $adminSettings['admin_style'];
  1635. }
  1636. /**
  1637. * curl get 请求
  1638. * @param $url
  1639. * @return mixed
  1640. */
  1641. function cmf_curl_get($url)
  1642. {
  1643. $ch = curl_init();
  1644. curl_setopt($ch, CURLOPT_URL, $url);
  1645. curl_setopt($ch, CURLOPT_FAILONERROR, true);
  1646. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  1647. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  1648. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  1649. curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  1650. $SSL = substr($url, 0, 8) == "https://" ? true : false;
  1651. // if ($SSL) {
  1652. // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
  1653. // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
  1654. // }
  1655. $content = curl_exec($ch);
  1656. curl_close($ch);
  1657. return $content;
  1658. }
  1659. /**
  1660. * 用户操作记录
  1661. * @param string $action 用户操作
  1662. * @throws \think\Exception
  1663. * @throws \think\db\exception\DataNotFoundException
  1664. * @throws \think\db\exception\ModelNotFoundException
  1665. * @throws \think\exception\DbException
  1666. * @throws \think\exception\PDOException
  1667. */
  1668. function cmf_user_action($action)
  1669. {
  1670. $userId = cmf_get_current_user_id();
  1671. if (empty($userId)) {
  1672. return;
  1673. }
  1674. $findUserAction = Db::name('user_action')->where('action', $action)->find();
  1675. if (empty($findUserAction)) {
  1676. return;
  1677. }
  1678. $changeScore = false;
  1679. if ($findUserAction['cycle_type'] == 0) {
  1680. $changeScore = true;
  1681. } elseif ($findUserAction['reward_number'] > 0) {
  1682. $findUserScoreLog = Db::name('user_score_log')->order('create_time DESC')->find();
  1683. if (!empty($findUserScoreLog)) {
  1684. $cycleType = intval($findUserAction['cycle_type']);
  1685. $cycleTime = intval($findUserAction['cycle_time']);
  1686. switch ($cycleType) {//1:按天;2:按小时;3:永久
  1687. case 1:
  1688. $firstDayStartTime = strtotime(date('Y-m-d', $findUserScoreLog['create_time']));
  1689. $endDayEndTime = strtotime(date('Y-m-d', strtotime("+{$cycleTime} day", $firstDayStartTime)));
  1690. // $todayStartTime = strtotime(date('Y-m-d'));
  1691. // $todayEndTime = strtotime(date('Y-m-d', strtotime('+1 day')));
  1692. $findUserScoreLogCount = Db::name('user_score_log')->where([
  1693. 'user_id' => $userId,
  1694. 'create_time' => [['gt', $firstDayStartTime], ['lt', $endDayEndTime]]
  1695. ])->count();
  1696. if ($findUserScoreLogCount < $findUserAction['reward_number']) {
  1697. $changeScore = true;
  1698. }
  1699. break;
  1700. case 2:
  1701. if (($findUserScoreLog['create_time'] + $cycleTime * 3600) < time()) {
  1702. $changeScore = true;
  1703. }
  1704. break;
  1705. case 3:
  1706. break;
  1707. }
  1708. } else {
  1709. $changeScore = true;
  1710. }
  1711. }
  1712. if ($changeScore) {
  1713. Db::name('user_score_log')->insert([
  1714. 'user_id' => $userId,
  1715. 'create_time' => time(),
  1716. 'action' => $action,
  1717. 'score' => $findUserAction['score'],
  1718. 'coin' => $findUserAction['coin'],
  1719. ]);
  1720. $data = [];
  1721. if ($findUserAction['score'] > 0) {
  1722. $data['score'] = Db::raw('score+' . $findUserAction['score']);
  1723. }
  1724. if ($findUserAction['score'] < 0) {
  1725. $data['score'] = Db::raw('score-' . abs($findUserAction['score']));
  1726. }
  1727. if ($findUserAction['coin'] > 0) {
  1728. $data['coin'] = Db::raw('coin+' . $findUserAction['coin']);
  1729. }
  1730. if ($findUserAction['coin'] < 0) {
  1731. $data['coin'] = Db::raw('coin-' . abs($findUserAction['coin']));
  1732. }
  1733. Db::name('user')->where('id', $userId)->update($data);
  1734. }
  1735. }
  1736. function cmf_api_request($url, $params = [])
  1737. {
  1738. //初始化
  1739. $curl = curl_init();
  1740. //设置抓取的url
  1741. curl_setopt($curl, CURLOPT_URL, 'http://127.0.0.1:1314/api/' . $url);
  1742. //设置头文件的信息作为数据流输出
  1743. curl_setopt($curl, CURLOPT_HEADER, 0);
  1744. //设置获取的信息以文件流的形式返回,而不是直接输出。
  1745. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  1746. //设置post方式提交
  1747. curl_setopt($curl, CURLOPT_POST, 1);
  1748. $token = session('token');
  1749. curl_setopt($curl, CURLOPT_HTTPHEADER, ["XX-Token: $token"]);
  1750. //设置post数据
  1751. curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
  1752. //执行命令
  1753. $data = curl_exec($curl);
  1754. //关闭URL请求
  1755. curl_close($curl);
  1756. //显示获得的数据
  1757. return json_decode($data, true);
  1758. }
  1759. /**
  1760. * 判断是否允许开放注册
  1761. */
  1762. function cmf_is_open_registration()
  1763. {
  1764. $cmfSettings = cmf_get_option('cmf_settings');
  1765. return empty($cmfSettings['open_registration']) ? false : true;
  1766. }
  1767. /**
  1768. * XML编码
  1769. * @param mixed $data 数据
  1770. * @param string $root 根节点名
  1771. * @param string $item 数字索引的子节点名
  1772. * @param string $attr 根节点属性
  1773. * @param string $id 数字索引子节点key转换的属性名
  1774. * @param string $encoding 数据编码
  1775. * @return string
  1776. */
  1777. function cmf_xml_encode($data, $root = 'think', $item = 'item', $attr = '', $id = 'id', $encoding = 'utf-8')
  1778. {
  1779. if (is_array($attr)) {
  1780. $_attr = [];
  1781. foreach ($attr as $key => $value) {
  1782. $_attr[] = "{$key}=\"{$value}\"";
  1783. }
  1784. $attr = implode(' ', $_attr);
  1785. }
  1786. $attr = trim($attr);
  1787. $attr = empty($attr) ? '' : " {$attr}";
  1788. $xml = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";
  1789. $xml .= "<{$root}{$attr}>";
  1790. $xml .= cmf_data_to_xml($data, $item, $id);
  1791. $xml .= "</{$root}>";
  1792. return $xml;
  1793. }
  1794. /**
  1795. * 数据XML编码
  1796. * @param mixed $data 数据
  1797. * @param string $item 数字索引时的节点名称
  1798. * @param string $id 数字索引key转换为的属性名
  1799. * @return string
  1800. */
  1801. function cmf_data_to_xml($data, $item = 'item', $id = 'id')
  1802. {
  1803. $xml = $attr = '';
  1804. foreach ($data as $key => $val) {
  1805. if (is_numeric($key)) {
  1806. $id && $attr = " {$id}=\"{$key}\"";
  1807. $key = $item;
  1808. }
  1809. $xml .= "<{$key}{$attr}>";
  1810. $xml .= (is_array($val) || is_object($val)) ? cmf_data_to_xml($val, $item, $id) : $val;
  1811. $xml .= "</{$key}>";
  1812. }
  1813. return $xml;
  1814. }
  1815. /**
  1816. * 检查手机格式,中国手机不带国家代码,国际手机号格式为:国家代码-手机号
  1817. * @param $mobile
  1818. * @return bool
  1819. */
  1820. function cmf_check_mobile($mobile)
  1821. {
  1822. if (preg_match('/(^(13\d|14\d|15\d|16\d|17\d|18\d|19\d)\d{8})$/', $mobile)) {
  1823. return true;
  1824. } else {
  1825. if (preg_match('/^\d{1,4}-\d{5,11}$/', $mobile)) {
  1826. if (preg_match('/^\d{1,4}-0+/', $mobile)) {
  1827. //不能以0开头
  1828. return false;
  1829. }
  1830. return true;
  1831. }
  1832. return false;
  1833. }
  1834. }
  1835. /**
  1836. * 文件大小格式化
  1837. * @param $bytes 文件大小(字节 Byte)
  1838. * @return string
  1839. */
  1840. function cmf_file_size_format($bytes)
  1841. {
  1842. $type = ['B', 'KB', 'MB', 'GB', 'TB'];
  1843. for ($i = 0; $bytes >= 1024; $i++)//单位每增大1024,则单位数组向后移动一位表示相应的单位
  1844. {
  1845. $bytes /= 1024;
  1846. }
  1847. return (floor($bytes * 100) / 100) . $type[$i];//floor是取整函数,为了防止出现一串的小数,这里取了两位小数
  1848. }
  1849. /**
  1850. * 计数器增加
  1851. * @param $name 计数器英文标识
  1852. * @param int $min 计数器最小值
  1853. * @param int $step 增加步长
  1854. * @return mixed
  1855. */
  1856. function cmf_counter_inc($name, $min = 1, $step = 1)
  1857. {
  1858. $id = cache('core_counter_' . $name);
  1859. if (empty($id)) {
  1860. $id = Db::name('core_counter')->where('name', $name)->value('id');
  1861. if (empty($id)) {
  1862. $id = Db::name('core_counter')->insertGetId([
  1863. 'name' => $name,
  1864. 'value' => 0
  1865. ]);
  1866. }
  1867. cache('core_counter_' . $name, $id);
  1868. }
  1869. Db::startTrans();
  1870. try {
  1871. $value = Db::name('core_counter')->where('id', $id)->lock(true)->value('value');
  1872. if ($min > $value) {
  1873. $value = $min;
  1874. } else {
  1875. $value += $step;
  1876. }
  1877. Db::name('core_counter')->where('id', $id)->update(['value' => $value]);
  1878. Db::commit();
  1879. } catch (\Exception $e) {
  1880. Db::rollback();
  1881. $value = false;
  1882. }
  1883. return $value;
  1884. }
  1885. /**
  1886. * 获取ThinkPHP版本
  1887. * @return string
  1888. */
  1889. function cmf_thinkphp_version()
  1890. {
  1891. return \think\facade\App::version();
  1892. }
  1893. /**
  1894. * 获取ThinkCMF版本
  1895. * @return string
  1896. */
  1897. function cmf_version()
  1898. {
  1899. try {
  1900. $version = trim(file_get_contents(CMF_ROOT . 'version'));
  1901. } catch (\Exception $e) {
  1902. $version = '0.0.0';
  1903. }
  1904. return $version;
  1905. }
  1906. /**
  1907. * 获取ThinkCMF核心包目录
  1908. */
  1909. function cmf_core_path()
  1910. {
  1911. return __DIR__ . DIRECTORY_SEPARATOR;
  1912. }
  1913. /**
  1914. * 获取模块配置文件路径
  1915. * @param $app 应用
  1916. * @param $file 文件名不带后缀
  1917. */
  1918. function cmf_get_app_config_file($app, $file)
  1919. {
  1920. switch ($app) {
  1921. case 'cmf':
  1922. $configFile = cmf_core_path() . "{$file}.php";
  1923. break;
  1924. case 'swoole':
  1925. $configFile = Env::get('root_path') . "vendor/thinkcmf/cmf-swoole/src/{$file}.php";
  1926. break;
  1927. default:
  1928. $configFile = APP_PATH . $app . "/{$file}.php";
  1929. if (!file_exists($configFile)) {
  1930. $configFile = Env::get('root_path') . "vendor/thinkcmf/cmf-app/src/{$app}/{$file}.php";
  1931. }
  1932. }
  1933. return $configFile;
  1934. }
  1935. /**
  1936. * 转换+-为desc和asc
  1937. * @deprecated
  1938. * @param $order array 转换对象
  1939. * @return array
  1940. */
  1941. function order_shift($order)
  1942. {
  1943. $orderArr = [];
  1944. foreach ($order as $key => $value) {
  1945. $upDwn = substr($value, 0, 1);
  1946. $orderType = $upDwn == '-' ? 'desc' : 'asc';
  1947. $orderField = substr($value, 1);
  1948. if (!empty($whiteParams)) {
  1949. if (in_array($orderField, $whiteParams)) {
  1950. $orderArr[$orderField] = $orderType;
  1951. }
  1952. } else {
  1953. $orderArr[$orderField] = $orderType;
  1954. }
  1955. }
  1956. return $orderArr;
  1957. }
  1958. /**
  1959. * 模型检查
  1960. * @deprecated
  1961. * @param $relationFilter array 检查的字段
  1962. * @param $relations string 被检查的字段
  1963. * @return array|bool
  1964. */
  1965. function allowed_relations($relationFilter, $relations)
  1966. {
  1967. if (is_string($relations)) {
  1968. $relations = explode(',', $relations);
  1969. }
  1970. if (!is_array($relations)) {
  1971. return false;
  1972. }
  1973. return array_intersect($relationFilter, $relations);
  1974. }
  1975. /**
  1976. * 字符串转数组
  1977. * @deprecated
  1978. * @param string $string 字符串
  1979. * @return array
  1980. */
  1981. function str_to_arr($string)
  1982. {
  1983. $result = is_string($string) ? explode(',', $string) : $string;
  1984. return $result;
  1985. }
  1986. ///////////// 新增函数 /////////////
  1987. /**
  1988. * 返回JSON数据
  1989. * @param $params 状态码:success-成功,error-失败或返回所有参数数组如:['code'=>'success','messgae'=>'message','data'=>[]]
  1990. * @param string $message 错误消息
  1991. * @param array $data 返回数据
  1992. */
  1993. function showJson($params, $message='', $data=null, $end=''){
  1994. if($params && is_array($params)){
  1995. $message = isset($params['message'])? trim($params['message']) : 'message';
  1996. $data = isset($params['data'])? $params['data'] : null;
  1997. $code = isset($params['code'])? $params['code'] : 'error';
  1998. }else{
  1999. $code = $params;
  2000. }
  2001. $code = is_numeric($code)? lang($code) : $code;
  2002. $message = is_numeric($message)? lang($message) : $message;
  2003. $jsonData = [
  2004. 'code' => in_array($code, ['error', 'success','login','exception']) ? $code : 'error',
  2005. 'message' => $message ? $message : 'message',
  2006. ];
  2007. if ($data !== null) {
  2008. $jsonData['data'] = $data;
  2009. }
  2010. header("Content:application/json;chartset=uft-8");
  2011. echo json_encode($jsonData, 256).$end;
  2012. exit;
  2013. }
  2014. /**
  2015. * HTTP请求
  2016. * @param $url 链接
  2017. * @param $data 提交数据
  2018. * @param string $type 请求类型:get post
  2019. * @param string $dataType 返回数据类型 array json
  2020. * @param int $timeout
  2021. * @return mixed
  2022. */
  2023. function httpRequest($url, $data=[], $type='post', $dataType='array', $timeout=60){
  2024. $data = $data && is_array($data)? http_build_query($data) : $data;
  2025. $url = strtolower($type) == 'get'? $url.(strpos($url, '?') === false ? '?' : ''). $data : $url;
  2026. $ch = curl_init($url);
  2027. echo $url;
  2028. var_dump($data);
  2029. curl_setopt($ch, CURLOPT_POST, 1);
  2030. curl_setopt($ch, CURLOPT_HEADER,0 );
  2031. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  2032. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  2033. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  2034. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查,0-规避ssl的证书检查
  2035. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  2036. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  2037. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  2038. $ret = curl_exec($ch);
  2039. curl_close($ch);
  2040. echo $ret;
  2041. if(strtolower($dataType) == 'array' && !is_array($ret)){
  2042. $ret = json_decode($ret, true);
  2043. }
  2044. return $ret;
  2045. }
  2046. /**
  2047. * HTTP请求
  2048. * @param $url 链接
  2049. * @param $data 提交数据
  2050. * @param string $type 请求类型:get post
  2051. * @param string $dataType 返回数据类型 array json
  2052. * @param int $timeout
  2053. * @return mixed
  2054. */
  2055. function grabRequest($url, $header=[], $data=[], $type='get', $dataType='array', $cookieType='', $timeout=60){
  2056. $getData = $data && is_array($data)? http_build_query($data) : '';
  2057. $url = strtolower($type) == 'get'? $url.(strpos($url, '?') === false && $getData? '?' : ''). $getData : $url;
  2058. $ch = curl_init($url);
  2059. if($header){
  2060. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  2061. }else{
  2062. curl_setopt($ch, CURLOPT_HEADER, 0);
  2063. }
  2064. if (!empty($cookieType)) {
  2065. $cookie = file_get_contents('./logs/cookie_{$cookieType}.txt');
  2066. if($cookie){
  2067. curl_setopt($ch, CURLOPT_COOKIE, $cookie);
  2068. }
  2069. }
  2070. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  2071. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  2072. curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
  2073. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  2074. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查,0-规避ssl的证书检查
  2075. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  2076. if($type == 'post'){
  2077. curl_setopt($ch, CURLOPT_POST, 1);
  2078. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  2079. }
  2080. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  2081. $ret = curl_exec($ch);
  2082. curl_close($ch);
  2083. if(strtolower($dataType) == 'array' && !is_array($ret)){
  2084. $ret = json_decode($ret, true);
  2085. }
  2086. return $ret;
  2087. }
  2088. /**
  2089. * HTTP请求
  2090. * @param $url 链接
  2091. * @param $data 提交数据
  2092. * @param string $type 请求类型:get post
  2093. * @param string $dataType 返回数据类型 array json
  2094. * @param int $timeout
  2095. * @return mixed
  2096. */
  2097. function postRequest($url, $data=[], $header=[], $dataType='array', $cookieType='', $timeout=60){
  2098. $ch = curl_init($url);
  2099. if($header){
  2100. var_dump($header);
  2101. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  2102. }else{
  2103. curl_setopt($ch, CURLOPT_HEADER, 0);
  2104. }
  2105. if (!empty($cookieType)) {
  2106. $cookie = file_get_contents("./logs/cookie_{$cookieType}.txt");
  2107. if($cookie){
  2108. echo $cookie."\n";
  2109. curl_setopt($ch, CURLOPT_COOKIE, $cookie);
  2110. }
  2111. }
  2112. echo $data;
  2113. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  2114. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  2115. curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
  2116. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  2117. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'post');
  2118. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查,0-规避ssl的证书检查
  2119. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  2120. curl_setopt($ch, CURLOPT_POST, 1);
  2121. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  2122. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  2123. $ret = curl_exec($ch);
  2124. echo $ret;
  2125. curl_close($ch);
  2126. if(strtolower($dataType) == 'array' && !is_array($ret)){
  2127. $ret = json_decode($ret, true);
  2128. }
  2129. return $ret;
  2130. }
  2131. /**
  2132. *
  2133. * 接口请求
  2134. * @author wesmiler
  2135. * @param $url 接口地址
  2136. * @param $data
  2137. * @param $type
  2138. * @param int $timeout
  2139. * @return mixed
  2140. */
  2141. function requestCookies($url, $data='', $cookie='', $type='auth', $timeout=5)
  2142. {
  2143. $ch = curl_init($url);
  2144. if($cookie){
  2145. curl_setopt($ch, CURLOPT_COOKIE, $cookie);
  2146. }
  2147. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //禁止 cURL 验证对等证书
  2148. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //是否检测服务器的域名与证书上的是否一致
  2149. curl_setopt($ch, CURLOPT_HEADER, 1);
  2150. curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
  2151. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  2152. curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
  2153. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  2154. if($data){
  2155. curl_setopt($ch, CURLOPT_POST, 1);
  2156. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  2157. }
  2158. $ret = curl_exec($ch);
  2159. curl_close($ch);
  2160. $cookie = '';
  2161. $time = microtime(true);
  2162. // file_put_contents("./logs/page_".date('YmdHis').".html", $url."\n".$ret);
  2163. file_put_contents("./logs/cookies_ret_".date('YmdHis').'_'.$time.".txt", $url."\n".$ret);
  2164. $preg_cookie = '/(Set-Cookie|set-cookie): (.*?);/m';
  2165. if ($ret && preg_match_all($preg_cookie, $ret, $cookies)) {
  2166. if(isset($cookies[2])){
  2167. array_filter($cookies[2]);
  2168. $cookie = implode(';', $cookies[2]);
  2169. }
  2170. }
  2171. file_put_contents("./logs/cookies_".date('YmdHis').'_'.$time.".txt", $cookie);
  2172. return $cookie;
  2173. }
  2174. /**
  2175. * 解析COOKIE
  2176. * @param $cookies
  2177. * @return array
  2178. */
  2179. function getCookieArr($cookies){
  2180. $cookieArr = [];
  2181. $cookies = explode(';', $cookies);
  2182. foreach ($cookies as $cookie){
  2183. $data = explode('=', $cookie);
  2184. $key = isset($data[0])? trim($data[0]) : '';
  2185. $val = preg_replace("/^{$key}/",'', $cookie);
  2186. if($key){
  2187. $cookieArr[$key] = trim($val);
  2188. }
  2189. }
  2190. return $cookieArr;
  2191. }
  2192. /**
  2193. * 生成用户名
  2194. * @author wesmiler
  2195. * @date 2018年9月25日
  2196. * @param string $userCode ID,可为空
  2197. * @return string
  2198. */
  2199. function makeUserName($userCode='',$prefix='U'){
  2200. $charset = 'utf-8';
  2201. $codeLength = 8;
  2202. $length = 10;
  2203. $userCode = $userCode? $userCode : db('user')->max('id')+1;
  2204. $length = $length>10? $length : 10;
  2205. $userCodeLength = mb_strlen($userCode, $charset);
  2206. $prefixLength = mb_strlen($prefix, $charset);
  2207. if($userCodeLength>$codeLength){
  2208. $code = md5(date('is').uniqid($prefix).rand(10, 999).$userCode);
  2209. $code = $prefix.'00'.mb_substr($code, -8, 6, $charset);
  2210. }else{
  2211. $time = microtime(true);
  2212. $code = $prefix.str_repeat('0', $length-$userCodeLength-$prefixLength-1).($time%9).$userCode;
  2213. }
  2214. $code = strtoupper($code);
  2215. return $code;
  2216. }
  2217. /**
  2218. * @param $str
  2219. * @return string
  2220. */
  2221. function formatName($str){
  2222. return mb_substr($str, 0, 3, 'utf-8').'*****'.mb_substr($str, -3, 3, 'utf-8');
  2223. }
  2224. /**
  2225. * 解码
  2226. * @param $str
  2227. * @return string
  2228. */
  2229. function phpescape($str)
  2230. {
  2231. $sublen=strlen($str);
  2232. $retrunString="";
  2233. for ($i=0;$i<$sublen;$i++)
  2234. {
  2235. if(ord($str[$i])>=127)
  2236. {
  2237. $tmpString=bin2hex(iconv("gb2312","ucs-2",substr($str,$i,2)));
  2238. $retrunString.="%u".$tmpString;
  2239. $i++;
  2240. } else
  2241. {
  2242. $retrunString.="%".dechex(ord($str[$i]));
  2243. }
  2244. }
  2245. return $retrunString;
  2246. }
  2247. /**
  2248. * 解析前端JSON字符串
  2249. * @param $data
  2250. * @return bool|mixed
  2251. */
  2252. function jsonParse($data){
  2253. if(empty($data)){
  2254. return false;
  2255. }
  2256. $data = html_entity_decode($data);
  2257. return json_decode($data, true);
  2258. }
  2259. /**
  2260. * 生成UUID
  2261. * @return bool|mixed
  2262. */
  2263. function makeRandomUid(){
  2264. $v8js = new V8Js();
  2265. $jsStr = <<< ETO
  2266. function r() {
  2267. function t() {
  2268. return n ? 15 & n[e++] : 16 * Math.random() | 0
  2269. }
  2270. var n = null,
  2271. e = 0,
  2272. r = window.crypto || window.msCrypto;
  2273. r && r.getRandomValues && (n = r.getRandomValues(new Uint8Array(31)));
  2274. for (var o, i = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx", a = "", s = 0; s < i.length; s++) o = i[s], "x" === o ? a += t().toString(16) : "y" === o ? (o = 3 & t() | 8, a += o.toString(16)) : a += o;
  2275. return a
  2276. }
  2277. ETO;
  2278. try {
  2279. $uuid = $v8js->executeString($jsStr, 'uuid.js');
  2280. echo $uuid;
  2281. return $uuid;
  2282. } catch (\V8JsScriptException $e){
  2283. return false;
  2284. }
  2285. }