Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
95.24% |
20 / 21 |
CRAP | |
94.74% |
72 / 76 |
Common | |
0.00% |
0 / 1 |
|
95.24% |
20 / 21 |
46.31 | |
94.74% |
72 / 76 |
setupConfig | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
setRequest | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
route | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isRoute | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
config | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
setConfig | |
100.00% |
1 / 1 |
1 | |
100.00% |
6 / 6 |
|||
getConfigDefaults | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
user | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
actor | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
userNickname | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
userId | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
ensureLoggedIn | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
isLoggedIn | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isSystemPath | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
arrayDiffRecursive | |
100.00% |
1 / 1 |
6 | |
100.00% |
11 / 11 |
|||
arrayRemoveKeys | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
sizeStrToInt | |
100.00% |
1 / 1 |
12 | |
100.00% |
19 / 19 |
|||
getPreferredPhpUploadLimit | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
clamp | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isValidHttpUrl | |
100.00% |
1 / 1 |
4 | |
100.00% |
5 / 5 |
|||
flattenNoteArray | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
1 | <?php |
2 | |
3 | // {{{ License |
4 | |
5 | // This file is part of GNU social - https://www.gnu.org/software/social |
6 | // |
7 | // GNU social is free software: you can redistribute it and/or modify |
8 | // it under the terms of the GNU Affero General Public License as published by |
9 | // the Free Software Foundation, either version 3 of the License, or |
10 | // (at your option) any later version. |
11 | // |
12 | // GNU social is distributed in the hope that it will be useful, |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | // GNU Affero General Public License for more details. |
16 | // |
17 | // You should have received a copy of the GNU Affero General Public License |
18 | // along with GNU social. If not, see <http://www.gnu.org/licenses/>. |
19 | |
20 | // }}} |
21 | |
22 | /** |
23 | * Common utility functions |
24 | * |
25 | * @package GNUsocial |
26 | * @category Util |
27 | * |
28 | * @author Hugo Sales <hugo@hsal.es> |
29 | * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org |
30 | * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later |
31 | */ |
32 | |
33 | namespace App\Util; |
34 | |
35 | use App\Core\Router\Router; |
36 | use App\Core\Security; |
37 | use App\Entity\GSActor; |
38 | use App\Entity\LocalUser; |
39 | use App\Util\Exception\NoLoggedInUser; |
40 | use Functional as F; |
41 | use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface; |
42 | use Symfony\Component\HttpFoundation\Request; |
43 | use Symfony\Component\Routing\Exception\ResourceNotFoundException; |
44 | use Symfony\Component\Yaml; |
45 | |
46 | abstract class Common |
47 | { |
48 | private static array $defaults; |
49 | private static ?array $config = null; |
50 | public static function setupConfig(ContainerBagInterface $config) |
51 | { |
52 | self::$config = $config->get('gnusocial'); |
53 | self::$defaults = $config->get('gnusocial_defaults'); |
54 | } |
55 | |
56 | private static ?Request $request = null; |
57 | public static function setRequest(Request $req) |
58 | { |
59 | self::$request = $req; |
60 | } |
61 | |
62 | public static function route() |
63 | { |
64 | return self::$request->attributes->get('_route'); |
65 | } |
66 | |
67 | public static function isRoute(string | array $routes) |
68 | { |
69 | return in_array(self::route(), is_array($routes) ? $routes : [$routes]); |
70 | } |
71 | |
72 | /** |
73 | * Access sysadmin's configuration preferences for GNU social |
74 | */ |
75 | public static function config(string $section, ?string $setting = null) |
76 | { |
77 | if ($setting !== null) { |
78 | return self::$config[$section][$setting]; |
79 | } else { |
80 | return self::$config[$section] ?? []; |
81 | } |
82 | } |
83 | |
84 | /** |
85 | * Set sysadmin's configuration preferences for GNU social |
86 | * |
87 | * @param mixed $value |
88 | */ |
89 | public static function setConfig(string $section, string $setting, $value): void |
90 | { |
91 | self::$config[$section][$setting] = $value; |
92 | $diff = self::arrayDiffRecursive(self::$config, self::$defaults); |
93 | $yaml = (new Yaml\Dumper(indentation: 2))->dump(['parameters' => ['gnusocial' => $diff]], Yaml\Yaml::DUMP_OBJECT_AS_MAP); |
94 | rename(INSTALLDIR . '/social.local.yaml', INSTALLDIR . '/social.local.yaml.back'); |
95 | file_put_contents(INSTALLDIR . '/social.local.yaml', $yaml); |
96 | } |
97 | |
98 | public static function getConfigDefaults() |
99 | { |
100 | return self::$defaults; |
101 | } |
102 | |
103 | public static function user(): ?LocalUser |
104 | { |
105 | return Security::getUser(); |
106 | } |
107 | |
108 | public static function actor(): ?GSActor |
109 | { |
110 | return self::user()->getActor(); |
111 | } |
112 | |
113 | public static function userNickname(): ?string |
114 | { |
115 | return self::ensureLoggedIn()->getNickname(); |
116 | } |
117 | |
118 | public static function userId(): ?int |
119 | { |
120 | return self::ensureLoggedIn()->getId(); |
121 | } |
122 | |
123 | public static function ensureLoggedIn(): LocalUser |
124 | { |
125 | if (($user = self::user()) == null) { |
126 | throw new NoLoggedInUser(); |
127 | // TODO Maybe redirect to login page and back |
128 | } else { |
129 | return $user; |
130 | } |
131 | } |
132 | |
133 | /** |
134 | * checks if user is logged in |
135 | * |
136 | * @return bool true if user is logged; false if it isn't |
137 | */ |
138 | public static function isLoggedIn(): bool |
139 | { |
140 | return self::user() != null; |
141 | } |
142 | |
143 | /** |
144 | * Is the given string identical to a system path or route? |
145 | * This could probably be put in some other class, but at |
146 | * at the moment, only Nickname requires this functionality. |
147 | */ |
148 | public static function isSystemPath(string $str): bool |
149 | { |
150 | try { |
151 | Router::match('/' . $str); |
152 | return true; |
153 | } catch (ResourceNotFoundException $e) { |
154 | return false; |
155 | } |
156 | } |
157 | |
158 | /** |
159 | * A recursive `array_diff`, while PHP itself doesn't provide one |
160 | * |
161 | * @param mixed $array1 |
162 | * @param mixed $array2 |
163 | */ |
164 | public static function arrayDiffRecursive($array1, $array2): array |
165 | { |
166 | $diff = []; |
167 | foreach ($array1 as $key => $value) { |
168 | if (array_key_exists($key, $array2)) { |
169 | if (is_array($value)) { |
170 | $recursive_diff = static::arrayDiffRecursive($value, $array2[$key]); |
171 | if (count($recursive_diff)) { |
172 | $diff[$key] = $recursive_diff; |
173 | } |
174 | } else { |
175 | if ($value != $array2[$key]) { |
176 | $diff[$key] = $value; |
177 | } |
178 | } |
179 | } else { |
180 | $diff[$key] = $value; |
181 | } |
182 | } |
183 | return $diff; |
184 | } |
185 | |
186 | /** |
187 | * Remove keys from the _values_ of $keys from the array $from |
188 | */ |
189 | public static function arrayRemoveKeys(array $from, array $keys, bool $strict = false) |
190 | { |
191 | return F\filter($from, function ($_, $key) use ($keys, $strict) { return !in_array($key, $keys, $strict); }); |
192 | } |
193 | |
194 | /** |
195 | * An internal helper function that converts a $size from php.ini for |
196 | * file size limit from the 'human-readable' shorthand into a int. If |
197 | * $size is empty (the value is not set in php.ini), returns a default |
198 | * value (3M) |
199 | * |
200 | * @return int the php.ini upload limit in machine-readable format |
201 | */ |
202 | public static function sizeStrToInt(string $size): int |
203 | { |
204 | // `memory_limit` can be -1 and `post_max_size` can be 0 |
205 | // for unlimited. Consistency. |
206 | if (empty($size) || $size === '-1' || $size === '0') { |
207 | $size = '3M'; |
208 | } |
209 | |
210 | $suffix = substr($size, -1); |
211 | $size = (int) substr($size, 0, -1); |
212 | switch (strtoupper($suffix)) { |
213 | case 'P': |
214 | $size *= 1024; |
215 | // no break |
216 | case 'T': |
217 | $size *= 1024; |
218 | // no break |
219 | case 'G': |
220 | $size *= 1024; |
221 | // no break |
222 | case 'M': |
223 | $size *= 1024; |
224 | // no break |
225 | case 'K': |
226 | $size *= 1024; |
227 | break; |
228 | default: |
229 | if ($suffix >= '0' && $suffix <= '9') { |
230 | $size = (int) "{$size}{$suffix}"; |
231 | } |
232 | } |
233 | return $size; |
234 | } |
235 | |
236 | /** |
237 | * Uses `size_str_to_int()` to find the smallest value for uploads in php.ini |
238 | * |
239 | * @return int |
240 | */ |
241 | public static function getPreferredPhpUploadLimit(): int |
242 | { |
243 | return min( |
244 | self::sizeStrToInt(ini_get('post_max_size')), |
245 | self::sizeStrToInt(ini_get('upload_max_filesize')), |
246 | self::sizeStrToInt(ini_get('memory_limit')) |
247 | ); |
248 | } |
249 | |
250 | /** |
251 | * Clamps a value between 2 numbers |
252 | * |
253 | * @return float|int clamped value |
254 | */ |
255 | public static function clamp(int | float $value, int | float $min, int | float $max): int | float |
256 | { |
257 | return min(max($value, $min), $max); |
258 | } |
259 | |
260 | /** |
261 | * If $ensure_secure is true, only allow https URLs to pass |
262 | */ |
263 | public static function isValidHttpUrl(string $url, bool $ensure_secure = false) |
264 | { |
265 | if (empty($url)) { |
266 | return false; |
267 | } |
268 | |
269 | // (if false, we use '?' in 'https?' to say the 's' is optional) |
270 | $regex = $ensure_secure ? '/^https$/' : '/^https?$/'; |
271 | return filter_var($url, FILTER_VALIDATE_URL) |
272 | && preg_match($regex, parse_url($url, PHP_URL_SCHEME)); |
273 | } |
274 | |
275 | /** |
276 | * Flatten an array of ['note' => note, 'replies' => [notes]] to an array of notes |
277 | */ |
278 | public static function flattenNoteArray(array $a): array |
279 | { |
280 | $notes = []; |
281 | foreach ($a as $n) { |
282 | $notes[] = $n['note']; |
283 | if (isset($n['replies'])) { |
284 | $notes = array_merge($notes, static::flattenNoteArray($n['replies'])); |
285 | } |
286 | } |
287 | return $notes; |
288 | } |
289 | } |