create-prisma-php-app 1.20.518 → 1.20.520
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.
- package/dist/bootstrap.php +75 -40
- package/dist/index.js +16 -9
- package/dist/settings/public-functions.php +29 -0
- package/dist/settings/swagger-setup.js +39 -7
- package/dist/src/Lib/Auth/Auth.php +29 -6
- package/dist/src/app/route.php +2 -1
- package/package.json +1 -1
package/dist/bootstrap.php
CHANGED
|
@@ -8,6 +8,7 @@ require_once __DIR__ . '/vendor/autoload.php';
|
|
|
8
8
|
require_once __DIR__ . '/settings/paths.php';
|
|
9
9
|
|
|
10
10
|
use Lib\Middleware\AuthMiddleware;
|
|
11
|
+
use Lib\Auth\Auth;
|
|
11
12
|
use Dotenv\Dotenv;
|
|
12
13
|
|
|
13
14
|
$dotenv = Dotenv::createImmutable(\DOCUMENT_PATH);
|
|
@@ -136,8 +137,9 @@ function getFilePrecedence()
|
|
|
136
137
|
|
|
137
138
|
function uriExtractor(string $scriptUrl): string
|
|
138
139
|
{
|
|
139
|
-
$
|
|
140
|
-
|
|
140
|
+
global $_prismaPHPSettings;
|
|
141
|
+
|
|
142
|
+
$projectName = $_prismaPHPSettings['projectName'] ?? '';
|
|
141
143
|
if (empty($projectName)) {
|
|
142
144
|
return "/";
|
|
143
145
|
}
|
|
@@ -383,44 +385,6 @@ function setupErrorHandling(&$content)
|
|
|
383
385
|
});
|
|
384
386
|
}
|
|
385
387
|
|
|
386
|
-
ob_start();
|
|
387
|
-
require_once SETTINGS_PATH . '/public-functions.php';
|
|
388
|
-
require_once SETTINGS_PATH . '/request-methods.php';
|
|
389
|
-
$_metadataFile = APP_PATH . '/metadata.php';
|
|
390
|
-
$_metadataArray = file_exists($_metadataFile) ? require_once $_metadataFile : [];
|
|
391
|
-
$_filesListRoutes = [];
|
|
392
|
-
/**
|
|
393
|
-
* @var array $metadata Metadata information
|
|
394
|
-
*/
|
|
395
|
-
$metadata = [];
|
|
396
|
-
/**
|
|
397
|
-
* @var string $uri The URI of the current request
|
|
398
|
-
*/
|
|
399
|
-
$uri = "";
|
|
400
|
-
/**
|
|
401
|
-
* @var string $pathname The pathname of the current request
|
|
402
|
-
*/
|
|
403
|
-
$pathname = "";
|
|
404
|
-
/**
|
|
405
|
-
* @var array $dynamicRouteParams The dynamic route parameters
|
|
406
|
-
*/
|
|
407
|
-
$dynamicRouteParams = [];
|
|
408
|
-
/**
|
|
409
|
-
* @var string $content The content to be included in the main layout file
|
|
410
|
-
*/
|
|
411
|
-
$content = "";
|
|
412
|
-
/**
|
|
413
|
-
* @var string $childContent The child content to be included in the layout file
|
|
414
|
-
*/
|
|
415
|
-
$childContent = "";
|
|
416
|
-
/**
|
|
417
|
-
* @var array $mainLayoutHead The head content to be included in the main layout file
|
|
418
|
-
*/
|
|
419
|
-
$mainLayoutHead = [];
|
|
420
|
-
/**
|
|
421
|
-
* @var array $mainLayoutFooter The footer content to be included in the main layout file
|
|
422
|
-
*/
|
|
423
|
-
$mainLayoutFooter = [];
|
|
424
388
|
|
|
425
389
|
function containsChildContent($filePath)
|
|
426
390
|
{
|
|
@@ -615,6 +579,76 @@ function getLoadingsFiles()
|
|
|
615
579
|
return '';
|
|
616
580
|
}
|
|
617
581
|
|
|
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
|
+
}
|
|
593
|
+
|
|
594
|
+
function getPrismaSettings(): \ArrayObject
|
|
595
|
+
{
|
|
596
|
+
$_prismaPHPSettingsFile = DOCUMENT_PATH . '/prisma-php.json';
|
|
597
|
+
|
|
598
|
+
if (file_exists($_prismaPHPSettingsFile)) {
|
|
599
|
+
$jsonContent = file_get_contents($_prismaPHPSettingsFile);
|
|
600
|
+
$decodedJson = json_decode($jsonContent, true);
|
|
601
|
+
|
|
602
|
+
if (json_last_error() === JSON_ERROR_NONE) {
|
|
603
|
+
return new \ArrayObject($decodedJson, \ArrayObject::ARRAY_AS_PROPS);
|
|
604
|
+
} else {
|
|
605
|
+
return new \ArrayObject([]);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
ob_start();
|
|
611
|
+
require_once SETTINGS_PATH . '/public-functions.php';
|
|
612
|
+
require_once SETTINGS_PATH . '/request-methods.php';
|
|
613
|
+
$_metadataFile = APP_PATH . '/metadata.php';
|
|
614
|
+
$_metadataArray = file_exists($_metadataFile) ? require_once $_metadataFile : [];
|
|
615
|
+
$_filesListRoutes = [];
|
|
616
|
+
$_prismaPHPSettings = getPrismaSettings();
|
|
617
|
+
$_fileToInclude = '';
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @var array $metadata Metadata information
|
|
621
|
+
*/
|
|
622
|
+
$metadata = [];
|
|
623
|
+
/**
|
|
624
|
+
* @var string $uri The URI of the current request
|
|
625
|
+
*/
|
|
626
|
+
$uri = "";
|
|
627
|
+
/**
|
|
628
|
+
* @var string $pathname The pathname of the current request
|
|
629
|
+
*/
|
|
630
|
+
$pathname = "";
|
|
631
|
+
/**
|
|
632
|
+
* @var array $dynamicRouteParams The dynamic route parameters
|
|
633
|
+
*/
|
|
634
|
+
$dynamicRouteParams = [];
|
|
635
|
+
/**
|
|
636
|
+
* @var string $content The content to be included in the main layout file
|
|
637
|
+
*/
|
|
638
|
+
$content = "";
|
|
639
|
+
/**
|
|
640
|
+
* @var string $childContent The child content to be included in the layout file
|
|
641
|
+
*/
|
|
642
|
+
$childContent = "";
|
|
643
|
+
/**
|
|
644
|
+
* @var array $mainLayoutHead The head content to be included in the main layout file
|
|
645
|
+
*/
|
|
646
|
+
$mainLayoutHead = [];
|
|
647
|
+
/**
|
|
648
|
+
* @var array $mainLayoutFooter The footer content to be included in the main layout file
|
|
649
|
+
*/
|
|
650
|
+
$mainLayoutFooter = [];
|
|
651
|
+
|
|
618
652
|
try {
|
|
619
653
|
$_determineContentToInclude = determineContentToInclude();
|
|
620
654
|
checkForDuplicateRoutes();
|
|
@@ -622,6 +656,7 @@ try {
|
|
|
622
656
|
$_layoutsToInclude = $_determineContentToInclude['layouts'] ?? [];
|
|
623
657
|
$uri = $_determineContentToInclude['uri'] ?? '';
|
|
624
658
|
$pathname = $uri ? "/" . $uri : "/";
|
|
659
|
+
$_fileToInclude = basename($_contentToInclude);
|
|
625
660
|
|
|
626
661
|
if (empty($_contentToInclude)) {
|
|
627
662
|
if (!$isXFilRequest) {
|
package/dist/index.js
CHANGED
|
@@ -343,18 +343,23 @@ function modifyLayoutPHP(baseDir, answer) {
|
|
|
343
343
|
if (checkExcludeFiles(layoutPath)) return;
|
|
344
344
|
try {
|
|
345
345
|
let indexContent = fs.readFileSync(layoutPath, "utf8");
|
|
346
|
-
|
|
346
|
+
let stylesAndLinks = "";
|
|
347
|
+
if (!answer.backendOnly) {
|
|
348
|
+
stylesAndLinks = `\n <link href="<?php echo $baseUrl; ?>/css/index.css" rel="stylesheet">\n <script src="<?php echo $baseUrl; ?>/js/index.js"></script>`;
|
|
349
|
+
}
|
|
347
350
|
// Tailwind CSS link or CDN script
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
+
let tailwindLink = "";
|
|
352
|
+
if (!answer.backendOnly) {
|
|
353
|
+
tailwindLink = answer.tailwindcss
|
|
354
|
+
? ` <link href="<?php echo $baseUrl; ?>/css/styles.css" rel="stylesheet"> ${stylesAndLinks}`
|
|
355
|
+
: ` <script src="https://cdn.tailwindcss.com"></script> ${stylesAndLinks}`;
|
|
356
|
+
}
|
|
351
357
|
// Insert before the closing </head> tag
|
|
352
358
|
indexContent = indexContent.replace(
|
|
353
359
|
"</head>",
|
|
354
360
|
`${tailwindLink}\n <!-- Dynamic Head -->
|
|
355
361
|
<?php echo implode("\\n", $mainLayoutHead); ?></head>`
|
|
356
362
|
);
|
|
357
|
-
console.log("🚀 ~ modifyLayoutPHP ~ indexContent:", indexContent);
|
|
358
363
|
fs.writeFileSync(layoutPath, indexContent, { flag: "w" });
|
|
359
364
|
console.log(
|
|
360
365
|
chalk.green(
|
|
@@ -460,13 +465,15 @@ async function createDirectoryStructure(baseDir, answer) {
|
|
|
460
465
|
await executeCopy(baseDir, directoriesToCopy, answer);
|
|
461
466
|
await updatePackageJson(baseDir, answer);
|
|
462
467
|
await updateComposerJson(baseDir, answer);
|
|
463
|
-
if (!answer.backendOnly)
|
|
468
|
+
if (!answer.backendOnly) {
|
|
469
|
+
await updateIndexJsForWebSocket(baseDir, answer);
|
|
470
|
+
}
|
|
464
471
|
if (answer.tailwindcss) {
|
|
465
472
|
createOrUpdateTailwindConfig(baseDir);
|
|
466
|
-
modifyLayoutPHP(baseDir, answer);
|
|
467
473
|
modifyPostcssConfig(baseDir);
|
|
468
|
-
}
|
|
469
|
-
|
|
474
|
+
}
|
|
475
|
+
if (answer.tailwindcss || !answer.backendOnly || answer.swaggerDocs) {
|
|
476
|
+
modifyLayoutPHP(baseDir, answer);
|
|
470
477
|
}
|
|
471
478
|
const prismaPHPEnvContent = `# Prisma PHP Auth Secret Key For development only - Change this in production
|
|
472
479
|
AUTH_SECRET=uxsjXVPHN038DEYls2Kw0QUgBcXKUyrjv416nIFWPY4=
|
|
@@ -88,3 +88,32 @@ function isXFilRequest(): bool
|
|
|
88
88
|
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the Bearer token from the Authorization header.
|
|
94
|
+
*
|
|
95
|
+
* @return string|null The Bearer token or null if not present.
|
|
96
|
+
*/
|
|
97
|
+
function getBearerToken(): ?string
|
|
98
|
+
{
|
|
99
|
+
// Normalize headers to handle case-insensitive keys
|
|
100
|
+
$headers = array_change_key_case(getallheaders(), CASE_LOWER);
|
|
101
|
+
$authHeader = $headers['authorization'] ?? null;
|
|
102
|
+
|
|
103
|
+
// If not found, try fetching it from $_SERVER as a fallback
|
|
104
|
+
if (!$authHeader && isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
|
105
|
+
$authHeader = $_SERVER['HTTP_AUTHORIZATION'];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Fallback for Apache servers
|
|
109
|
+
if (!$authHeader && isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
|
110
|
+
$authHeader = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check if the Authorization header is in the expected Bearer format
|
|
114
|
+
if ($authHeader && preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
|
115
|
+
return $matches[1];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import swaggerJsdoc from "swagger-jsdoc";
|
|
2
|
-
import { writeFileSync } from "fs";
|
|
2
|
+
import { writeFileSync, readFileSync, existsSync } from "fs";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { join, dirname } from "path";
|
|
5
|
-
import { readFileSync } from "fs";
|
|
6
5
|
import chalk from "chalk";
|
|
7
6
|
|
|
8
7
|
// Define __dirname equivalent in ES modules
|
|
@@ -16,9 +15,28 @@ const outputPath = join(
|
|
|
16
15
|
);
|
|
17
16
|
|
|
18
17
|
const bsConnectionInfo = join(__dirname, "bs-output.json");
|
|
19
|
-
const jsonData = JSON.parse(readFileSync(bsConnectionInfo, "utf8"));
|
|
20
18
|
|
|
21
|
-
//
|
|
19
|
+
// Check if the bs-output.json file exists
|
|
20
|
+
const defaultConnectionInfo = {
|
|
21
|
+
local: "http://localhost:3000",
|
|
22
|
+
external: "http://192.168.1.5:3000",
|
|
23
|
+
ui: "http://localhost:3001",
|
|
24
|
+
uiExternal: "http://192.168.1.5:3001",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
let jsonData = defaultConnectionInfo;
|
|
28
|
+
|
|
29
|
+
if (existsSync(bsConnectionInfo)) {
|
|
30
|
+
try {
|
|
31
|
+
const data = readFileSync(bsConnectionInfo, "utf8");
|
|
32
|
+
jsonData = JSON.parse(data);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("Error parsing bs-output.json:", error);
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
console.warn("bs-output.json not found, using default connection info.");
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
const options = {
|
|
23
41
|
definition: {
|
|
24
42
|
openapi: "3.0.0",
|
|
@@ -30,11 +48,25 @@ const options = {
|
|
|
30
48
|
servers: [
|
|
31
49
|
{
|
|
32
50
|
url: jsonData.local, // For Development
|
|
33
|
-
description: "Server",
|
|
51
|
+
description: "Development Server",
|
|
34
52
|
},
|
|
35
53
|
{
|
|
36
|
-
url: "your-domain", // For Production
|
|
37
|
-
description: "Server",
|
|
54
|
+
url: "your-production-domain", // For Production
|
|
55
|
+
description: "Production Server",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
components: {
|
|
59
|
+
securitySchemes: {
|
|
60
|
+
bearerAuth: {
|
|
61
|
+
type: "http",
|
|
62
|
+
scheme: "bearer",
|
|
63
|
+
bearerFormat: "JWT",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
security: [
|
|
68
|
+
{
|
|
69
|
+
bearerAuth: [],
|
|
38
70
|
},
|
|
39
71
|
],
|
|
40
72
|
},
|
|
@@ -100,13 +100,22 @@ class Auth
|
|
|
100
100
|
*/
|
|
101
101
|
public function isAuthenticated(): bool
|
|
102
102
|
{
|
|
103
|
+
global $_fileToInclude;
|
|
104
|
+
|
|
103
105
|
if (!isset($_COOKIE[self::COOKIE_NAME])) {
|
|
104
106
|
unset($_SESSION[self::PAYLOAD]);
|
|
105
107
|
return false;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
$
|
|
110
|
+
if ($_fileToInclude === 'route.php') {
|
|
111
|
+
$bearerToken = getBearerToken();
|
|
112
|
+
$verifyBearerToken = $this->verifyToken($bearerToken);
|
|
113
|
+
if (!$verifyBearerToken) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
109
117
|
|
|
118
|
+
$jwt = $_COOKIE[self::COOKIE_NAME];
|
|
110
119
|
$verifyToken = $this->verifyToken($jwt);
|
|
111
120
|
if ($verifyToken === false) {
|
|
112
121
|
return false;
|
|
@@ -148,17 +157,31 @@ class Auth
|
|
|
148
157
|
|
|
149
158
|
/**
|
|
150
159
|
* Verifies the JWT token and returns the decoded payload if the token is valid.
|
|
151
|
-
* If the token is invalid,
|
|
160
|
+
* If the token is invalid or expired, null is returned.
|
|
152
161
|
*
|
|
153
162
|
* @param string $jwt The JWT token to verify.
|
|
154
|
-
* @return object Returns the decoded payload if the token is valid.
|
|
163
|
+
* @return object|null Returns the decoded payload if the token is valid, or null if invalid or expired.
|
|
155
164
|
*/
|
|
156
|
-
public function verifyToken(string $jwt)
|
|
165
|
+
public function verifyToken(?string $jwt): ?object
|
|
157
166
|
{
|
|
158
167
|
try {
|
|
159
|
-
|
|
168
|
+
if (!$jwt) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
$token = JWT::decode($jwt, new Key($this->secretKey, 'HS256'));
|
|
173
|
+
|
|
174
|
+
if (empty($token->role)) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (isset($token->exp) && time() >= $token->exp) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return $token;
|
|
160
183
|
} catch (\Exception) {
|
|
161
|
-
|
|
184
|
+
return null;
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
|
package/dist/src/app/route.php
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
$welcome = 'Welcome to the Prisma PHP Backend Only Starter Kit! This starter kit provides a powerful foundation for building robust PHP applications with Prisma PHP ORM, a modern database toolkit. To create a new route, follow these steps:
|
|
4
4
|
1. Create a new folder inside the "src/app" directory with the name of your route.
|
|
5
|
-
2. Inside the newly created folder, create a route.php file
|
|
5
|
+
2. Inside the newly created folder, create a route.php file. src/app/your-route/route.php
|
|
6
|
+
3. Define your route logic inside the route.php file.
|
|
6
7
|
|
|
7
8
|
This will serve as your API endpoint for the newly created route. Feel free to customize and extend the functionality as needed. Happy coding!
|
|
8
9
|
|