1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace ICanBoogie;
13
14 const TOKEN_NUMERIC = "23456789";
15 const TOKEN_ALPHA = "abcdefghjkmnpqrstuvwxyz";
16 const TOKEN_ALPHA_UPCASE = "ABCDEFGHJKLMNPQRTUVWXYZ";
17 const TOKEN_SYMBOL = "!$=@#";
18 const TOKEN_SYMBOL_WIDE = '%&()*+,-./:;<>?@[]^_`{|}~';
19
20 define('ICanBoogie\TOKEN_NARROW', TOKEN_NUMERIC . TOKEN_ALPHA . TOKEN_SYMBOL);
21 define('ICanBoogie\TOKEN_MEDIUM', TOKEN_NUMERIC . TOKEN_ALPHA . TOKEN_SYMBOL . TOKEN_ALPHA_UPCASE);
22 define('ICanBoogie\TOKEN_WIDE', TOKEN_NUMERIC . TOKEN_ALPHA . TOKEN_SYMBOL . TOKEN_ALPHA_UPCASE . TOKEN_SYMBOL_WIDE);
23
24 25 26 27 28 29 30 31 32 33
34 function generate_token($length=8, $possible=TOKEN_NARROW)
35 {
36 return Helpers::generate_token($length, $possible);
37 }
38
39 40 41 42 43 44 45 46
47 function generate_token_wide()
48 {
49 return Helpers::generate_token(64, TOKEN_WIDE);
50 }
51
52 53 54 55 56 57 58 59 60 61 62 63
64 function pbkdf2($p, $s, $c=1000, $kl=32, $a='sha256')
65 {
66 return Helpers::pbkdf2($p, $s, $c=1000, $kl=32, $a='sha256');
67 }
68
69 70 71 72 73 74
75 class Helpers
76 {
77 static private $jumptable = [
78
79 'generate_token' => [ __CLASS__, 'generate_token' ],
80 'pbkdf2' => [ __CLASS__, 'pbkdf2' ]
81
82 ];
83
84 85 86 87 88 89 90 91
92 static public function __callstatic($name, array $arguments)
93 {
94 return call_user_func_array(self::$jumptable[$name], $arguments);
95 }
96
97 98 99 100 101 102 103 104
105 static public function patch($name, $callback)
106 {
107 if (empty(self::$jumptable[$name]))
108 {
109 throw new \RuntimeException("Undefined patchable: $name.");
110 }
111
112 self::$jumptable[$name] = $callback;
113 }
114
115 116 117
118
119 static private function generate_token($length=8, $possible=TOKEN_NARROW)
120 {
121 $token = '';
122 $y = strlen($possible) - 1;
123
124 while ($length--)
125 {
126 $i = mt_rand(0, $y);
127 $token .= $possible[$i];
128 }
129
130 return $token;
131 }
132
133 static private function pbkdf2($p, $s, $c=1000, $kl=32, $a='sha256')
134 {
135 $hl = strlen(hash($a, null, true));
136 $kb = ceil($kl / $hl);
137 $dk = '';
138
139
140 for ($block = 1 ; $block <= $kb ; $block++)
141 {
142
143 $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
144
145 for ( $i = 1; $i < $c; $i ++ )
146
147 $ib ^= ($b = hash_hmac($a, $b, $p, true));
148 $dk .= $ib;
149 }
150
151
152 return substr($dk, 0, $kl);
153 }
154 }
155
156 157 158 159 160 161 162
163 function normalize_namespace_part($part)
164 {
165 return preg_replace_callback
166 (
167 '/[-\s_\.]\D/', function ($match)
168 {
169 $rc = ucfirst($match[0]{1});
170
171 if ($match[0]{0} == '.')
172 {
173 $rc = '\\' . $rc;
174 }
175
176 return $rc;
177 },
178
179 ' ' . $part
180 );
181 }
182
183 184 185 186 187 188 189 190 191 192
193 function excerpt($str, $limit=55)
194 {
195 static $allowed_tags = [
196
197 'a', 'p', 'code', 'del', 'em', 'ins', 'strong'
198
199 ];
200
201 $str = strip_tags(trim($str), '<' . implode('><', $allowed_tags) . '>');
202 $str = preg_replace('#(<p>|<p\s+[^\>]+>)\s*</p>#', '', $str);
203
204 $parts = preg_split('#<([^\s>]+)([^>]*)>#m', $str, 0, PREG_SPLIT_DELIM_CAPTURE);
205
206
207
208
209
210 $rc = '';
211 $opened = [];
212
213 foreach ($parts as $i => $part)
214 {
215 if ($i % 3 == 0)
216 {
217 $words = preg_split('#(\s+)#', $part, 0, PREG_SPLIT_DELIM_CAPTURE);
218
219 foreach ($words as $w => $word)
220 {
221 if ($w % 2 == 0)
222 {
223 if (!$word)
224 {
225 continue;
226 }
227
228 $rc .= $word;
229
230 if (!--$limit)
231 {
232 break;
233 }
234 }
235 else
236 {
237 $rc .= $word;
238 }
239 }
240
241 if (!$limit)
242 {
243 break;
244 }
245 }
246 else if ($i % 3 == 1)
247 {
248 if ($part[0] == '/')
249 {
250 $rc .= '<' . $part . '>';
251
252 array_shift($opened);
253 }
254 else
255 {
256 array_unshift($opened, $part);
257
258 $rc .= '<' . $part . $parts[$i + 1] . '>';
259 }
260 }
261 }
262
263 if (!$limit)
264 {
265 $rc .= ' <span class="excerpt-warp">[…]</span>';
266 }
267
268 if ($opened)
269 {
270 $rc .= '</' . implode('></', $opened) . '>';
271 }
272
273 return $rc;
274 }
275
276 277 278 279 280 281 282 283 284 285
286 function strip_root($pathname)
287 {
288 $root = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR);
289 $root = strtr($root, DIRECTORY_SEPARATOR == '/' ? '\\' : '/', DIRECTORY_SEPARATOR);
290 $pathname = strtr($pathname, DIRECTORY_SEPARATOR == '/' ? '\\' : '/', DIRECTORY_SEPARATOR);
291
292 if ($root && strpos($pathname, $root) === 0)
293 {
294 $pathname = substr($pathname, strlen($root));
295 }
296
297 if (DIRECTORY_SEPARATOR != '/')
298 {
299 $pathname = strtr($pathname, DIRECTORY_SEPARATOR, '/');
300 }
301
302 return $pathname;
303 }
304
305 306 307 308 309 310 311 312 313
314 function log($message, array $params=[], $message_id=null, $type='debug')
315 {
316 Debug::log($type, $message, $params, $message_id);
317 }
318
319 320 321 322 323 324 325
326 function log_success($message, array $params=[], $message_id=null)
327 {
328 Debug::log('success', $message, $params, $message_id);
329 }
330
331 332 333 334 335 336 337
338 function log_error($message, array $params=[], $message_id=null)
339 {
340 Debug::log('error', $message, $params, $message_id);
341 }
342
343 344 345 346 347 348 349
350 function log_info($message, array $params=[], $message_id=null)
351 {
352 Debug::log('info', $message, $params, $message_id);
353 }
354
355 356 357 358 359 360
361 function log_time($message, array $params=[])
362 {
363 static $last;
364
365 $now = microtime(true);
366
367 $add = '<var>[';
368
369 $add .= '∑' . number_format($now - $_SERVER['REQUEST_TIME_FLOAT'], 3, '\'', '') . '"';
370
371 if ($last)
372 {
373 $add .= ', +' . number_format($now - $last, 3, '\'', '') . '"';
374 }
375
376 $add .= ']</var>';
377
378 $last = $now;
379
380 $message = $add . ' ' . $message;
381
382 log($message, $params);
383 }
384