create-prisma-php-app 1.11.18 → 1.11.20
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.
|
@@ -14,9 +14,9 @@ class Auth
|
|
|
14
14
|
{
|
|
15
15
|
public const PAYLOAD_NAME = 'role';
|
|
16
16
|
public const ROLE_NAME = '';
|
|
17
|
-
public const PAYLOAD = '
|
|
18
|
-
public const COOKIE_NAME = '
|
|
19
|
-
private const PPHPAUTH = '
|
|
17
|
+
public const PAYLOAD = 'payload_2183A';
|
|
18
|
+
public const COOKIE_NAME = 'pphp_aut_token_D36E5';
|
|
19
|
+
private const PPHPAUTH = 'pphpauth_9C5D5';
|
|
20
20
|
|
|
21
21
|
private $secretKey;
|
|
22
22
|
private $defaultTokenValidity = '1h'; // Default to 1 hour
|
|
@@ -213,38 +213,59 @@ class Auth
|
|
|
213
213
|
// Save user data to the database
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
private function findProvider(array $providers, string $type): ?object
|
|
217
|
+
{
|
|
218
|
+
foreach ($providers as $provider) {
|
|
219
|
+
if ($provider instanceof $type) {
|
|
220
|
+
return $provider;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public function authProviders(...$providers)
|
|
217
227
|
{
|
|
218
228
|
global $isGet, $dynamicRouteParams;
|
|
219
229
|
|
|
220
|
-
if ($isGet && in_array('signin', $dynamicRouteParams[self::PPHPAUTH])
|
|
221
|
-
$
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
if ($isGet && in_array('signin', $dynamicRouteParams[self::PPHPAUTH])) {
|
|
231
|
+
foreach ($providers as $provider) {
|
|
232
|
+
if ($provider instanceof GithubProvider && in_array('github', $dynamicRouteParams[self::PPHPAUTH])) {
|
|
233
|
+
$githubAuthUrl = "https://github.com/login/oauth/authorize?scope=user:email%20read:user&client_id={$provider->clientId}";
|
|
234
|
+
redirect($githubAuthUrl);
|
|
235
|
+
} elseif ($provider instanceof GoogleProvider && in_array('google', $dynamicRouteParams[self::PPHPAUTH])) {
|
|
236
|
+
$googleAuthUrl = "https://accounts.google.com/o/oauth2/v2/auth?"
|
|
237
|
+
. "scope=" . urlencode('email profile') . "&"
|
|
238
|
+
. "response_type=code&"
|
|
239
|
+
. "client_id=" . urlencode($provider->clientId) . "&"
|
|
240
|
+
. "redirect_uri=" . urlencode($provider->redirectUri);
|
|
241
|
+
redirect($googleAuthUrl);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
231
244
|
}
|
|
232
245
|
|
|
233
246
|
$authCode = Validator::validateString($_GET['code'] ?? '');
|
|
234
247
|
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
if ($isGet && in_array('callback', $dynamicRouteParams[self::PPHPAUTH]) && isset($authCode)) {
|
|
249
|
+
if (in_array('github', $dynamicRouteParams[self::PPHPAUTH])) {
|
|
250
|
+
$provider = $this->findProvider($providers, GithubProvider::class);
|
|
251
|
+
|
|
252
|
+
if (!$provider) {
|
|
253
|
+
exit("Error occurred. Please try again.");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return $this->githubProvider($provider, $authCode);
|
|
257
|
+
} elseif (in_array('google', $dynamicRouteParams[self::PPHPAUTH])) {
|
|
258
|
+
$provider = $this->findProvider($providers, GoogleProvider::class);
|
|
259
|
+
|
|
260
|
+
if (!$provider) {
|
|
261
|
+
exit("Error occurred. Please try again.");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return $this->googleProvider($provider, $authCode);
|
|
265
|
+
}
|
|
247
266
|
}
|
|
267
|
+
|
|
268
|
+
exit("Error occurred. Please try again.");
|
|
248
269
|
}
|
|
249
270
|
|
|
250
271
|
private function githubProvider(GithubProvider $githubProvider, string $authCode)
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Lib;
|
|
4
|
+
|
|
5
|
+
use Lib\StateManager;
|
|
6
|
+
use Lib\Validator;
|
|
7
|
+
|
|
8
|
+
class FormHandler
|
|
9
|
+
{
|
|
10
|
+
private $data;
|
|
11
|
+
private $errors;
|
|
12
|
+
private $validated;
|
|
13
|
+
private $isPost;
|
|
14
|
+
private $pathname;
|
|
15
|
+
private StateManager $stateManager;
|
|
16
|
+
private const FORM_STATE = 'pphp_form_state_977A9';
|
|
17
|
+
private const FORM_INPUT_REGISTER = 'pphp_form_input_register_7A16F';
|
|
18
|
+
private const FORM_INPUT_ERRORS = 'pphp_form_input_errors_CBF6C';
|
|
19
|
+
|
|
20
|
+
public function __construct($formData = [])
|
|
21
|
+
{
|
|
22
|
+
global $isPost, $pathname;
|
|
23
|
+
|
|
24
|
+
$this->isPost = $isPost;
|
|
25
|
+
$this->pathname = $pathname;
|
|
26
|
+
$this->data = $formData;
|
|
27
|
+
$this->errors = [];
|
|
28
|
+
$this->validated = false;
|
|
29
|
+
|
|
30
|
+
$this->stateManager = new StateManager();
|
|
31
|
+
|
|
32
|
+
if ($this->stateManager->getState(self::FORM_INPUT_REGISTER)) {
|
|
33
|
+
$this->getData();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validates the form data.
|
|
39
|
+
*
|
|
40
|
+
* @return bool True if the form data is valid, false otherwise.
|
|
41
|
+
*/
|
|
42
|
+
public function validate(): bool
|
|
43
|
+
{
|
|
44
|
+
return empty($this->errors) && $this->validated;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public function addError($field, $message)
|
|
48
|
+
{
|
|
49
|
+
$this->errors[$field] = $message;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the form data and performs validation if the form was submitted.
|
|
54
|
+
*
|
|
55
|
+
* @return mixed An object containing the form data.
|
|
56
|
+
*/
|
|
57
|
+
public function getData(): mixed
|
|
58
|
+
{
|
|
59
|
+
if ($this->isPost) {
|
|
60
|
+
if ($inputField = $this->stateManager->getState(self::FORM_INPUT_REGISTER)) {
|
|
61
|
+
foreach ($inputField as $field => $fieldData) {
|
|
62
|
+
$this->data[$field] = Validator::validateString($this->data[$field] ?? '');
|
|
63
|
+
$this->validateField($field, $fieldData['rules']);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
$formDataInfo = [
|
|
68
|
+
'data' => $this->data,
|
|
69
|
+
'errors' => $this->errors,
|
|
70
|
+
'validated' => true
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
$this->stateManager->resetState(self::FORM_INPUT_ERRORS, true);
|
|
74
|
+
$this->stateManager->setState([self::FORM_INPUT_ERRORS => $formDataInfo], true);
|
|
75
|
+
$this->stateManager->setState([self::FORM_STATE => $formDataInfo], true);
|
|
76
|
+
|
|
77
|
+
redirect($this->pathname);
|
|
78
|
+
} else {
|
|
79
|
+
if ($state = $this->stateManager->getState(self::FORM_STATE)) {
|
|
80
|
+
$this->data = $state['data'] ?? [];
|
|
81
|
+
$this->errors = $state['errors'] ?? [];
|
|
82
|
+
$this->validated = $state['validated'] ?? false;
|
|
83
|
+
|
|
84
|
+
$this->stateManager->resetState([self::FORM_STATE, self::FORM_INPUT_REGISTER], true);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return new \ArrayObject($this->data, \ArrayObject::ARRAY_AS_PROPS);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Retrieves the validation errors from the form state.
|
|
93
|
+
*
|
|
94
|
+
* @param string|null $field The name of the field to get errors for. If null, all errors are returned.
|
|
95
|
+
* @return mixed If a field name is provided, returns the error message for that field or an empty string if no error.
|
|
96
|
+
* If no field name is provided, returns an associative array of all errors or an empty array if no errors.
|
|
97
|
+
* If the form has not been validated yet, returns an empty string.
|
|
98
|
+
*/
|
|
99
|
+
public function getErrors(string $field = null): mixed
|
|
100
|
+
{
|
|
101
|
+
$state = $this->stateManager->getState(self::FORM_INPUT_ERRORS);
|
|
102
|
+
|
|
103
|
+
if ($this->validated && $state) {
|
|
104
|
+
if ($field) {
|
|
105
|
+
return $state['errors'][$field] ?? '';
|
|
106
|
+
}
|
|
107
|
+
return $state['errors'] ?? [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Validates a form field based on the provided rules.
|
|
115
|
+
*
|
|
116
|
+
* @param string $field The name of the field to validate.
|
|
117
|
+
* @param array $rules An associative array of rules to apply. Each key is the rule name, and the value is the rule options.
|
|
118
|
+
* The options can be a scalar value or an array with 'value' and 'message' keys.
|
|
119
|
+
* The 'value' key is the value to compare with, and the 'message' key is the custom error message.
|
|
120
|
+
*
|
|
121
|
+
* Supported rules:
|
|
122
|
+
* - text, search, email, password, number, date, color, range, tel, url, time, datetime-local, month, week, file
|
|
123
|
+
* - required, min, max, minLength, maxLength, pattern, autocomplete, readonly, disabled, placeholder, autofocus, multiple, accept, size, step, list
|
|
124
|
+
*
|
|
125
|
+
* Custom error messages can be provided for each rule. If not provided, a default message is used.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* $form->validateField('email', [
|
|
129
|
+
* 'required' => ['value' => true, 'message' => 'Email is required.'],
|
|
130
|
+
* 'email' => ['value' => true, 'message' => 'Please enter a valid email address.']
|
|
131
|
+
* ]);
|
|
132
|
+
*
|
|
133
|
+
* @return void
|
|
134
|
+
*/
|
|
135
|
+
public function validateField($field, $rules)
|
|
136
|
+
{
|
|
137
|
+
$value = Validator::validateString($this->data[$field] ?? null);
|
|
138
|
+
foreach ($rules as $rule => $options) {
|
|
139
|
+
$ruleValue = $options;
|
|
140
|
+
$customMessage = null;
|
|
141
|
+
|
|
142
|
+
if (is_array($options)) {
|
|
143
|
+
$ruleValue = $options['value'];
|
|
144
|
+
$customMessage = $options['message'] ?? null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
switch ($rule) {
|
|
148
|
+
case 'text':
|
|
149
|
+
case 'search':
|
|
150
|
+
if (!is_string($value)) $this->addError($field, $customMessage ?? 'Must be a string.');
|
|
151
|
+
break;
|
|
152
|
+
case 'email':
|
|
153
|
+
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) $this->addError($field, $customMessage ?? 'Invalid email format.');
|
|
154
|
+
break;
|
|
155
|
+
case 'number':
|
|
156
|
+
if (!is_numeric($value)) $this->addError($field, $customMessage ?? 'Must be a number.');
|
|
157
|
+
break;
|
|
158
|
+
case 'date':
|
|
159
|
+
if (!\DateTime::createFromFormat('Y-m-d', $value)) $this->addError($field, $customMessage ?? 'Invalid date format.');
|
|
160
|
+
break;
|
|
161
|
+
case 'range':
|
|
162
|
+
if (!is_numeric($value) || $value < $ruleValue[0] || $value > $ruleValue[1]) $this->addError($field, $customMessage ?? "Must be between $ruleValue[0] and $ruleValue[1].");
|
|
163
|
+
break;
|
|
164
|
+
case 'url':
|
|
165
|
+
if (!filter_var($value, FILTER_VALIDATE_URL)) $this->addError($field, $customMessage ?? 'Invalid URL format.');
|
|
166
|
+
break;
|
|
167
|
+
case 'datetime-local':
|
|
168
|
+
if (!\DateTime::createFromFormat('Y-m-d\TH:i', $value)) $this->addError($field, $customMessage ?? 'Invalid datetime-local format.');
|
|
169
|
+
break;
|
|
170
|
+
case 'file':
|
|
171
|
+
if (!is_uploaded_file($value)) $this->addError($field, $customMessage ?? 'Invalid file format.');
|
|
172
|
+
break;
|
|
173
|
+
case 'required':
|
|
174
|
+
if (empty($value)) $this->addError($field, $customMessage ?? 'This field is required.');
|
|
175
|
+
break;
|
|
176
|
+
case 'min':
|
|
177
|
+
if ($value < $ruleValue) $this->addError($field, $customMessage ?? "Must be at least $ruleValue.");
|
|
178
|
+
break;
|
|
179
|
+
case 'max':
|
|
180
|
+
if ($value > $ruleValue) $this->addError($field, $customMessage ?? "Must be at most $ruleValue.");
|
|
181
|
+
break;
|
|
182
|
+
case 'minLength':
|
|
183
|
+
if (strlen($value) < $ruleValue) $this->addError($field, $customMessage ?? "Must be at least $ruleValue characters.");
|
|
184
|
+
break;
|
|
185
|
+
case 'maxLength':
|
|
186
|
+
if (strlen($value) > $ruleValue) $this->addError($field, $customMessage ?? "Must be at most $ruleValue characters.");
|
|
187
|
+
break;
|
|
188
|
+
case 'pattern':
|
|
189
|
+
if (!preg_match("/$ruleValue/", $value)) $this->addError($field, $customMessage ?? 'Invalid format.');
|
|
190
|
+
break;
|
|
191
|
+
case 'accept':
|
|
192
|
+
if (!in_array($value, explode(',', $ruleValue))) $this->addError($field, $customMessage ?? 'Invalid file format.');
|
|
193
|
+
break;
|
|
194
|
+
case 'autocomplete':
|
|
195
|
+
if (!in_array($value, ['on', 'off'])) $this->addError($field, $customMessage ?? 'Invalid autocomplete value.');
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
// Optionally handle unknown rules or log them
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Registers a form field and its validation rules, and updates the form state.
|
|
206
|
+
*
|
|
207
|
+
* @param string $fieldName The name of the form field.
|
|
208
|
+
* @param array $rules Validation rules for the field.
|
|
209
|
+
* @return string HTML attributes for the field.
|
|
210
|
+
*/
|
|
211
|
+
public function register($fieldName, $rules = []): string
|
|
212
|
+
{
|
|
213
|
+
$value = Validator::validateString($this->data[$fieldName] ?? '');
|
|
214
|
+
$attributes = "name=\"$fieldName\" value=\"$value\"";
|
|
215
|
+
|
|
216
|
+
if (!array_intersect(array_keys($rules), ['text', 'email', 'password', 'number', 'date', 'color', 'range', 'tel', 'url', 'search', 'time', 'datetime-local', 'month', 'week'])) {
|
|
217
|
+
$rules['text'] = ['value' => true];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
foreach ($rules as $rule => $ruleValue) {
|
|
221
|
+
$attributes .= $this->parseRule($rule, $ruleValue);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
$inputField = $this->stateManager->getState(self::FORM_INPUT_REGISTER) ?? [];
|
|
225
|
+
$inputField[$fieldName] = [
|
|
226
|
+
'value' => $value,
|
|
227
|
+
'attributes' => $attributes,
|
|
228
|
+
'rules' => $rules
|
|
229
|
+
];
|
|
230
|
+
$this->stateManager->setState([self::FORM_INPUT_REGISTER => $inputField], true);
|
|
231
|
+
|
|
232
|
+
return $attributes;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private function parseRule($rule, $ruleValue)
|
|
236
|
+
{
|
|
237
|
+
$attribute = '';
|
|
238
|
+
$ruleParam = is_array($ruleValue) ? $ruleValue['value'] : $ruleValue;
|
|
239
|
+
|
|
240
|
+
switch ($rule) {
|
|
241
|
+
case 'text':
|
|
242
|
+
case 'search':
|
|
243
|
+
case 'email':
|
|
244
|
+
case 'password':
|
|
245
|
+
case 'number':
|
|
246
|
+
case 'date':
|
|
247
|
+
case 'color':
|
|
248
|
+
case 'range':
|
|
249
|
+
case 'tel':
|
|
250
|
+
case 'url':
|
|
251
|
+
case 'time':
|
|
252
|
+
case 'datetime-local':
|
|
253
|
+
case 'month':
|
|
254
|
+
case 'week':
|
|
255
|
+
case 'file':
|
|
256
|
+
$attribute .= " type=\"$rule\"";
|
|
257
|
+
break;
|
|
258
|
+
case 'required':
|
|
259
|
+
$attribute .= " required";
|
|
260
|
+
break;
|
|
261
|
+
case 'min':
|
|
262
|
+
case 'max':
|
|
263
|
+
$attribute .= " $rule=\"$ruleParam\"";
|
|
264
|
+
break;
|
|
265
|
+
case 'minLength':
|
|
266
|
+
case 'maxLength':
|
|
267
|
+
$attribute .= " $rule=\"{$ruleParam}\"";
|
|
268
|
+
break;
|
|
269
|
+
case 'pattern':
|
|
270
|
+
$attribute .= " pattern=\"$ruleParam\"";
|
|
271
|
+
break;
|
|
272
|
+
case 'autocomplete':
|
|
273
|
+
$attribute .= " autocomplete=\"$ruleParam\"";
|
|
274
|
+
break;
|
|
275
|
+
case 'readonly':
|
|
276
|
+
$attribute .= " readonly";
|
|
277
|
+
break;
|
|
278
|
+
case 'disabled':
|
|
279
|
+
$attribute .= " disabled";
|
|
280
|
+
break;
|
|
281
|
+
case 'placeholder':
|
|
282
|
+
$attribute .= " placeholder=\"$ruleParam\"";
|
|
283
|
+
break;
|
|
284
|
+
case 'autofocus':
|
|
285
|
+
$attribute .= " autofocus";
|
|
286
|
+
break;
|
|
287
|
+
case 'multiple':
|
|
288
|
+
$attribute .= " multiple";
|
|
289
|
+
break;
|
|
290
|
+
case 'accept':
|
|
291
|
+
$attribute .= " accept=\"$ruleParam\"";
|
|
292
|
+
break;
|
|
293
|
+
case 'size':
|
|
294
|
+
$attribute .= " size=\"$ruleParam\"";
|
|
295
|
+
break;
|
|
296
|
+
case 'step':
|
|
297
|
+
$attribute .= " step=\"$ruleParam\"";
|
|
298
|
+
break;
|
|
299
|
+
case 'list':
|
|
300
|
+
$attribute .= " list=\"$ruleParam\"";
|
|
301
|
+
break;
|
|
302
|
+
default:
|
|
303
|
+
// Optionally handle unknown rules or log them
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
return $attribute;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -9,14 +9,11 @@ use Lib\Validator;
|
|
|
9
9
|
class Mailer
|
|
10
10
|
{
|
|
11
11
|
private PHPMailer $mail;
|
|
12
|
-
private Validator $validator;
|
|
13
12
|
|
|
14
13
|
public function __construct()
|
|
15
14
|
{
|
|
16
15
|
$this->mail = new PHPMailer(true);
|
|
17
16
|
$this->setup();
|
|
18
|
-
|
|
19
|
-
$this->validator = new Validator();
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
private function setup(): void
|
|
@@ -67,11 +64,11 @@ class Mailer
|
|
|
67
64
|
public function send(string $to, string $subject, string $body, string $name = '', string $altBody = ''): bool
|
|
68
65
|
{
|
|
69
66
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
Validator::validateString($to);
|
|
68
|
+
Validator::validateString($subject);
|
|
69
|
+
Validator::validateString($body);
|
|
70
|
+
Validator::validateString($name);
|
|
71
|
+
Validator::validateString($altBody);
|
|
75
72
|
|
|
76
73
|
$this->mail->addAddress($to, $name);
|
|
77
74
|
$this->mail->isHTML(true);
|
|
@@ -77,6 +77,34 @@ class Validator
|
|
|
77
77
|
return static::validateInt($value); // Placeholder
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
public static function validateDate($value)
|
|
81
|
+
{
|
|
82
|
+
$date = \DateTime::createFromFormat('Y-m-d', $value);
|
|
83
|
+
if ($date && $date->format('Y-m-d') === $value) {
|
|
84
|
+
return $value;
|
|
85
|
+
} else {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public static function validateEmail($value)
|
|
91
|
+
{
|
|
92
|
+
if ($value === null) {
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return filter_var($value, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public static function validateUrl($value)
|
|
100
|
+
{
|
|
101
|
+
if ($value === null) {
|
|
102
|
+
return '';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return filter_var($value, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
|
|
106
|
+
}
|
|
107
|
+
|
|
80
108
|
public static function validateUnsupported($value)
|
|
81
109
|
{
|
|
82
110
|
// Placeholder for future data types
|