Func.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. /**
  3. * This file is part of the ForkBB <https://github.com/forkbb>.
  4. *
  5. * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
  6. * @license The MIT License (MIT)
  7. */
  8. declare(strict_types=1);
  9. namespace ForkBB\Core;
  10. use ForkBB\Core\Container;
  11. use DateTime;
  12. use DateTimeZone;
  13. use function \ForkBB\__;
  14. class Func
  15. {
  16. /**
  17. * Список доступных стилей
  18. */
  19. protected ?array $styles = null;
  20. /**
  21. * Список доступных языков
  22. */
  23. protected ?array $langs = null;
  24. /**
  25. * Список имен доступных языков
  26. */
  27. protected ?array $nameLangs = null;
  28. public function __construct(protected Container $c)
  29. {
  30. }
  31. /**
  32. * Список доступных стилей
  33. */
  34. public function getStyles(): array
  35. {
  36. if (! \is_array($this->styles)) {
  37. $this->styles = $this->getFoldersWithFile($this->c->DIR_PUBLIC . '/style', 'style.css');
  38. }
  39. return $this->styles;
  40. }
  41. /**
  42. * Список доступных языков
  43. */
  44. public function getLangs(): array
  45. {
  46. if (! \is_array($this->langs)) {
  47. $this->langs = $this->getFoldersWithFile($this->c->DIR_LANG, 'common.po');
  48. }
  49. return $this->langs;
  50. }
  51. /**
  52. * Список имен доступных языков
  53. */
  54. public function getNameLangs(): array
  55. {
  56. if (! \is_array($this->nameLangs)) {
  57. $langs = $this->getLangs();
  58. foreach ($langs as &$value) {
  59. $value = include "{$this->c->DIR_LANG}/{$value}/name.php";
  60. }
  61. unset($value);
  62. $this->nameLangs = $langs;
  63. }
  64. return $this->nameLangs;
  65. }
  66. /**
  67. * Список папок в данной директории содержащих заданный файл
  68. */
  69. public function getFoldersWithFile(string $dir, string $file): array
  70. {
  71. $result = [];
  72. if (
  73. \is_dir($dir)
  74. && false !== ($dh = \opendir($dir))
  75. ) {
  76. while (false !== ($entry = \readdir($dh))) {
  77. if (
  78. isset($entry[0])
  79. && '.' !== $entry[0]
  80. && \is_dir("{$dir}/{$entry}")
  81. && \is_file("{$dir}/{$entry}/{$file}")
  82. ) {
  83. $result[$entry] = $entry;
  84. }
  85. }
  86. \closedir($dh);
  87. \asort($result, \SORT_NATURAL);
  88. }
  89. return $result;
  90. }
  91. /**
  92. * Пагинация
  93. */
  94. public function paginate(int $all, int $cur, string $marker, array $args = [], string $info = 'Page %1$s of %2$s'): array
  95. {
  96. $pages = [];
  97. if ($all < 2) {
  98. return $pages;
  99. }
  100. // нестандарная переменная для page
  101. if (isset($args['page'])) {
  102. if (\is_string($args['page'])) {
  103. $pn = $args['page'];
  104. unset($args[$pn]);
  105. } else {
  106. $pn = 'page';
  107. }
  108. unset($args['page']);
  109. } else {
  110. $pn = 'page';
  111. }
  112. if ($cur > 0) {
  113. $pages[] = [[$info, $cur, $all], 'info', null];
  114. $cur = \min(\max(1, $cur), $all);
  115. if ($cur > 1) {
  116. $i = $cur - 1;
  117. $pages[] = [
  118. $this->c->Router->link(
  119. $marker,
  120. [
  121. $pn => $i > 1 ? $i : null,
  122. ]
  123. + $args
  124. ),
  125. 'prev',
  126. null,
  127. ];
  128. }
  129. $tpl = [1 => 1];
  130. $start = $cur < 6 ? 2 : $cur - 2;
  131. $end = $all - $cur < 5 ? $all : $cur + 3;
  132. for ($i = $start; $i < $end; ++$i) {
  133. $tpl[$i] = $i;
  134. }
  135. $tpl[$all] = $all;
  136. } else {
  137. $tpl = [];
  138. if ($all > 999) {
  139. $d = 2;
  140. } elseif ($all > 99) {
  141. $d = 3;
  142. } else {
  143. $d = \min(4, $all - 2);
  144. }
  145. for ($i = $all - $d; $i <= $all; $i++) {
  146. $tpl[$i] = $i;
  147. }
  148. }
  149. $k = 1;
  150. foreach ($tpl as $i) {
  151. if ($i - $k > 1) {
  152. $pages[] = [null, 'space', null];
  153. }
  154. $pages[] = [
  155. $this->c->Router->link(
  156. $marker,
  157. [
  158. $pn => $i > 1 ? $i : null,
  159. ]
  160. + $args
  161. ),
  162. $i,
  163. $i === $cur ? true : null,
  164. ];
  165. $k = $i;
  166. }
  167. if (
  168. $cur > 0
  169. && $cur < $all
  170. ) {
  171. $pages[] = [
  172. $this->c->Router->link(
  173. $marker,
  174. [
  175. $pn => $cur + 1,
  176. ]
  177. + $args
  178. ),
  179. 'next',
  180. null,
  181. ];
  182. }
  183. return $pages;
  184. }
  185. /**
  186. * Разбор HTTP_ACCEPT_LANGUAGE
  187. */
  188. public function langParse(string $str): array
  189. {
  190. $result = [];
  191. foreach (\explode(',', $str) as $step) {
  192. $dsr = \explode(';', $step, 2);
  193. if (isset($dsr[1])) {
  194. $q = \trim(\ltrim(\ltrim($dsr[1], 'q '), '='));
  195. if (
  196. ! \is_numeric($q)
  197. || $q < 0
  198. || $q > 1
  199. ) {
  200. continue;
  201. }
  202. $q = (float) $q;
  203. } else {
  204. $q = 1;
  205. }
  206. $l = \trim($dsr[0]);
  207. if (\preg_match('%^[[:alpha:]]{1,8}(?:-[[:alnum:]]{1,8})?$%', $l)) {
  208. $result[$l] = $q;
  209. }
  210. }
  211. \arsort($result, \SORT_NUMERIC);
  212. return \array_keys($result);
  213. }
  214. /**
  215. * Возвращает смещение в секундах для часовой зоны текущего пользователя или 0
  216. */
  217. public function offset(): int
  218. {
  219. if (\in_array($this->c->user->timezone, DateTimeZone::listIdentifiers(), true)) {
  220. $dateTimeZone = new DateTimeZone($this->c->user->timezone);
  221. $dateTime = new DateTime('now', $dateTimeZone);
  222. return $dateTime->getOffset();
  223. } else {
  224. return 0;
  225. }
  226. }
  227. }