create-prisma-php-app 1.22.0 → 1.22.500

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.
@@ -25,8 +25,17 @@ function determineContentToInclude()
25
25
  $baseDir = APP_PATH;
26
26
  $includePath = '';
27
27
  $layoutsToInclude = [];
28
- writeRoutes();
28
+
29
+ /**
30
+ * ============ Middleware Management ============
31
+ * AuthMiddleware is invoked to handle authentication logic for the current route ($uri).
32
+ * ================================================
33
+ */
29
34
  AuthMiddleware::handle($uri);
35
+ /**
36
+ * ============ End of Middleware Management ======
37
+ * ================================================
38
+ */
30
39
 
31
40
  $isDirectAccessToPrivateRoute = preg_match('/\/_/', $uri);
32
41
  if ($isDirectAccessToPrivateRoute) {
@@ -107,31 +116,23 @@ function getFilePrecedence()
107
116
  global $_filesListRoutes;
108
117
 
109
118
  // Normalize the file paths for consistent comparison
110
- $_filesListRoutes = array_map(function ($route) {
111
- return str_replace('\\', '/', $route);
112
- }, $_filesListRoutes);
113
-
114
- // Look for route.php in the /src/app/ directory
115
- $routeFile = array_filter($_filesListRoutes, function ($route) {
116
- return preg_match('/^\.\/src\/app\/route\.php$/', $route);
117
- });
118
-
119
- // If route.php is found, return just the file name
120
- if (!empty($routeFile)) {
121
- return '/route.php';
119
+ foreach ($_filesListRoutes as $route) {
120
+ $normalizedRoute = str_replace('\\', '/', $route);
121
+ // First, check for route.php
122
+ if (preg_match('/^\.\/src\/app\/route\.php$/', $normalizedRoute)) {
123
+ return '/route.php';
124
+ }
122
125
  }
123
126
 
124
- // If route.php is not found, look for index.php in the /src/app/ directory
125
- $indexFile = array_filter($_filesListRoutes, function ($route) {
126
- return preg_match('/^\.\/src\/app\/index\.php$/', $route);
127
- });
128
-
129
- // If index.php is found, return just the file name
130
- if (!empty($indexFile)) {
131
- return '/index.php';
127
+ // If no route.php is found, check for index.php
128
+ foreach ($_filesListRoutes as $route) {
129
+ $normalizedRoute = str_replace('\\', '/', $route);
130
+ if (preg_match('/^\.\/src\/app\/index\.php$/', $normalizedRoute)) {
131
+ return '/index.php';
132
+ }
132
133
  }
133
134
 
134
- // If neither file is found, return null or handle the case as needed
135
+ // If neither file is found, return null
135
136
  return null;
136
137
  }
137
138
 
@@ -145,42 +146,19 @@ function uriExtractor(string $scriptUrl): string
145
146
  }
146
147
 
147
148
  $escapedIdentifier = preg_quote($projectName, '/');
148
- $pattern = "/(?:.*$escapedIdentifier)(\/.*)$/";
149
- if (preg_match($pattern, $scriptUrl, $matches)) {
150
- if (!empty($matches[1])) {
151
- $leftTrim = ltrim($matches[1], '/');
152
- $rightTrim = rtrim($leftTrim, '/');
153
- return "$rightTrim";
154
- }
149
+ if (preg_match("/(?:.*$escapedIdentifier)(\/.*)$/", $scriptUrl, $matches) && !empty($matches[1])) {
150
+ return rtrim(ltrim($matches[1], '/'), '/');
155
151
  }
156
152
 
157
153
  return "/";
158
154
  }
159
155
 
160
- function writeRoutes()
156
+ function getFilesListRoutes()
161
157
  {
162
- global $_filesListRoutes;
163
- $directory = './src/app';
164
-
165
- if (is_dir($directory)) {
166
- $filesList = [];
167
-
168
- $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
169
-
170
- foreach ($iterator as $file) {
171
- if ($file->isFile()) {
172
- $filesList[] = $file->getPathname();
173
- }
174
- }
175
-
176
- $jsonData = json_encode($filesList, JSON_PRETTY_PRINT);
177
- $jsonFileName = SETTINGS_PATH . '/files-list.json';
178
- file_put_contents($jsonFileName, $jsonData);
158
+ $jsonFileName = SETTINGS_PATH . '/files-list.json';
159
+ $routeFiles = file_exists($jsonFileName) ? json_decode(file_get_contents($jsonFileName), true) : [];
179
160
 
180
- if (file_exists($jsonFileName)) {
181
- $_filesListRoutes = json_decode(file_get_contents($jsonFileName), true);
182
- }
183
- }
161
+ return $routeFiles;
184
162
  }
185
163
 
186
164
  function findGroupFolder($uri): string
@@ -213,14 +191,21 @@ function dynamicRoute($uri)
213
191
  foreach ($_filesListRoutes as $route) {
214
192
  $normalizedRoute = trim(str_replace('\\', '/', $route), '.');
215
193
  $routeSegments = explode('/', ltrim($normalizedRoute, '/'));
194
+
195
+ $filteredRouteSegments = array_values(array_filter($routeSegments, function ($segment) {
196
+ return !preg_match('/\(.+\)/', $segment); // Skip segments with parentheses (groups)
197
+ }));
198
+
216
199
  $singleDynamic = preg_match_all('/\[[^\]]+\]/', $normalizedRoute, $matches) === 1 && !strpos($normalizedRoute, '[...');
217
200
  if ($singleDynamic) {
218
- $segmentMatch = singleDynamicRoute($uriSegments, $routeSegments);
219
- if (!empty($segmentMatch)) {
201
+ $segmentMatch = singleDynamicRoute($uriSegments, $filteredRouteSegments);
202
+ $index = array_search($segmentMatch, $filteredRouteSegments);
203
+ if ($index !== false && isset($uriSegments[$index])) {
220
204
  $trimSegmentMatch = trim($segmentMatch, '[]');
221
- $dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[array_search($segmentMatch, $routeSegments)]], \ArrayObject::ARRAY_AS_PROPS);
222
-
223
- $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[array_search($segmentMatch, $routeSegments)], $normalizedRoute);
205
+ $dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[$index]], \ArrayObject::ARRAY_AS_PROPS);
206
+ $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[$index], $normalizedRoute);
207
+ $dynamicRouteUri = preg_replace('/\(.+\)/', '', $dynamicRouteUri);
208
+ $dynamicRouteUri = preg_replace('/\/+/', '/', $dynamicRouteUri);
224
209
  $dynamicRouteUriDirname = dirname($dynamicRouteUri);
225
210
  $dynamicRouteUriDirname = rtrim($dynamicRouteUriDirname, '/');
226
211
 
@@ -235,30 +220,41 @@ function dynamicRoute($uri)
235
220
  }
236
221
  }
237
222
  } elseif (strpos($normalizedRoute, '[...') !== false) {
238
- $cleanedRoute = preg_replace('/\[\.\.\..*?\].*/', '', $normalizedRoute);
239
- if (strpos('/src/app/' . $normalizedUri, $cleanedRoute) === 0) {
240
-
241
- $normalizedUriEdited = "/src/app/$normalizedUri";
242
- $trimNormalizedUriEdited = str_replace($cleanedRoute, '', $normalizedUriEdited);
243
- $explodedNormalizedUri = explode('/', $trimNormalizedUriEdited);
244
- $pattern = '/\[\.\.\.(.*?)\]/';
245
- if (preg_match($pattern, $normalizedRoute, $matches)) {
246
- $contentWithinBrackets = $matches[1];
247
- $dynamicRouteParams = new \ArrayObject([$contentWithinBrackets => $explodedNormalizedUri], \ArrayObject::ARRAY_AS_PROPS);
223
+ // Clean and normalize the route
224
+ $cleanedNormalizedRoute = preg_replace('/\(.+\)/', '', $normalizedRoute); // Remove any public/private segment
225
+ $cleanedNormalizedRoute = preg_replace('/\/+/', '/', $cleanedNormalizedRoute); // Replace multiple slashes
226
+ $dynamicSegmentRoute = preg_replace('/\[\.\.\..*?\].*/', '', $cleanedNormalizedRoute); // Remove the dynamic segment
227
+
228
+ // Check if the normalized URI starts with the cleaned route
229
+ if (strpos("/src/app/$normalizedUri", $dynamicSegmentRoute) === 0) {
230
+ $trimmedUri = str_replace($dynamicSegmentRoute, '', "/src/app/$normalizedUri");
231
+ $uriParts = explode('/', trim($trimmedUri, '/'));
232
+
233
+ // Extract the dynamic segment content
234
+ if (preg_match('/\[\.\.\.(.*?)\]/', $normalizedRoute, $matches)) {
235
+ $dynamicParam = $matches[1];
236
+ $dynamicRouteParams = new \ArrayObject([$dynamicParam => $uriParts], \ArrayObject::ARRAY_AS_PROPS);
248
237
  }
238
+
239
+ // Check for 'route.php'
249
240
  if (strpos($normalizedRoute, 'route.php') !== false) {
250
241
  $uriMatch = $normalizedRoute;
251
242
  break;
252
- } else {
253
- if (strpos($normalizedRoute, 'index.php') !== false) {
254
- $segmentMatch = "[...$contentWithinBrackets]";
255
- $dynamicRouteUri = str_replace($segmentMatch, $uriSegments[array_search($segmentMatch, $routeSegments)], $normalizedRoute);
256
- $dynamicRouteUriDirname = dirname($dynamicRouteUri);
257
- $dynamicRouteUriDirname = rtrim($dynamicRouteUriDirname, '/');
243
+ }
244
+
245
+ // Handle matching routes ending with 'index.php'
246
+ if (strpos($normalizedRoute, 'index.php') !== false) {
247
+ $segmentMatch = "[...$dynamicParam]";
248
+ $index = array_search($segmentMatch, $filteredRouteSegments);
249
+
250
+ if ($index !== false && isset($uriSegments[$index])) {
251
+ // Generate the dynamic URI
252
+ $dynamicRouteUri = str_replace($segmentMatch, implode('/', $uriParts), $cleanedNormalizedRoute);
253
+ $dynamicRouteUriDirname = rtrim(dirname($dynamicRouteUri), '/');
258
254
 
259
- $expectedUri = '/src/app/' . $normalizedUri;
260
- $expectedUri = rtrim($expectedUri, '/');
255
+ $expectedUri = rtrim("/src/app/$normalizedUri", '/');
261
256
 
257
+ // Compare the expected and dynamic URIs
262
258
  if ($expectedUri === $dynamicRouteUriDirname) {
263
259
  $uriMatch = $normalizedRoute;
264
260
  break;
@@ -280,6 +276,7 @@ function isGroupIdentifier($segment): bool
280
276
  function matchGroupFolder($constructedPath): ?string
281
277
  {
282
278
  global $_filesListRoutes;
279
+
283
280
  $bestMatch = null;
284
281
  $normalizedConstructedPath = ltrim(str_replace('\\', '/', $constructedPath), './');
285
282
 
@@ -330,6 +327,10 @@ function singleDynamicRoute($uriSegments, $routeSegments)
330
327
 
331
328
  function checkForDuplicateRoutes()
332
329
  {
330
+ if ($_ENV['APP_ENV'] !== 'development') {
331
+ return;
332
+ }
333
+
333
334
  global $_filesListRoutes;
334
335
  $normalizedRoutesMap = [];
335
336
  foreach ($_filesListRoutes as $route) {
@@ -363,72 +364,27 @@ function checkForDuplicateRoutes()
363
364
  }
364
365
  }
365
366
 
366
- function setupErrorHandling(&$content)
367
- {
368
- set_error_handler(function ($severity, $message, $file, $line) use (&$content) {
369
- $content .= "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
370
- });
371
-
372
- set_exception_handler(function ($exception) use (&$content) {
373
- $content .= "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
374
- });
375
-
376
- register_shutdown_function(function () use (&$content) {
377
- $error = error_get_last();
378
- if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
379
- $formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
380
- " in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
381
- " on line " . $error['line'] . "</div>";
382
- $content .= $formattedError;
383
- modifyOutputLayoutForError($content);
384
- }
385
- });
386
- }
387
-
388
367
 
389
368
  function containsChildContent($filePath)
390
369
  {
391
370
  $fileContent = file_get_contents($filePath);
392
- if (
393
- (strpos($fileContent, 'echo $childContent') === false &&
394
- strpos($fileContent, 'echo $childContent;') === false) &&
395
- (strpos($fileContent, '<?= $childContent ?>') === false) &&
396
- (strpos($fileContent, '<?= $childContent; ?>') === false)
397
- ) {
398
- return true;
399
- } else {
400
- return false;
401
- }
371
+
372
+ // Regular expression to match different ways of echoing $childContent
373
+ $pattern = '/\<\?=\s*\$childContent\s*;?\s*\?>|echo\s*\$childContent\s*;?/';
374
+
375
+ // Return true if $childContent variables are found, false otherwise
376
+ return preg_match($pattern, $fileContent) === 1;
402
377
  }
403
378
 
404
379
  function containsContent($filePath)
405
380
  {
406
381
  $fileContent = file_get_contents($filePath);
407
- if (
408
- (strpos($fileContent, 'echo $content') === false &&
409
- strpos($fileContent, 'echo $content;') === false) &&
410
- (strpos($fileContent, '<?= $content ?>') === false) &&
411
- (strpos($fileContent, '<?= $content; ?>') === false)
412
- ) {
413
- return true;
414
- } else {
415
- return false;
416
- }
417
- }
418
-
419
- function modifyOutputLayoutForError($contentToAdd)
420
- {
421
- if ($_ENV['SHOW_ERRORS'] === "false") exit;
422
-
423
- $layoutContent = file_get_contents(APP_PATH . '/layout.php');
424
- if ($layoutContent !== false) {
425
- $newBodyContent = "<body class=\"fatal-error\">$contentToAdd</body>";
426
382
 
427
- $modifiedNotFoundContent = preg_replace('~<body.*?>.*?</body>~s', $newBodyContent, $layoutContent);
383
+ // Improved regular expression to match different ways of echoing $content
384
+ $pattern = '/\<\?=\s*\$content\s*;?\s*\?>|echo\s*\$content\s*;?/';
428
385
 
429
- echo $modifiedNotFoundContent;
430
- exit;
431
- }
386
+ // Return true if content variables are found, false otherwise
387
+ return preg_match($pattern, $fileContent) === 1;
432
388
  }
433
389
 
434
390
  function convertToArrayObject($data)
@@ -579,17 +535,7 @@ function getLoadingsFiles()
579
535
  return '';
580
536
  }
581
537
 
582
- function authenticateUserToken()
583
- {
584
- $token = getBearerToken();
585
- if ($token) {
586
- $auth = Auth::getInstance();
587
- $verifyToken = $auth->verifyToken($token);
588
- if ($verifyToken) {
589
- $auth->authenticate($verifyToken);
590
- }
591
- }
592
- }
538
+
593
539
 
594
540
  function getPrismaSettings(): \ArrayObject
595
541
  {
@@ -607,15 +553,101 @@ function getPrismaSettings(): \ArrayObject
607
553
  }
608
554
  }
609
555
 
610
- ob_start();
556
+ function modifyOutputLayoutForError($contentToAdd)
557
+ {
558
+ global
559
+ $baseUrl,
560
+ $metadata,
561
+ $content,
562
+ $childContent,
563
+ $uri,
564
+ $pathname,
565
+ $dynamicRouteParams,
566
+ $params,
567
+ $referer,
568
+ $mainLayoutHead,
569
+ $mainLayoutFooter;
570
+
571
+ $errorFile = APP_PATH . '/error.php';
572
+ $errorFileExists = file_exists($errorFile);
573
+
574
+ if ($_ENV['SHOW_ERRORS'] === "false") {
575
+ if ($errorFileExists) {
576
+ $contentToAdd = "<div class='error'>An error occurred</div>";
577
+ } else {
578
+ exit; // Exit if SHOW_ERRORS is false and no error file exists
579
+ }
580
+ }
581
+
582
+ if ($errorFileExists) {
583
+
584
+ $errorContent = $contentToAdd;
585
+
586
+ $layoutFile = APP_PATH . '/layout.php';
587
+ if (file_exists($layoutFile)) {
588
+
589
+ ob_start();
590
+ include_once $errorFile;
591
+ $content = ob_get_clean();
592
+ include $layoutFile;
593
+ } else {
594
+ echo $errorContent;
595
+ }
596
+ }
597
+ exit;
598
+ }
599
+
600
+ set_error_handler(function ($severity, $message, $file, $line) {
601
+ if (!(error_reporting() & $severity)) {
602
+ // This error code is not included in error_reporting
603
+ return;
604
+ }
605
+
606
+ // Capture the specific severity types, including warnings (E_WARNING)
607
+ $errorContent = "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
608
+
609
+ // If needed, log it or output immediately based on severity
610
+ if ($severity === E_WARNING || $severity === E_NOTICE) {
611
+ modifyOutputLayoutForError($errorContent);
612
+ }
613
+ });
614
+
615
+ set_exception_handler(function ($exception) {
616
+ $errorContent = "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
617
+ modifyOutputLayoutForError($errorContent);
618
+ });
619
+
620
+ register_shutdown_function(function () {
621
+ $error = error_get_last();
622
+ if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
623
+ $formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
624
+ " in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
625
+ " on line " . $error['line'] . "</div>";
626
+ $errorContent = $formattedError;
627
+ modifyOutputLayoutForError($errorContent);
628
+ }
629
+ });
630
+
611
631
  require_once SETTINGS_PATH . '/public-functions.php';
612
632
  require_once SETTINGS_PATH . '/request-methods.php';
613
633
  $_metadataFile = APP_PATH . '/metadata.php';
614
634
  $_metadataArray = file_exists($_metadataFile) ? require_once $_metadataFile : [];
615
- $_filesListRoutes = [];
635
+ $_filesListRoutes = getFilesListRoutes();
616
636
  $_prismaPHPSettings = getPrismaSettings();
617
637
  $_fileToInclude = '';
618
638
 
639
+ function authenticateUserToken()
640
+ {
641
+ $token = getBearerToken();
642
+ if ($token) {
643
+ $auth = Auth::getInstance();
644
+ $verifyToken = $auth->verifyToken($token);
645
+ if ($verifyToken) {
646
+ $auth->authenticate($verifyToken);
647
+ }
648
+ }
649
+ }
650
+
619
651
  /**
620
652
  * @var array $metadata Metadata information
621
653
  */
@@ -656,7 +688,10 @@ try {
656
688
  $_layoutsToInclude = $_determineContentToInclude['layouts'] ?? [];
657
689
  $uri = $_determineContentToInclude['uri'] ?? '';
658
690
  $pathname = $uri ? "/" . $uri : "/";
659
- $_fileToInclude = basename($_contentToInclude);
691
+ $_fileToInclude = null;
692
+ if (is_file($_contentToInclude)) {
693
+ $_fileToInclude = basename($_contentToInclude); // returns the file name
694
+ }
660
695
  authenticateUserToken();
661
696
 
662
697
  if (empty($_contentToInclude)) {
@@ -710,11 +745,11 @@ try {
710
745
 
711
746
  $_isContentIncluded = false;
712
747
  $_isChildContentIncluded = false;
713
- if (containsContent($_parentLayoutPath)) {
748
+ $_isContentVariableIncluded = containsContent($_parentLayoutPath);
749
+ if (!$_isContentVariableIncluded) {
714
750
  $_isContentIncluded = true;
715
751
  }
716
752
 
717
- ob_start();
718
753
  if (!empty($_contentToInclude)) {
719
754
  if (!$_isParentLayout) {
720
755
  ob_start();
@@ -726,7 +761,8 @@ try {
726
761
  continue;
727
762
  }
728
763
 
729
- if (containsChildContent($layoutPath)) {
764
+ $_isChildContentVariableIncluded = containsChildContent($layoutPath);
765
+ if (!$_isChildContentVariableIncluded) {
730
766
  $_isChildContentIncluded = true;
731
767
  }
732
768
 
@@ -759,18 +795,15 @@ try {
759
795
  }
760
796
  } else {
761
797
  if ($_isContentIncluded) {
762
- $content .= "<div class='error'>The parent layout file does not contain &lt;?php echo \$content; ?&gt; Or &lt;?= \$content ?&gt;<br>" . "<strong>$_parentLayoutPath</strong></div>";
763
- modifyOutputLayoutForError($content);
798
+ echo "<div class='error'>The parent layout file does not contain &lt;?php echo \$content; ?&gt; Or &lt;?= \$content ?&gt;<br>" . "<strong>$_parentLayoutPath</strong></div>";
764
799
  } else {
765
- $content .= "<div class='error'>The layout file does not contain &lt;?php echo \$childContent; ?&gt; or &lt;?= \$childContent ?&gt;<br><strong>$layoutPath</strong></div>";
766
- modifyOutputLayoutForError($content);
800
+ echo "<div class='error'>The layout file does not contain &lt;?php echo \$childContent; ?&gt; or &lt;?= \$childContent ?&gt;<br><strong>$layoutPath</strong></div>";
767
801
  }
768
802
  }
769
803
  } catch (Throwable $e) {
770
- $content = ob_get_clean();
771
804
  $errorDetails = "Unhandled Exception: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
772
805
  $errorDetails .= "<br>File: " . htmlspecialchars($e->getFile(), ENT_QUOTES, 'UTF-8');
773
806
  $errorDetails .= "<br>Line: " . htmlspecialchars($e->getLine(), ENT_QUOTES, 'UTF-8');
774
- $content .= "<div class='error'>" . $errorDetails . "</div>";
775
- modifyOutputLayoutForError($content);
807
+ $errorDetails = "<div class='error'>$errorDetails</div>";
808
+ modifyOutputLayoutForError($errorDetails);
776
809
  }