create-prisma-php-app 4.0.0-alpha.5 → 4.0.0-alpha.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/.htaccess +54 -41
  2. package/dist/bootstrap.php +142 -97
  3. package/dist/index.js +819 -343
  4. package/dist/settings/auto-swagger-docs.ts +196 -95
  5. package/dist/settings/bs-config.ts +53 -58
  6. package/dist/settings/files-list.json +1 -1
  7. package/dist/settings/project-name.ts +2 -0
  8. package/dist/settings/restart-mcp.ts +58 -0
  9. package/dist/settings/restart-websocket.ts +51 -45
  10. package/dist/settings/utils.ts +240 -0
  11. package/dist/src/Lib/AI/ChatGPTClient.php +147 -0
  12. package/dist/src/Lib/Auth/Auth.php +544 -0
  13. package/dist/src/Lib/Auth/AuthConfig.php +89 -0
  14. package/dist/src/Lib/CacheHandler.php +121 -0
  15. package/dist/src/Lib/ErrorHandler.php +322 -0
  16. package/dist/src/Lib/FileManager/UploadFile.php +383 -0
  17. package/dist/src/Lib/Headers/Boom.php +192 -0
  18. package/dist/src/Lib/IncludeTracker.php +59 -0
  19. package/dist/src/Lib/MCP/WeatherTools.php +104 -0
  20. package/dist/src/Lib/MCP/mcp-server.php +80 -0
  21. package/dist/src/Lib/MainLayout.php +230 -0
  22. package/dist/src/Lib/Middleware/AuthMiddleware.php +157 -0
  23. package/dist/src/Lib/Middleware/CorsMiddleware.php +145 -0
  24. package/dist/src/Lib/PHPMailer/Mailer.php +169 -0
  25. package/dist/src/Lib/PartialRenderer.php +40 -0
  26. package/dist/src/Lib/PrismaPHPSettings.php +181 -0
  27. package/dist/src/Lib/Request.php +479 -0
  28. package/dist/src/Lib/Security/RateLimiter.php +33 -0
  29. package/dist/src/Lib/Set.php +102 -0
  30. package/dist/src/Lib/StateManager.php +127 -0
  31. package/dist/src/Lib/Validator.php +752 -0
  32. package/dist/src/{Websocket → Lib/Websocket}/ConnectionManager.php +1 -1
  33. package/dist/src/Lib/Websocket/websocket-server.php +118 -0
  34. package/dist/src/app/error.php +1 -1
  35. package/dist/src/app/index.php +22 -5
  36. package/dist/src/app/js/index.js +1 -1
  37. package/dist/src/app/layout.php +2 -2
  38. package/package.json +1 -1
  39. package/dist/settings/restart-websocket.bat +0 -28
  40. package/dist/src/app/assets/images/prisma-php-black.svg +0 -6
  41. package/dist/websocket-server.php +0 -22
  42. package/vendor/autoload.php +0 -25
  43. package/vendor/composer/ClassLoader.php +0 -579
  44. package/vendor/composer/InstalledVersions.php +0 -359
  45. package/vendor/composer/LICENSE +0 -21
  46. package/vendor/composer/autoload_classmap.php +0 -10
  47. package/vendor/composer/autoload_namespaces.php +0 -9
  48. package/vendor/composer/autoload_psr4.php +0 -10
  49. package/vendor/composer/autoload_real.php +0 -38
  50. package/vendor/composer/autoload_static.php +0 -25
  51. package/vendor/composer/installed.json +0 -825
  52. package/vendor/composer/installed.php +0 -132
  53. package/vendor/composer/platform_check.php +0 -26
@@ -0,0 +1,479 @@
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace Lib;
6
+
7
+ use Lib\Headers\Boom;
8
+ use ArrayObject;
9
+ use stdClass;
10
+ use Lib\PrismaPHPSettings;
11
+
12
+ class Request
13
+ {
14
+ /**
15
+ * The base URL for the application.
16
+ *
17
+ * @var string
18
+ */
19
+ public const baseUrl = '/src/app';
20
+
21
+ /**
22
+ * @var stdClass $params A static property to hold request parameters.
23
+ *
24
+ * This property is used to hold request parameters that are passed to the request.
25
+ *
26
+ * Example usage:
27
+ * The parameters can be accessed using the following syntax:
28
+ * ```php
29
+ * $id = Request::$params['id'];
30
+ * OR
31
+ * $id = Request::$params->id;
32
+ * ```
33
+ */
34
+ public static ArrayObject $params;
35
+
36
+ /**
37
+ * @var stdClass $dynamicParams A static property to hold dynamic parameters.
38
+ *
39
+ * This property is used to hold dynamic parameters that are passed to the request.
40
+ *
41
+ * Example usage:
42
+ * Single parameter:
43
+ * ```php
44
+ * $id = Request::$dynamicParams['id'];
45
+ * OR
46
+ * $id = Request::$dynamicParams->id;
47
+ * ```
48
+ *
49
+ * Multiple parameters:
50
+ * ```php
51
+ * $dynamicParams = Request::$dynamicParams;
52
+ * echo '<pre>';
53
+ * print_r($dynamicParams);
54
+ * echo '</pre>';
55
+ * ```
56
+ *
57
+ * The above code will output the dynamic parameters as an array, which can be useful for debugging purposes.
58
+ */
59
+ public static ArrayObject $dynamicParams;
60
+
61
+ /**
62
+ * @var stdClass $localStorage A static property to hold request parameters.
63
+ *
64
+ * This property is used to hold request parameters that are passed to the request.
65
+ *
66
+ * Example usage:
67
+ * The parameters can be accessed using the following syntax:
68
+ * ```php
69
+ * $id = Request::$localStorage['id'];
70
+ * OR
71
+ * $id = Request::$localStorage->id;
72
+ * ```
73
+ */
74
+ public static ArrayObject $localStorage;
75
+
76
+ /**
77
+ * @var mixed $data Holds request data (e.g., JSON body).
78
+ */
79
+ public static mixed $data = null;
80
+
81
+ /**
82
+ * @var string $pathname Holds the request pathname.
83
+ */
84
+ public static string $pathname = '';
85
+
86
+ /**
87
+ * @var string $uri Holds the request URI.
88
+ */
89
+ public static string $uri = '';
90
+
91
+ /**
92
+ * @var string $decodedUri Holds the decoded request URI.
93
+ */
94
+ public static string $decodedUri = '';
95
+
96
+ /**
97
+ * @var string $referer Holds the referer of the request.
98
+ */
99
+ public static string $referer = '';
100
+
101
+ /**
102
+ * @var string $method Holds the request method.
103
+ */
104
+ public static string $method = '';
105
+
106
+ /**
107
+ * @var string $contentType Holds the content type of the request.
108
+ */
109
+ public static string $contentType = '';
110
+
111
+ /**
112
+ * @var string $protocol The protocol used for the request.
113
+ */
114
+ public static string $protocol = '';
115
+
116
+ /**
117
+ * @var string $domainName The domain name of the request.
118
+ */
119
+ public static string $domainName = '';
120
+
121
+ /**
122
+ * @var string $scriptName The script name of the request.
123
+ */
124
+ public static string $scriptName = '';
125
+
126
+ /**
127
+ * @var string $documentUrl The full document URL of the request.
128
+ */
129
+ public static string $documentUrl = '';
130
+
131
+ /**
132
+ * @var string $fileToInclude The file to include in the request.
133
+ */
134
+ public static string $fileToInclude = '';
135
+
136
+ /**
137
+ * @var bool $isGet Indicates if the request method is GET.
138
+ */
139
+ public static bool $isGet = false;
140
+
141
+ /**
142
+ * @var bool $isPost Indicates if the request method is POST.
143
+ */
144
+ public static bool $isPost = false;
145
+
146
+ /**
147
+ * @var bool $isPut Indicates if the request method is PUT.
148
+ */
149
+ public static bool $isPut = false;
150
+
151
+ /**
152
+ * @var bool $isDelete Indicates if the request method is DELETE.
153
+ */
154
+ public static bool $isDelete = false;
155
+
156
+ /**
157
+ * @var bool $isPatch Indicates if the request method is PATCH.
158
+ */
159
+ public static bool $isPatch = false;
160
+
161
+ /**
162
+ * @var bool $isHead Indicates if the request method is HEAD.
163
+ */
164
+ public static bool $isHead = false;
165
+
166
+ /**
167
+ * @var bool $isOptions Indicates if the request method is OPTIONS.
168
+ */
169
+ public static bool $isOptions = false;
170
+
171
+ /**
172
+ * @var bool $isAjax Indicates if the request is an AJAX request.
173
+ */
174
+ public static bool $isAjax = false;
175
+
176
+ /**
177
+ * Indicates whether the request is a wire request.
178
+ *
179
+ * @var bool
180
+ */
181
+ public static bool $isWire = false;
182
+
183
+ /**
184
+ * Indicates whether the request is an X-File request.
185
+ *
186
+ * @var bool
187
+ */
188
+ public static bool $isXFileRequest = false;
189
+
190
+ /**
191
+ * @var string $requestedWith Holds the value of the X-Requested-With header.
192
+ */
193
+ public static string $requestedWith = '';
194
+
195
+ /**
196
+ * @var string $remoteAddr Holds the remote address of the request.
197
+ */
198
+ public static string $remoteAddr = '';
199
+
200
+ public static function init(): void
201
+ {
202
+ self::$params = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
203
+ self::$dynamicParams = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
204
+
205
+ self::$referer = $_SERVER['HTTP_REFERER'] ?? 'Unknown';
206
+ self::$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
207
+ self::$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
208
+ self::$domainName = $_SERVER['HTTP_HOST'] ?? '';
209
+ self::$scriptName = dirname($_SERVER['SCRIPT_NAME']);
210
+ self::$requestedWith = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '';
211
+
212
+ self::$isGet = self::$method === 'GET';
213
+ self::$isPost = self::$method === 'POST';
214
+ self::$isPut = self::$method === 'PUT';
215
+ self::$isDelete = self::$method === 'DELETE';
216
+ self::$isPatch = self::$method === 'PATCH';
217
+ self::$isHead = self::$method === 'HEAD';
218
+ self::$isOptions = self::$method === 'OPTIONS';
219
+
220
+ self::$isWire = self::isWireRequest();
221
+ self::$isAjax = self::isAjaxRequest();
222
+ self::$isXFileRequest = self::isXFileRequest();
223
+ self::$params = self::getParams();
224
+ self::$localStorage = self::getLocalStorage();
225
+ self::$protocol = self::getProtocol();
226
+ self::$documentUrl = self::$protocol . self::$domainName . self::$scriptName;
227
+ self::$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? 'Unknown';
228
+ }
229
+
230
+ /**
231
+ * Determines if the current request is an AJAX request.
232
+ *
233
+ * @return bool True if the request is an AJAX request, false otherwise.
234
+ */
235
+ private static function isAjaxRequest(): bool
236
+ {
237
+ // Check for standard AJAX header
238
+ if (
239
+ !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
240
+ strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'
241
+ ) {
242
+ return true;
243
+ }
244
+
245
+ // Check for common AJAX content types
246
+ if (!empty($_SERVER['CONTENT_TYPE'])) {
247
+ $ajaxContentTypes = [
248
+ 'application/json',
249
+ 'application/x-www-form-urlencoded',
250
+ 'multipart/form-data',
251
+ ];
252
+
253
+ foreach ($ajaxContentTypes as $contentType) {
254
+ if (stripos($_SERVER['CONTENT_TYPE'], $contentType) !== false) {
255
+ return true;
256
+ }
257
+ }
258
+ }
259
+
260
+ // Check for common AJAX request methods
261
+ $ajaxMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
262
+ if (
263
+ !empty($_SERVER['REQUEST_METHOD']) &&
264
+ in_array(strtoupper($_SERVER['REQUEST_METHOD']), $ajaxMethods, true)
265
+ ) {
266
+ return true;
267
+ }
268
+
269
+ return false;
270
+ }
271
+
272
+ /**
273
+ * Checks if the request is a wire request.
274
+ */
275
+ private static function isWireRequest(): bool
276
+ {
277
+ $headers = array_change_key_case(getallheaders(), CASE_LOWER);
278
+ return isset($headers['http_pphp_wire_request']) && strtolower($headers['http_pphp_wire_request']) === 'true';
279
+ }
280
+
281
+ /**
282
+ * Checks if the request is an X-File request.
283
+ *
284
+ * @return bool True if the request is an X-File request, false otherwise.
285
+ */
286
+ private static function isXFileRequest(): bool
287
+ {
288
+ $serverFetchSite = $_SERVER['HTTP_SEC_FETCH_SITE'] ?? '';
289
+ if (isset($serverFetchSite) && $serverFetchSite === 'same-origin') {
290
+ $headers = array_change_key_case(getallheaders(), CASE_LOWER);
291
+ return isset($headers['http_pphp_x_file_request']) && $headers['http_pphp_x_file_request'] === 'true';
292
+ }
293
+
294
+ return false;
295
+ }
296
+
297
+ /**
298
+ * Get the request parameters.
299
+ *
300
+ * @return ArrayObject The request parameters as an ArrayObject with properties.
301
+ */
302
+ private static function getParams(): ArrayObject
303
+ {
304
+ $params = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
305
+
306
+ switch (self::$method) {
307
+ case 'GET':
308
+ $params = new ArrayObject($_GET, ArrayObject::ARRAY_AS_PROPS);
309
+ break;
310
+ default:
311
+ // Handle JSON input with different variations (e.g., application/json, application/ld+json, etc.)
312
+ if (preg_match('#^application/(|\S+\+)json($|[ ;])#', self::$contentType)) {
313
+ $jsonInput = file_get_contents('php://input');
314
+ if ($jsonInput !== false && !empty($jsonInput)) {
315
+ self::$data = json_decode($jsonInput, true);
316
+ if (json_last_error() === JSON_ERROR_NONE) {
317
+ $params = new ArrayObject(self::$data, ArrayObject::ARRAY_AS_PROPS);
318
+ } else {
319
+ Boom::badRequest('Invalid JSON body')->toResponse();
320
+ }
321
+ }
322
+ }
323
+
324
+ // Handle URL-encoded input
325
+ if (stripos(self::$contentType, 'application/x-www-form-urlencoded') !== false) {
326
+ $rawInput = file_get_contents('php://input');
327
+ if ($rawInput !== false && !empty($rawInput)) {
328
+ parse_str($rawInput, $parsedParams);
329
+ $params = new ArrayObject($parsedParams, ArrayObject::ARRAY_AS_PROPS);
330
+ } else {
331
+ $params = new ArrayObject($_POST, ArrayObject::ARRAY_AS_PROPS);
332
+ }
333
+ }
334
+ break;
335
+ }
336
+
337
+ return $params;
338
+ }
339
+
340
+ /**
341
+ * Retrieves the local storage data from the session or initializes it if not present.
342
+ *
343
+ * This method checks if the local storage data is available in the static data array or the session.
344
+ * If the data is found, it is decoded from JSON if necessary and returned as an ArrayObject.
345
+ * If the data is not found, an empty ArrayObject is returned.
346
+ *
347
+ * @return ArrayObject The local storage data as an ArrayObject.
348
+ */
349
+ private static function getLocalStorage(): ArrayObject
350
+ {
351
+ $sessionKey = PrismaPHPSettings::$localStoreKey;
352
+ $localStorage = new ArrayObject([], ArrayObject::ARRAY_AS_PROPS);
353
+
354
+ if (isset(self::$data[$sessionKey])) {
355
+ $data = self::$data[$sessionKey];
356
+
357
+ if (is_array($data)) {
358
+ $_SESSION[$sessionKey] = $data;
359
+ $localStorage = new ArrayObject($data, ArrayObject::ARRAY_AS_PROPS);
360
+ } else {
361
+ $decodedData = json_decode($data, true);
362
+
363
+ if (json_last_error() === JSON_ERROR_NONE) {
364
+ $_SESSION[$sessionKey] = $data;
365
+ $localStorage = new ArrayObject($decodedData, ArrayObject::ARRAY_AS_PROPS);
366
+ } else {
367
+ Boom::badRequest('Invalid JSON body')->toResponse();
368
+ }
369
+ }
370
+ } else {
371
+ if (isset($_SESSION[$sessionKey])) {
372
+ $sessionData = $_SESSION[$sessionKey];
373
+
374
+ if (is_array($sessionData)) {
375
+ $localStorage = new ArrayObject($sessionData, ArrayObject::ARRAY_AS_PROPS);
376
+ } else {
377
+ $decodedData = json_decode($sessionData, true);
378
+
379
+ if (json_last_error() === JSON_ERROR_NONE) {
380
+ $localStorage = new ArrayObject($decodedData, ArrayObject::ARRAY_AS_PROPS);
381
+ }
382
+ }
383
+ }
384
+ }
385
+
386
+ return $localStorage;
387
+ }
388
+
389
+ /**
390
+ * Get the protocol of the request.
391
+ */
392
+ private static function getProtocol(): string
393
+ {
394
+ return (
395
+ (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
396
+ (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') ||
397
+ ($_SERVER['SERVER_PORT'] == 443)
398
+ ) ? "https://" : "http://";
399
+ }
400
+
401
+ /**
402
+ * Get the Bearer token from the Authorization header.
403
+ */
404
+ public static function getBearerToken(): ?string
405
+ {
406
+ $headers = array_change_key_case(getallheaders(), CASE_LOWER);
407
+ $authHeader = $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? null;
408
+
409
+ if ($authHeader && preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
410
+ return $matches[1];
411
+ }
412
+
413
+ return null;
414
+ }
415
+
416
+ /**
417
+ * Handle preflight OPTIONS request.
418
+ */
419
+ public static function handlePreflight(): void
420
+ {
421
+ if (self::$method === 'OPTIONS') {
422
+ header('HTTP/1.1 200 OK');
423
+ exit;
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Check if the request method is allowed.
429
+ */
430
+ public static function checkAllowedMethods(): void
431
+ {
432
+ if (!in_array(self::$method, ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'])) {
433
+ Boom::methodNotAllowed()->toResponse();
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Redirects the client to a specified URL.
439
+ *
440
+ * This method handles both normal and AJAX/wire requests. For normal requests,
441
+ * it sends a standard HTTP redirection header. For AJAX/wire requests, it outputs
442
+ * a custom redirect message.
443
+ *
444
+ * @param string $url The URL to redirect to.
445
+ * @param bool $replace Whether to replace the current header. Default is true.
446
+ * @param int $responseCode The HTTP response code to use for the redirection. Default is 0.
447
+ *
448
+ * @return void
449
+ */
450
+ public static function redirect(string $url, bool $replace = true, int $responseCode = 0): void
451
+ {
452
+ if (ob_get_length()) {
453
+ ob_clean();
454
+ }
455
+
456
+ ob_start();
457
+
458
+ if (!self::$isWire && !self::$isAjax) {
459
+ header("Location: $url", $replace, $responseCode);
460
+ } else {
461
+ echo "redirect_7F834=$url";
462
+ ob_end_flush();
463
+ }
464
+
465
+ exit;
466
+ }
467
+
468
+ public static function getDecodedUrl(string $uri): string
469
+ {
470
+ $parsedUrl = parse_url($uri);
471
+
472
+ $queryString = isset($parsedUrl['query']) ? '?' . urldecode($parsedUrl['query']) : '';
473
+ $path = $parsedUrl['path'] ?? '';
474
+
475
+ $decodedUrl = urldecode($path . $queryString);
476
+
477
+ return $decodedUrl;
478
+ }
479
+ }
@@ -0,0 +1,33 @@
1
+ <?php
2
+ namespace Lib\Security;
3
+
4
+ use Lib\Headers\Boom;
5
+
6
+ final class RateLimiter
7
+ {
8
+ /**
9
+ * Lanza HTTP 429 si se supera el máximo de intentos en la ventana dada.
10
+ *
11
+ * @param string $key Identificador único (p. ej. IP o user‑id).
12
+ * @param int $maxAttempts Nº de peticiones permitidas.
13
+ * @param int $seconds Ventana de tiempo en segundos.
14
+ */
15
+ public static function check(string $key, int $maxAttempts = 60, int $seconds = 60): void
16
+ {
17
+ if (!function_exists('apcu_fetch')) {
18
+ // APCu no instalado: conviene registrar un “fallback” o lanzar excepción.
19
+ Boom::internal("APCu extension missing for rate‑limit.")->toResponse();
20
+ }
21
+
22
+ $apcuKey = "ratelimit:{$key}";
23
+ $current = apcu_fetch($apcuKey) ?: 0;
24
+
25
+ if ($current >= $maxAttempts) {
26
+ // HTTP 429 Too Many Requests
27
+ Boom::tooManyRequests('Rate limit exceeded, try again later.')->toResponse();
28
+ }
29
+
30
+ // Incrementa contador y refresca TTL
31
+ apcu_store($apcuKey, $current + 1, $seconds);
32
+ }
33
+ }
@@ -0,0 +1,102 @@
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace Lib;
6
+
7
+ /**
8
+ * @template T
9
+ */
10
+ final class Set
11
+ {
12
+ /**
13
+ * @var array<string|int, T>
14
+ */
15
+ private array $items = [];
16
+
17
+ /**
18
+ * Adds a value to the set.
19
+ *
20
+ * @param T $value The value to add.
21
+ * @return void
22
+ */
23
+ public function add($value): void
24
+ {
25
+ $key = $this->getKey($value);
26
+ if (!isset($this->items[$key])) {
27
+ $this->items[$key] = $value;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Checks whether the set contains a given value.
33
+ *
34
+ * @param T $value The value to check.
35
+ * @return bool True if the value exists in the set, false otherwise.
36
+ */
37
+ public function has($value): bool
38
+ {
39
+ return isset($this->items[$this->getKey($value)]);
40
+ }
41
+
42
+ /**
43
+ * Removes a value from the set.
44
+ *
45
+ * @param T $value The value to remove.
46
+ * @return void
47
+ */
48
+ public function delete($value): void
49
+ {
50
+ unset($this->items[$this->getKey($value)]);
51
+ }
52
+
53
+ /**
54
+ * Clears all values from the set.
55
+ *
56
+ * @return void
57
+ */
58
+ public function clear(): void
59
+ {
60
+ $this->items = [];
61
+ }
62
+
63
+ /**
64
+ * Retrieves all values from the set, preserving insertion order.
65
+ *
66
+ * @return T[]
67
+ */
68
+ public function values(): array
69
+ {
70
+ return array_values($this->items);
71
+ }
72
+
73
+ /**
74
+ * Returns the number of values in the set.
75
+ *
76
+ * @return int The size of the set.
77
+ */
78
+ public function size(): int
79
+ {
80
+ return count($this->items);
81
+ }
82
+
83
+ /**
84
+ * Generates a unique key for the given value.
85
+ *
86
+ * - For objects, it uses spl_object_id.
87
+ * - For arrays, it uses md5(serialize($value)) to create a unique string.
88
+ * - For other types (scalars), the value itself is used as the key.
89
+ *
90
+ * @param T $value The value for which to generate a key.
91
+ * @return string|int The unique key.
92
+ */
93
+ private function getKey($value): string|int
94
+ {
95
+ if (is_object($value)) {
96
+ return spl_object_id($value);
97
+ } elseif (is_array($value)) {
98
+ return md5(serialize($value));
99
+ }
100
+ return $value;
101
+ }
102
+ }