This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Proengsoft\JsValidation; |
||
4 | |||
5 | use Illuminate\Contracts\Validation\Factory as ValidationFactory; |
||
6 | use Illuminate\Foundation\Http\FormRequest as IlluminateFormRequest; |
||
7 | use Illuminate\Support\Arr; |
||
8 | use Illuminate\Validation\Validator; |
||
9 | use Proengsoft\JsValidation\Javascript\JavascriptValidator; |
||
10 | use Proengsoft\JsValidation\Javascript\MessageParser; |
||
11 | use Proengsoft\JsValidation\Javascript\RuleParser; |
||
12 | use Proengsoft\JsValidation\Javascript\ValidatorHandler; |
||
13 | use Proengsoft\JsValidation\Remote\FormRequest; |
||
14 | use Proengsoft\JsValidation\Support\DelegatedValidator; |
||
15 | use Proengsoft\JsValidation\Support\ValidationRuleParserProxy; |
||
16 | |||
17 | class JsValidatorFactory |
||
18 | { |
||
19 | const ASTERISK = '__asterisk__'; |
||
20 | |||
21 | /** |
||
22 | * The application instance. |
||
23 | * |
||
24 | * @var \Illuminate\Container\Container |
||
25 | */ |
||
26 | protected $app; |
||
27 | |||
28 | /** |
||
29 | * Configuration options. |
||
30 | * |
||
31 | * @var array |
||
32 | */ |
||
33 | protected $options; |
||
34 | |||
35 | /** |
||
36 | * Create a new Validator factory instance. |
||
37 | 84 | * |
|
38 | * @param \Illuminate\Container\Container $app |
||
39 | 84 | * @param array $options |
|
40 | 84 | */ |
|
41 | 84 | public function __construct($app, array $options = []) |
|
42 | { |
||
43 | $this->app = $app; |
||
44 | $this->setOptions($options); |
||
45 | } |
||
46 | |||
47 | 84 | /** |
|
48 | * @param $options |
||
49 | 84 | * @return void |
|
50 | 84 | */ |
|
51 | 84 | protected function setOptions($options) |
|
52 | { |
||
53 | 84 | $options['disable_remote_validation'] = empty($options['disable_remote_validation']) ? false : $options['disable_remote_validation']; |
|
54 | 84 | $options['view'] = empty($options['view']) ? 'jsvalidation:bootstrap' : $options['view']; |
|
55 | $options['form_selector'] = empty($options['form_selector']) ? 'form' : $options['form_selector']; |
||
56 | |||
57 | $this->options = $options; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Creates JsValidator instance based on rules and message arrays. |
||
62 | * |
||
63 | * @param array $rules |
||
64 | * @param array $messages |
||
65 | 48 | * @param array $customAttributes |
|
66 | * @param null|string $selector |
||
67 | 48 | * @return \Proengsoft\JsValidation\Javascript\JavascriptValidator |
|
68 | */ |
||
69 | 48 | public function make(array $rules, array $messages = [], array $customAttributes = [], $selector = null) |
|
70 | { |
||
71 | $validator = $this->getValidatorInstance($rules, $messages, $customAttributes); |
||
72 | |||
73 | return $this->validator($validator, $selector); |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * Get the validator instance for the request. |
||
78 | * |
||
79 | * @param array $rules |
||
80 | 72 | * @param array $messages |
|
81 | * @param array $customAttributes |
||
82 | 72 | * @return \Illuminate\Validation\Validator |
|
83 | */ |
||
84 | 72 | protected function getValidatorInstance(array $rules, array $messages = [], array $customAttributes = []) |
|
85 | 72 | { |
|
86 | 72 | $factory = $this->app->make(ValidationFactory::class); |
|
87 | |||
88 | 72 | $data = $this->getValidationData($rules, $customAttributes); |
|
89 | $validator = $factory->make($data, $rules, $messages, $customAttributes); |
||
90 | $validator->addCustomAttributes($customAttributes); |
||
91 | |||
92 | return $validator; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Gets fake data when validator has wildcard rules. |
||
97 | 72 | * |
|
98 | * @param array $rules |
||
99 | * @param array $customAttributes |
||
100 | 48 | * @return array |
|
101 | 72 | */ |
|
102 | protected function getValidationData(array $rules, array $customAttributes = []) |
||
103 | 72 | { |
|
104 | $attributes = array_filter(array_keys($rules), function ($attribute) { |
||
105 | 24 | return $attribute !== '' && mb_strpos($attribute, '*') !== false; |
|
106 | }); |
||
107 | 24 | ||
108 | 72 | $attributes = array_merge(array_keys($customAttributes), $attributes); |
|
109 | $data = array_reduce($attributes, function ($data, $attribute) { |
||
110 | 72 | // Prevent wildcard rule being removed as an implicit attribute (not present in the data). |
|
111 | $attribute = str_replace('*', self::ASTERISK, $attribute); |
||
112 | |||
113 | Arr::set($data, $attribute, true); |
||
114 | |||
115 | return $data; |
||
116 | }, []); |
||
117 | |||
118 | return $data; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | 24 | * Creates JsValidator instance based on FormRequest. |
|
123 | * |
||
124 | 24 | * @param $formRequest |
|
125 | 12 | * @param null|string $selector |
|
126 | * @return \Proengsoft\JsValidation\Javascript\JavascriptValidator |
||
127 | * |
||
128 | 24 | * @throws \Illuminate\Contracts\Container\BindingResolutionException |
|
129 | */ |
||
130 | 24 | public function formRequest($formRequest, $selector = null) |
|
131 | { |
||
132 | 24 | if (! is_object($formRequest)) { |
|
133 | $formRequest = $this->createFormRequest($formRequest); |
||
134 | 24 | } |
|
135 | |||
136 | if ($formRequest instanceof FormRequest) { |
||
137 | return $this->newFormRequestValidator($formRequest, $selector); |
||
138 | 24 | } |
|
139 | |||
140 | return $this->oldFormRequestValidator($formRequest, $selector); |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Create form request validator. |
||
145 | 12 | * |
|
146 | * @param FormRequest $formRequest |
||
147 | 12 | * @param string $selector |
|
148 | 12 | * @return JavascriptValidator |
|
149 | 12 | */ |
|
150 | 12 | private function newFormRequestValidator($formRequest, $selector) |
|
151 | { |
||
152 | // Replace all rules with Noop rules which are checked client-side and always valid to true. |
||
153 | 12 | // This is important because jquery-validation expects fields under validation to have rules present. For |
|
154 | // example, if you mark a field as invalid without a defined rule, then unhighlight won't be called. |
||
155 | $rules = method_exists($formRequest, 'rules') ? $formRequest->rules() : []; |
||
0 ignored issues
–
show
|
|||
156 | foreach ($rules as $key => $value) { |
||
157 | $rules[$key] = 'proengsoft_noop'; |
||
158 | } |
||
159 | |||
160 | // This rule controls AJAX validation of all fields. |
||
161 | $rules['proengsoft_jsvalidation'] = RuleParser::FORM_REQUEST_RULE_NAME; |
||
162 | |||
163 | $baseValidator = $this->getValidatorInstance($rules); |
||
164 | 12 | ||
165 | return $this->validator($baseValidator, $selector); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Create a form request validator instance. |
||
170 | 12 | * |
|
171 | * @param IlluminateFormRequest $formRequest |
||
172 | 12 | * @param string $selector |
|
173 | 12 | * @return JavascriptValidator |
|
174 | */ |
||
175 | 12 | private function oldFormRequestValidator($formRequest, $selector) |
|
176 | 12 | { |
|
177 | $rules = method_exists($formRequest, 'rules') ? $this->app->call([$formRequest, 'rules']) : []; |
||
178 | 12 | ||
179 | 12 | $validator = $this->getValidatorInstance($rules, $formRequest->messages(), $formRequest->attributes()); |
|
180 | 12 | ||
181 | 12 | $jsValidator = $this->validator($validator, $selector); |
|
182 | |||
183 | 12 | if (method_exists($formRequest, 'withJsValidator')) { |
|
184 | $formRequest->withJsValidator($jsValidator); |
||
185 | } |
||
186 | |||
187 | return $jsValidator; |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * @param string|array $class |
||
192 | * @return array |
||
193 | 72 | */ |
|
194 | protected function parseFormRequestName($class) |
||
195 | 72 | { |
|
196 | $params = []; |
||
197 | if (is_array($class)) { |
||
198 | $params = empty($class[1]) ? $params : $class[1]; |
||
199 | $class = $class[0]; |
||
200 | } |
||
201 | |||
202 | return [$class, $params]; |
||
203 | } |
||
204 | |||
205 | 72 | /** |
|
206 | * Creates and initializes an Form Request instance. |
||
207 | 72 | * |
|
208 | 72 | * @param string $class |
|
209 | 72 | * @return IlluminateFormRequest |
|
210 | * |
||
211 | 72 | * @throws \Illuminate\Contracts\Container\BindingResolutionException |
|
212 | 72 | */ |
|
213 | 72 | protected function createFormRequest($class) |
|
214 | { |
||
215 | 72 | /* |
|
216 | * @var $formRequest \Illuminate\Foundation\Http\FormRequest |
||
217 | 72 | * @var $request Request |
|
218 | */ |
||
219 | 72 | [$class, $params] = $this->parseFormRequestName($class); |
|
220 | |||
221 | $request = $this->app->__get('request'); |
||
222 | $formRequest = $this->app->build($class, $params); |
||
223 | |||
224 | if ($session = $request->getSession()) { |
||
225 | $formRequest->setLaravelSession($session); |
||
226 | } |
||
227 | 72 | $formRequest->setUserResolver($request->getUserResolver()); |
|
228 | $formRequest->setRouteResolver($request->getRouteResolver()); |
||
229 | 72 | $formRequest->setContainer($this->app); |
|
230 | 72 | $formRequest->query = $request->query; |
|
231 | 12 | ||
232 | return $formRequest; |
||
233 | } |
||
234 | 72 | ||
235 | 12 | /** |
|
236 | * Creates JsValidator instance based on Validator. |
||
237 | * |
||
238 | 72 | * @param \Illuminate\Validation\Validator $validator |
|
239 | * @param null|string $selector |
||
240 | * @return \Proengsoft\JsValidation\Javascript\JavascriptValidator |
||
241 | */ |
||
242 | public function validator(Validator $validator, $selector = null) |
||
243 | { |
||
244 | return $this->jsValidator($validator, $selector); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Creates JsValidator instance based on Validator. |
||
249 | * |
||
250 | * @param \Illuminate\Validation\Validator $validator |
||
251 | * @param null|string $selector |
||
252 | * @return \Proengsoft\JsValidation\Javascript\JavascriptValidator |
||
253 | */ |
||
254 | protected function jsValidator(Validator $validator, $selector = null) |
||
255 | { |
||
256 | $remote = ! $this->options['disable_remote_validation']; |
||
257 | $view = $this->options['view']; |
||
258 | $selector = is_null($selector) ? $this->options['form_selector'] : $selector; |
||
259 | $ignore = $this->options['ignore']; |
||
260 | |||
261 | $delegated = new DelegatedValidator($validator, new ValidationRuleParserProxy($validator->getData())); |
||
262 | $rules = new RuleParser($delegated, $this->getSessionToken()); |
||
263 | $messages = new MessageParser($delegated, isset($this->options['escape']) ? $this->options['escape'] : false); |
||
264 | |||
265 | $jsValidator = new ValidatorHandler($rules, $messages); |
||
266 | |||
267 | return new JavascriptValidator($jsValidator, compact('view', 'selector', 'remote', 'ignore')); |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Get and encrypt token from session store. |
||
272 | * |
||
273 | * @return null|string |
||
274 | */ |
||
275 | protected function getSessionToken() |
||
276 | { |
||
277 | $token = null; |
||
278 | if ($session = $this->app->__get('session')) { |
||
279 | $token = $session->token(); |
||
280 | } |
||
281 | |||
282 | if ($encrypter = $this->app->__get('encrypter')) { |
||
283 | $token = $encrypter->encrypt($token); |
||
284 | } |
||
285 | |||
286 | return $token; |
||
287 | } |
||
288 | } |
||
289 |
If you implement
__call
and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.This is often the case, when
__call
is implemented by a parent class and only the child class knows which methods exist: