PageRenderTime 31ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Validation/Validator.php

https://gitlab.com/ealexis.t/trends
PHP | 1708 lines | 731 code | 244 blank | 733 comment | 117 complexity | f1a588f3b25a56b1bd985def2aa9b738 MD5 | raw file
  1. <?php
  2. namespace Illuminate\Validation;
  3. use Closure;
  4. use DateTime;
  5. use Countable;
  6. use Exception;
  7. use DateTimeZone;
  8. use Carbon\Carbon;
  9. use RuntimeException;
  10. use Illuminate\Support\Arr;
  11. use Illuminate\Support\Str;
  12. use BadMethodCallException;
  13. use InvalidArgumentException;
  14. use Illuminate\Support\Fluent;
  15. use Illuminate\Support\MessageBag;
  16. use Illuminate\Contracts\Container\Container;
  17. use Symfony\Component\HttpFoundation\File\File;
  18. use Symfony\Component\Translation\TranslatorInterface;
  19. use Symfony\Component\HttpFoundation\File\UploadedFile;
  20. use Illuminate\Contracts\Validation\Validator as ValidatorContract;
  21. class Validator implements ValidatorContract
  22. {
  23. /**
  24. * The Translator implementation.
  25. *
  26. * @var \Symfony\Component\Translation\TranslatorInterface
  27. */
  28. protected $translator;
  29. /**
  30. * The Presence Verifier implementation.
  31. *
  32. * @var \Illuminate\Validation\PresenceVerifierInterface
  33. */
  34. protected $presenceVerifier;
  35. /**
  36. * The container instance.
  37. *
  38. * @var \Illuminate\Contracts\Container\Container
  39. */
  40. protected $container;
  41. /**
  42. * The failed validation rules.
  43. *
  44. * @var array
  45. */
  46. protected $failedRules = [];
  47. /**
  48. * The message bag instance.
  49. *
  50. * @var \Illuminate\Support\MessageBag
  51. */
  52. protected $messages;
  53. /**
  54. * The data under validation.
  55. *
  56. * @var array
  57. */
  58. protected $data;
  59. /**
  60. * The files under validation.
  61. *
  62. * @var array
  63. */
  64. protected $files = [];
  65. /**
  66. * The initial rules provided.
  67. *
  68. * @var array
  69. */
  70. protected $initialRules;
  71. /**
  72. * The rules to be applied to the data.
  73. *
  74. * @var array
  75. */
  76. protected $rules;
  77. /**
  78. * The array of wildcard attributes with their asterisks expanded.
  79. *
  80. * @var array
  81. */
  82. protected $implicitAttributes = [];
  83. /**
  84. * All of the registered "after" callbacks.
  85. *
  86. * @var array
  87. */
  88. protected $after = [];
  89. /**
  90. * The array of custom error messages.
  91. *
  92. * @var array
  93. */
  94. protected $customMessages = [];
  95. /**
  96. * The array of fallback error messages.
  97. *
  98. * @var array
  99. */
  100. protected $fallbackMessages = [];
  101. /**
  102. * The array of custom attribute names.
  103. *
  104. * @var array
  105. */
  106. protected $customAttributes = [];
  107. /**
  108. * The array of custom displayable values.
  109. *
  110. * @var array
  111. */
  112. protected $customValues = [];
  113. /**
  114. * All of the custom validator extensions.
  115. *
  116. * @var array
  117. */
  118. protected $extensions = [];
  119. /**
  120. * All of the custom replacer extensions.
  121. *
  122. * @var array
  123. */
  124. protected $replacers = [];
  125. /**
  126. * The size related validation rules.
  127. *
  128. * @var array
  129. */
  130. protected $sizeRules = ['Size', 'Between', 'Min', 'Max'];
  131. /**
  132. * The numeric related validation rules.
  133. *
  134. * @var array
  135. */
  136. protected $numericRules = ['Numeric', 'Integer'];
  137. /**
  138. * The validation rules that imply the field is required.
  139. *
  140. * @var array
  141. */
  142. protected $implicitRules = [
  143. 'Required', 'Filled', 'RequiredWith', 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll',
  144. 'RequiredIf', 'RequiredUnless', 'Accepted', 'Present',
  145. // 'Array', 'Boolean', 'Integer', 'Numeric', 'String',
  146. ];
  147. /**
  148. * The validation rules which depend on other fields as parameters.
  149. *
  150. * @var array
  151. */
  152. protected $dependentRules = [
  153. 'RequiredWith', 'RequiredWithAll', 'RequiredWithout', 'RequiredWithoutAll',
  154. 'RequiredIf', 'RequiredUnless', 'Confirmed', 'Same', 'Different', 'Unique',
  155. 'Before', 'After',
  156. ];
  157. /**
  158. * Create a new Validator instance.
  159. *
  160. * @param \Symfony\Component\Translation\TranslatorInterface $translator
  161. * @param array $data
  162. * @param array $rules
  163. * @param array $messages
  164. * @param array $customAttributes
  165. * @return void
  166. */
  167. public function __construct(TranslatorInterface $translator, array $data, array $rules, array $messages = [], array $customAttributes = [])
  168. {
  169. $this->translator = $translator;
  170. $this->customMessages = $messages;
  171. $this->data = $this->parseData($data);
  172. $this->customAttributes = $customAttributes;
  173. $this->initialRules = $rules;
  174. $this->setRules($rules);
  175. }
  176. /**
  177. * Parse the data and hydrate the files array.
  178. *
  179. * @param array $data
  180. * @param string $arrayKey
  181. * @return array
  182. */
  183. protected function parseData(array $data, $arrayKey = null)
  184. {
  185. if (is_null($arrayKey)) {
  186. $this->files = [];
  187. }
  188. foreach ($data as $key => $value) {
  189. $key = ($arrayKey) ? "$arrayKey.$key" : $key;
  190. // If this value is an instance of the HttpFoundation File class we will
  191. // remove it from the data array and add it to the files array, which
  192. // we use to conveniently separate out these files from other data.
  193. if ($value instanceof File) {
  194. $this->files[$key] = $value;
  195. unset($data[$key]);
  196. } elseif (is_array($value)) {
  197. $this->parseData($value, $key);
  198. }
  199. }
  200. return $data;
  201. }
  202. /**
  203. * Explode the rules into an array of rules.
  204. *
  205. * @param string|array $rules
  206. * @return array
  207. */
  208. protected function explodeRules($rules)
  209. {
  210. foreach ($rules as $key => $rule) {
  211. if (Str::contains($key, '*')) {
  212. $this->each($key, [$rule]);
  213. unset($rules[$key]);
  214. } else {
  215. $rules[$key] = (is_string($rule)) ? explode('|', $rule) : $rule;
  216. }
  217. }
  218. return $rules;
  219. }
  220. /**
  221. * After an after validation callback.
  222. *
  223. * @param callable|string $callback
  224. * @return $this
  225. */
  226. public function after($callback)
  227. {
  228. $this->after[] = function () use ($callback) {
  229. return call_user_func_array($callback, [$this]);
  230. };
  231. return $this;
  232. }
  233. /**
  234. * Add conditions to a given field based on a Closure.
  235. *
  236. * @param string $attribute
  237. * @param string|array $rules
  238. * @param callable $callback
  239. * @return void
  240. */
  241. public function sometimes($attribute, $rules, callable $callback)
  242. {
  243. $payload = new Fluent($this->attributes());
  244. if (call_user_func($callback, $payload)) {
  245. foreach ((array) $attribute as $key) {
  246. if (Str::contains($key, '*')) {
  247. $this->explodeRules([$key => $rules]);
  248. } else {
  249. $this->mergeRules($key, $rules);
  250. }
  251. }
  252. }
  253. }
  254. /**
  255. * Define a set of rules that apply to each element in an array attribute.
  256. *
  257. * @param string $attribute
  258. * @param string|array $rules
  259. * @return void
  260. *
  261. * @throws \InvalidArgumentException
  262. */
  263. public function each($attribute, $rules)
  264. {
  265. $data = Arr::dot($this->initializeAttributeOnData($attribute));
  266. $pattern = str_replace('\*', '[^\.]+', preg_quote($attribute));
  267. $data = array_merge($data, $this->extractValuesForWildcards(
  268. $data, $attribute
  269. ));
  270. foreach ($data as $key => $value) {
  271. if (Str::startsWith($key, $attribute) || (bool) preg_match('/^'.$pattern.'\z/', $key)) {
  272. foreach ((array) $rules as $ruleKey => $ruleValue) {
  273. if (! is_string($ruleKey) || Str::endsWith($key, $ruleKey)) {
  274. $this->implicitAttributes[$attribute][] = $key;
  275. $this->mergeRules($key, $ruleValue);
  276. }
  277. }
  278. }
  279. }
  280. }
  281. /**
  282. * Gather a copy of the attribute data filled with any missing attributes.
  283. *
  284. * @param string $attribute
  285. * @return array
  286. */
  287. protected function initializeAttributeOnData($attribute)
  288. {
  289. $explicitPath = $this->getLeadingExplicitAttributePath($attribute);
  290. $data = $this->extractDataFromPath($explicitPath);
  291. if (! Str::contains($attribute, '*') || Str::endsWith($attribute, '*')) {
  292. return $data;
  293. }
  294. return data_set($data, $attribute, null, true);
  295. }
  296. /**
  297. * Get all of the exact attribute values for a given wildcard attribute.
  298. *
  299. * @param array $data
  300. * @param string $attribute
  301. * @return array
  302. */
  303. public function extractValuesForWildcards($data, $attribute)
  304. {
  305. $keys = [];
  306. $pattern = str_replace('\*', '[^\.]+', preg_quote($attribute));
  307. foreach ($data as $key => $value) {
  308. if ((bool) preg_match('/^'.$pattern.'/', $key, $matches)) {
  309. $keys[] = $matches[0];
  310. }
  311. }
  312. $keys = array_unique($keys);
  313. $data = [];
  314. foreach ($keys as $key) {
  315. $data[$key] = array_get($this->data, $key);
  316. }
  317. return $data;
  318. }
  319. /**
  320. * Merge additional rules into a given attribute(s).
  321. *
  322. * @param string $attribute
  323. * @param string|array $rules
  324. * @return $this
  325. */
  326. public function mergeRules($attribute, $rules = [])
  327. {
  328. if (is_array($attribute)) {
  329. foreach ($attribute as $innerAttribute => $innerRules) {
  330. $this->mergeRulesForAttribute($innerAttribute, $innerRules);
  331. }
  332. return $this;
  333. }
  334. return $this->mergeRulesForAttribute($attribute, $rules);
  335. }
  336. /**
  337. * Merge additional rules into a given attribute.
  338. *
  339. * @param string $attribute
  340. * @param string|array $rules
  341. * @return $this
  342. */
  343. protected function mergeRulesForAttribute($attribute, $rules)
  344. {
  345. $current = isset($this->rules[$attribute]) ? $this->rules[$attribute] : [];
  346. $merge = head($this->explodeRules([$rules]));
  347. $this->rules[$attribute] = array_merge($current, $merge);
  348. return $this;
  349. }
  350. /**
  351. * Determine if the data passes the validation rules.
  352. *
  353. * @return bool
  354. */
  355. public function passes()
  356. {
  357. $this->messages = new MessageBag;
  358. // We'll spin through each rule, validating the attributes attached to that
  359. // rule. Any error messages will be added to the containers with each of
  360. // the other error messages, returning true if we don't have messages.
  361. foreach ($this->rules as $attribute => $rules) {
  362. foreach ($rules as $rule) {
  363. $this->validate($attribute, $rule);
  364. if ($this->shouldStopValidating($attribute)) {
  365. break;
  366. }
  367. }
  368. }
  369. // Here we will spin through all of the "after" hooks on this validator and
  370. // fire them off. This gives the callbacks a chance to perform all kinds
  371. // of other validation that needs to get wrapped up in this operation.
  372. foreach ($this->after as $after) {
  373. call_user_func($after);
  374. }
  375. return $this->messages->isEmpty();
  376. }
  377. /**
  378. * Determine if the data fails the validation rules.
  379. *
  380. * @return bool
  381. */
  382. public function fails()
  383. {
  384. return ! $this->passes();
  385. }
  386. /**
  387. * Validate a given attribute against a rule.
  388. *
  389. * @param string $attribute
  390. * @param string $rule
  391. * @return void
  392. */
  393. protected function validate($attribute, $rule)
  394. {
  395. list($rule, $parameters) = $this->parseRule($rule);
  396. if ($rule == '') {
  397. return;
  398. }
  399. // First we will get the correct keys for the given attribute in case the field is nested in
  400. // an array. Then we determine if the given rule accepts other field names as parameters.
  401. // If so, we will replace any asterisks found in the parameters with the correct keys.
  402. if (($keys = $this->getExplicitKeys($attribute)) &&
  403. $this->dependsOnOtherFields($rule)) {
  404. $parameters = $this->replaceAsterisksInParameters($parameters, $keys);
  405. }
  406. // We will get the value for the given attribute from the array of data and then
  407. // verify that the attribute is indeed validatable. Unless the rule implies
  408. // that the attribute is required, rules are not run for missing values.
  409. $value = $this->getValue($attribute);
  410. $validatable = $this->isValidatable($rule, $attribute, $value);
  411. $method = "validate{$rule}";
  412. if ($validatable && ! $this->$method($attribute, $value, $parameters, $this)) {
  413. $this->addFailure($attribute, $rule, $parameters);
  414. }
  415. }
  416. /**
  417. * Returns the data which was valid.
  418. *
  419. * @return array
  420. */
  421. public function valid()
  422. {
  423. if (! $this->messages) {
  424. $this->passes();
  425. }
  426. return array_diff_key($this->data, $this->messages()->toArray());
  427. }
  428. /**
  429. * Returns the data which was invalid.
  430. *
  431. * @return array
  432. */
  433. public function invalid()
  434. {
  435. if (! $this->messages) {
  436. $this->passes();
  437. }
  438. return array_intersect_key($this->data, $this->messages()->toArray());
  439. }
  440. /**
  441. * Get the value of a given attribute.
  442. *
  443. * @param string $attribute
  444. * @return mixed
  445. */
  446. protected function getValue($attribute)
  447. {
  448. if (! is_null($value = Arr::get($this->data, $attribute))) {
  449. return $value;
  450. } elseif (! is_null($value = Arr::get($this->files, $attribute))) {
  451. return $value;
  452. }
  453. }
  454. /**
  455. * Determine if the attribute is validatable.
  456. *
  457. * @param string $rule
  458. * @param string $attribute
  459. * @param mixed $value
  460. * @return bool
  461. */
  462. protected function isValidatable($rule, $attribute, $value)
  463. {
  464. return $this->presentOrRuleIsImplicit($rule, $attribute, $value) &&
  465. $this->passesOptionalCheck($attribute) &&
  466. $this->hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute);
  467. }
  468. /**
  469. * Determine if the field is present, or the rule implies required.
  470. *
  471. * @param string $rule
  472. * @param string $attribute
  473. * @param mixed $value
  474. * @return bool
  475. */
  476. protected function presentOrRuleIsImplicit($rule, $attribute, $value)
  477. {
  478. return $this->validateRequired($attribute, $value) || $this->isImplicit($rule);
  479. }
  480. /**
  481. * Determine if the attribute passes any optional check.
  482. *
  483. * @param string $attribute
  484. * @return bool
  485. */
  486. protected function passesOptionalCheck($attribute)
  487. {
  488. if ($this->hasRule($attribute, ['Sometimes'])) {
  489. return array_key_exists($attribute, Arr::dot($this->data))
  490. || in_array($attribute, array_keys($this->data))
  491. || array_key_exists($attribute, $this->files);
  492. }
  493. return true;
  494. }
  495. /**
  496. * Determine if a given rule implies the attribute is required.
  497. *
  498. * @param string $rule
  499. * @return bool
  500. */
  501. protected function isImplicit($rule)
  502. {
  503. return in_array($rule, $this->implicitRules);
  504. }
  505. /**
  506. * Determine if it's a necessary presence validation.
  507. *
  508. * This is to avoid possible database type comparison errors.
  509. *
  510. * @param string $rule
  511. * @param string $attribute
  512. * @return bool
  513. */
  514. protected function hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute)
  515. {
  516. return in_array($rule, ['Unique', 'Exists'])
  517. ? ! $this->messages->has($attribute) : true;
  518. }
  519. /**
  520. * Add a failed rule and error message to the collection.
  521. *
  522. * @param string $attribute
  523. * @param string $rule
  524. * @param array $parameters
  525. * @return void
  526. */
  527. protected function addFailure($attribute, $rule, $parameters)
  528. {
  529. $this->addError($attribute, $rule, $parameters);
  530. $this->failedRules[$attribute][$rule] = $parameters;
  531. }
  532. /**
  533. * Add an error message to the validator's collection of messages.
  534. *
  535. * @param string $attribute
  536. * @param string $rule
  537. * @param array $parameters
  538. * @return void
  539. */
  540. protected function addError($attribute, $rule, $parameters)
  541. {
  542. $message = $this->getMessage($attribute, $rule);
  543. $message = $this->doReplacements($message, $attribute, $rule, $parameters);
  544. $this->messages->add($attribute, $message);
  545. }
  546. /**
  547. * "Validate" optional attributes.
  548. *
  549. * Always returns true, just lets us put sometimes in rules.
  550. *
  551. * @return bool
  552. */
  553. protected function validateSometimes()
  554. {
  555. return true;
  556. }
  557. /**
  558. * "Break" on first validation fail.
  559. *
  560. * Always returns true, just lets us put "bail" in rules.
  561. *
  562. * @return bool
  563. */
  564. protected function validateBail()
  565. {
  566. return true;
  567. }
  568. /**
  569. * Stop on error if "bail" rule is assigned and attribute has a message.
  570. *
  571. * @param string $attribute
  572. * @return bool
  573. */
  574. protected function shouldStopValidating($attribute)
  575. {
  576. if (! $this->hasRule($attribute, ['Bail'])) {
  577. return false;
  578. }
  579. return $this->messages->has($attribute);
  580. }
  581. /**
  582. * Validate that a required attribute exists.
  583. *
  584. * @param string $attribute
  585. * @param mixed $value
  586. * @return bool
  587. */
  588. protected function validateRequired($attribute, $value)
  589. {
  590. if (is_null($value)) {
  591. return false;
  592. } elseif (is_string($value) && trim($value) === '') {
  593. return false;
  594. } elseif ((is_array($value) || $value instanceof Countable) && count($value) < 1) {
  595. return false;
  596. } elseif ($value instanceof File) {
  597. return (string) $value->getPath() != '';
  598. }
  599. return true;
  600. }
  601. /**
  602. * Validate that an attribute exists even if not filled.
  603. *
  604. * @param string $attribute
  605. * @param mixed $value
  606. * @return bool
  607. */
  608. protected function validatePresent($attribute, $value)
  609. {
  610. return Arr::has($this->data, $attribute);
  611. }
  612. /**
  613. * Validate the given attribute is filled if it is present.
  614. *
  615. * @param string $attribute
  616. * @param mixed $value
  617. * @return bool
  618. */
  619. protected function validateFilled($attribute, $value)
  620. {
  621. if (Arr::has(array_merge($this->data, $this->files), $attribute)) {
  622. return $this->validateRequired($attribute, $value);
  623. }
  624. return true;
  625. }
  626. /**
  627. * Determine if any of the given attributes fail the required test.
  628. *
  629. * @param array $attributes
  630. * @return bool
  631. */
  632. protected function anyFailingRequired(array $attributes)
  633. {
  634. foreach ($attributes as $key) {
  635. if (! $this->validateRequired($key, $this->getValue($key))) {
  636. return true;
  637. }
  638. }
  639. return false;
  640. }
  641. /**
  642. * Determine if all of the given attributes fail the required test.
  643. *
  644. * @param array $attributes
  645. * @return bool
  646. */
  647. protected function allFailingRequired(array $attributes)
  648. {
  649. foreach ($attributes as $key) {
  650. if ($this->validateRequired($key, $this->getValue($key))) {
  651. return false;
  652. }
  653. }
  654. return true;
  655. }
  656. /**
  657. * Validate that an attribute exists when any other attribute exists.
  658. *
  659. * @param string $attribute
  660. * @param mixed $value
  661. * @param mixed $parameters
  662. * @return bool
  663. */
  664. protected function validateRequiredWith($attribute, $value, $parameters)
  665. {
  666. if (! $this->allFailingRequired($parameters)) {
  667. return $this->validateRequired($attribute, $value);
  668. }
  669. return true;
  670. }
  671. /**
  672. * Validate that an attribute exists when all other attributes exists.
  673. *
  674. * @param string $attribute
  675. * @param mixed $value
  676. * @param mixed $parameters
  677. * @return bool
  678. */
  679. protected function validateRequiredWithAll($attribute, $value, $parameters)
  680. {
  681. if (! $this->anyFailingRequired($parameters)) {
  682. return $this->validateRequired($attribute, $value);
  683. }
  684. return true;
  685. }
  686. /**
  687. * Validate that an attribute exists when another attribute does not.
  688. *
  689. * @param string $attribute
  690. * @param mixed $value
  691. * @param mixed $parameters
  692. * @return bool
  693. */
  694. protected function validateRequiredWithout($attribute, $value, $parameters)
  695. {
  696. if ($this->anyFailingRequired($parameters)) {
  697. return $this->validateRequired($attribute, $value);
  698. }
  699. return true;
  700. }
  701. /**
  702. * Validate that an attribute exists when all other attributes do not.
  703. *
  704. * @param string $attribute
  705. * @param mixed $value
  706. * @param mixed $parameters
  707. * @return bool
  708. */
  709. protected function validateRequiredWithoutAll($attribute, $value, $parameters)
  710. {
  711. if ($this->allFailingRequired($parameters)) {
  712. return $this->validateRequired($attribute, $value);
  713. }
  714. return true;
  715. }
  716. /**
  717. * Validate that an attribute exists when another attribute has a given value.
  718. *
  719. * @param string $attribute
  720. * @param mixed $value
  721. * @param mixed $parameters
  722. * @return bool
  723. */
  724. protected function validateRequiredIf($attribute, $value, $parameters)
  725. {
  726. $this->requireParameterCount(2, $parameters, 'required_if');
  727. $data = Arr::get($this->data, $parameters[0]);
  728. $values = array_slice($parameters, 1);
  729. if (is_bool($data)) {
  730. array_walk($values, function (&$value) {
  731. if ($value === 'true') {
  732. $value = true;
  733. } elseif ($value === 'false') {
  734. $value = false;
  735. }
  736. });
  737. }
  738. if (in_array($data, $values)) {
  739. return $this->validateRequired($attribute, $value);
  740. }
  741. return true;
  742. }
  743. /**
  744. * Validate that an attribute exists when another attribute does not have a given value.
  745. *
  746. * @param string $attribute
  747. * @param mixed $value
  748. * @param mixed $parameters
  749. * @return bool
  750. */
  751. protected function validateRequiredUnless($attribute, $value, $parameters)
  752. {
  753. $this->requireParameterCount(2, $parameters, 'required_unless');
  754. $data = Arr::get($this->data, $parameters[0]);
  755. $values = array_slice($parameters, 1);
  756. if (! in_array($data, $values)) {
  757. return $this->validateRequired($attribute, $value);
  758. }
  759. return true;
  760. }
  761. /**
  762. * Get the number of attributes in a list that are present.
  763. *
  764. * @param array $attributes
  765. * @return int
  766. */
  767. protected function getPresentCount($attributes)
  768. {
  769. $count = 0;
  770. foreach ($attributes as $key) {
  771. if (Arr::get($this->data, $key) || Arr::get($this->files, $key)) {
  772. $count++;
  773. }
  774. }
  775. return $count;
  776. }
  777. /**
  778. * Validate that the values of an attribute is in another attribute.
  779. *
  780. * @param string $attribute
  781. * @param mixed $value
  782. * @param array $parameters
  783. * @return bool
  784. */
  785. protected function validateInArray($attribute, $value, $parameters)
  786. {
  787. $this->requireParameterCount(1, $parameters, 'in_array');
  788. $explicitPath = $this->getLeadingExplicitAttributePath($parameters[0]);
  789. $attributeData = $this->extractDataFromPath($explicitPath);
  790. $otherValues = Arr::where(Arr::dot($attributeData), function ($key) use ($parameters) {
  791. return Str::is($parameters[0], $key);
  792. });
  793. return in_array($value, $otherValues);
  794. }
  795. /**
  796. * Validate that an attribute has a matching confirmation.
  797. *
  798. * @param string $attribute
  799. * @param mixed $value
  800. * @return bool
  801. */
  802. protected function validateConfirmed($attribute, $value)
  803. {
  804. return $this->validateSame($attribute, $value, [$attribute.'_confirmation']);
  805. }
  806. /**
  807. * Validate that two attributes match.
  808. *
  809. * @param string $attribute
  810. * @param mixed $value
  811. * @param array $parameters
  812. * @return bool
  813. */
  814. protected function validateSame($attribute, $value, $parameters)
  815. {
  816. $this->requireParameterCount(1, $parameters, 'same');
  817. $other = Arr::get($this->data, $parameters[0]);
  818. return isset($other) && $value === $other;
  819. }
  820. /**
  821. * Validate that an attribute is different from another attribute.
  822. *
  823. * @param string $attribute
  824. * @param mixed $value
  825. * @param array $parameters
  826. * @return bool
  827. */
  828. protected function validateDifferent($attribute, $value, $parameters)
  829. {
  830. $this->requireParameterCount(1, $parameters, 'different');
  831. $other = Arr::get($this->data, $parameters[0]);
  832. return isset($other) && $value !== $other;
  833. }
  834. /**
  835. * Validate that an attribute was "accepted".
  836. *
  837. * This validation rule implies the attribute is "required".
  838. *
  839. * @param string $attribute
  840. * @param mixed $value
  841. * @return bool
  842. */
  843. protected function validateAccepted($attribute, $value)
  844. {
  845. $acceptable = ['yes', 'on', '1', 1, true, 'true'];
  846. return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true);
  847. }
  848. /**
  849. * Validate that an attribute is an array.
  850. *
  851. * @param string $attribute
  852. * @param mixed $value
  853. * @return bool
  854. */
  855. protected function validateArray($attribute, $value)
  856. {
  857. if (! $this->hasAttribute($attribute)) {
  858. return true;
  859. }
  860. return is_null($value) || is_array($value);
  861. }
  862. /**
  863. * Validate that an attribute is a boolean.
  864. *
  865. * @param string $attribute
  866. * @param mixed $value
  867. * @return bool
  868. */
  869. protected function validateBoolean($attribute, $value)
  870. {
  871. if (! $this->hasAttribute($attribute)) {
  872. return true;
  873. }
  874. $acceptable = [true, false, 0, 1, '0', '1'];
  875. return is_null($value) || in_array($value, $acceptable, true);
  876. }
  877. /**
  878. * Validate that an attribute is an integer.
  879. *
  880. * @param string $attribute
  881. * @param mixed $value
  882. * @return bool
  883. */
  884. protected function validateInteger($attribute, $value)
  885. {
  886. if (! $this->hasAttribute($attribute)) {
  887. return true;
  888. }
  889. return is_null($value) || filter_var($value, FILTER_VALIDATE_INT) !== false;
  890. }
  891. /**
  892. * Validate that an attribute is numeric.
  893. *
  894. * @param string $attribute
  895. * @param mixed $value
  896. * @return bool
  897. */
  898. protected function validateNumeric($attribute, $value)
  899. {
  900. if (! $this->hasAttribute($attribute)) {
  901. return true;
  902. }
  903. return is_null($value) || is_numeric($value);
  904. }
  905. /**
  906. * Validate that an attribute is a string.
  907. *
  908. * @param string $attribute
  909. * @param mixed $value
  910. * @return bool
  911. */
  912. protected function validateString($attribute, $value)
  913. {
  914. if (! $this->hasAttribute($attribute)) {
  915. return true;
  916. }
  917. return is_null($value) || is_string($value);
  918. }
  919. /**
  920. * Validate the attribute is a valid JSON string.
  921. *
  922. * @param string $attribute
  923. * @param mixed $value
  924. * @return bool
  925. */
  926. protected function validateJson($attribute, $value)
  927. {
  928. if (! is_scalar($value) && ! method_exists($value, '__toString')) {
  929. return false;
  930. }
  931. json_decode($value);
  932. return json_last_error() === JSON_ERROR_NONE;
  933. }
  934. /**
  935. * Validate that an attribute has a given number of digits.
  936. *
  937. * @param string $attribute
  938. * @param mixed $value
  939. * @param array $parameters
  940. * @return bool
  941. */
  942. protected function validateDigits($attribute, $value, $parameters)
  943. {
  944. $this->requireParameterCount(1, $parameters, 'digits');
  945. return $this->validateNumeric($attribute, $value)
  946. && strlen((string) $value) == $parameters[0];
  947. }
  948. /**
  949. * Validate that an attribute is between a given number of digits.
  950. *
  951. * @param string $attribute
  952. * @param mixed $value
  953. * @param array $parameters
  954. * @return bool
  955. */
  956. protected function validateDigitsBetween($attribute, $value, $parameters)
  957. {
  958. $this->requireParameterCount(2, $parameters, 'digits_between');
  959. $length = strlen((string) $value);
  960. return $this->validateNumeric($attribute, $value)
  961. && $length >= $parameters[0] && $length <= $parameters[1];
  962. }
  963. /**
  964. * Validate the size of an attribute.
  965. *
  966. * @param string $attribute
  967. * @param mixed $value
  968. * @param array $parameters
  969. * @return bool
  970. */
  971. protected function validateSize($attribute, $value, $parameters)
  972. {
  973. $this->requireParameterCount(1, $parameters, 'size');
  974. return $this->getSize($attribute, $value) == $parameters[0];
  975. }
  976. /**
  977. * Validate the size of an attribute is between a set of values.
  978. *
  979. * @param string $attribute
  980. * @param mixed $value
  981. * @param array $parameters
  982. * @return bool
  983. */
  984. protected function validateBetween($attribute, $value, $parameters)
  985. {
  986. $this->requireParameterCount(2, $parameters, 'between');
  987. $size = $this->getSize($attribute, $value);
  988. return $size >= $parameters[0] && $size <= $parameters[1];
  989. }
  990. /**
  991. * Validate the size of an attribute is greater than a minimum value.
  992. *
  993. * @param string $attribute
  994. * @param mixed $value
  995. * @param array $parameters
  996. * @return bool
  997. */
  998. protected function validateMin($attribute, $value, $parameters)
  999. {
  1000. $this->requireParameterCount(1, $parameters, 'min');
  1001. return $this->getSize($attribute, $value) >= $parameters[0];
  1002. }
  1003. /**
  1004. * Validate the size of an attribute is less than a maximum value.
  1005. *
  1006. * @param string $attribute
  1007. * @param mixed $value
  1008. * @param array $parameters
  1009. * @return bool
  1010. */
  1011. protected function validateMax($attribute, $value, $parameters)
  1012. {
  1013. $this->requireParameterCount(1, $parameters, 'max');
  1014. if ($value instanceof UploadedFile && ! $value->isValid()) {
  1015. return false;
  1016. }
  1017. return $this->getSize($attribute, $value) <= $parameters[0];
  1018. }
  1019. /**
  1020. * Get the size of an attribute.
  1021. *
  1022. * @param string $attribute
  1023. * @param mixed $value
  1024. * @return mixed
  1025. */
  1026. protected function getSize($attribute, $value)
  1027. {
  1028. $hasNumeric = $this->hasRule($attribute, $this->numericRules);
  1029. // This method will determine if the attribute is a number, string, or file and
  1030. // return the proper size accordingly. If it is a number, then number itself
  1031. // is the size. If it is a file, we take kilobytes, and for a string the
  1032. // entire length of the string will be considered the attribute size.
  1033. if (is_numeric($value) && $hasNumeric) {
  1034. return $value;
  1035. } elseif (is_array($value)) {
  1036. return count($value);
  1037. } elseif ($value instanceof File) {
  1038. return $value->getSize() / 1024;
  1039. }
  1040. return mb_strlen($value);
  1041. }
  1042. /**
  1043. * Validate an attribute is contained within a list of values.
  1044. *
  1045. * @param string $attribute
  1046. * @param mixed $value
  1047. * @param array $parameters
  1048. * @return bool
  1049. */
  1050. protected function validateIn($attribute, $value, $parameters)
  1051. {
  1052. if (is_array($value) && $this->hasRule($attribute, 'Array')) {
  1053. return count(array_diff($value, $parameters)) == 0;
  1054. }
  1055. return ! is_array($value) && in_array((string) $value, $parameters);
  1056. }
  1057. /**
  1058. * Validate an attribute is not contained within a list of values.
  1059. *
  1060. * @param string $attribute
  1061. * @param mixed $value
  1062. * @param array $parameters
  1063. * @return bool
  1064. */
  1065. protected function validateNotIn($attribute, $value, $parameters)
  1066. {
  1067. return ! $this->validateIn($attribute, $value, $parameters);
  1068. }
  1069. /**
  1070. * Validate an attribute is unique among other values.
  1071. *
  1072. * @param string $attribute
  1073. * @param mixed $value
  1074. * @param array $parameters
  1075. * @return bool
  1076. */
  1077. protected function validateDistinct($attribute, $value, $parameters)
  1078. {
  1079. $attributeName = $this->getPrimaryAttribute($attribute);
  1080. $explicitPath = $this->getLeadingExplicitAttributePath($attributeName);
  1081. $attributeData = $this->extractDataFromPath($explicitPath);
  1082. $data = Arr::where(Arr::dot($attributeData), function ($key) use ($attribute, $attributeName) {
  1083. return $key != $attribute && Str::is($attributeName, $key);
  1084. });
  1085. return ! in_array($value, array_values($data));
  1086. }
  1087. /**
  1088. * Validate the uniqueness of an attribute value on a given database table.
  1089. *
  1090. * If a database column is not specified, the attribute will be used.
  1091. *
  1092. * @param string $attribute
  1093. * @param mixed $value
  1094. * @param array $parameters
  1095. * @return bool
  1096. */
  1097. protected function validateUnique($attribute, $value, $parameters)
  1098. {
  1099. $this->requireParameterCount(1, $parameters, 'unique');
  1100. list($connection, $table) = $this->parseTable($parameters[0]);
  1101. // The second parameter position holds the name of the column that needs to
  1102. // be verified as unique. If this parameter isn't specified we will just
  1103. // assume that this column to be verified shares the attribute's name.
  1104. $column = isset($parameters[1])
  1105. ? $parameters[1] : $this->guessColumnForQuery($attribute);
  1106. list($idColumn, $id) = [null, null];
  1107. if (isset($parameters[2])) {
  1108. list($idColumn, $id) = $this->getUniqueIds($parameters);
  1109. if (preg_match('/\[(.*)\]/', $id, $matches)) {
  1110. $id = $this->getValue($matches[1]);
  1111. }
  1112. if (strtolower($id) == 'null') {
  1113. $id = null;
  1114. }
  1115. }
  1116. // The presence verifier is responsible for counting rows within this store
  1117. // mechanism which might be a relational database or any other permanent
  1118. // data store like Redis, etc. We will use it to determine uniqueness.
  1119. $verifier = $this->getPresenceVerifier();
  1120. $verifier->setConnection($connection);
  1121. $extra = $this->getUniqueExtra($parameters);
  1122. return $verifier->getCount(
  1123. $table, $column, $value, $id, $idColumn, $extra
  1124. ) == 0;
  1125. }
  1126. /**
  1127. * Parse the connection / table for the unique / exists rules.
  1128. *
  1129. * @param string $table
  1130. * @return array
  1131. */
  1132. protected function parseTable($table)
  1133. {
  1134. return Str::contains($table, '.') ? explode('.', $table, 2) : [null, $table];
  1135. }
  1136. /**
  1137. * Get the excluded ID column and value for the unique rule.
  1138. *
  1139. * @param array $parameters
  1140. * @return array
  1141. */
  1142. protected function getUniqueIds($parameters)
  1143. {
  1144. $idColumn = isset($parameters[3]) ? $parameters[3] : 'id';
  1145. return [$idColumn, $parameters[2]];
  1146. }
  1147. /**
  1148. * Get the extra conditions for a unique rule.
  1149. *
  1150. * @param array $parameters
  1151. * @return array
  1152. */
  1153. protected function getUniqueExtra($parameters)
  1154. {
  1155. if (isset($parameters[4])) {
  1156. return $this->getExtraConditions(array_slice($parameters, 4));
  1157. }
  1158. return [];
  1159. }
  1160. /**
  1161. * Validate the existence of an attribute value in a database table.
  1162. *
  1163. * @param string $attribute
  1164. * @param mixed $value
  1165. * @param array $parameters
  1166. * @return bool
  1167. */
  1168. protected function validateExists($attribute, $value, $parameters)
  1169. {
  1170. $this->requireParameterCount(1, $parameters, 'exists');
  1171. list($connection, $table) = $this->parseTable($parameters[0]);
  1172. // The second parameter position holds the name of the column that should be
  1173. // verified as existing. If this parameter is not specified we will guess
  1174. // that the columns being "verified" shares the given attribute's name.
  1175. $column = isset($parameters[1])
  1176. ? $parameters[1] : $this->guessColumnForQuery($attribute);
  1177. $expected = (is_array($value)) ? count($value) : 1;
  1178. return $this->getExistCount(
  1179. $connection, $table, $column, $value, $parameters
  1180. ) >= $expected;
  1181. }
  1182. /**
  1183. * Get the number of records that exist in storage.
  1184. *
  1185. * @param mixed $connection
  1186. * @param string $table
  1187. * @param string $column
  1188. * @param mixed $value
  1189. * @param array $parameters
  1190. * @return int
  1191. */
  1192. protected function getExistCount($connection, $table, $column, $value, $parameters)
  1193. {
  1194. $verifier = $this->getPresenceVerifier();
  1195. $verifier->setConnection($connection);
  1196. $extra = $this->getExtraExistConditions($parameters);
  1197. if (is_array($value)) {
  1198. return $verifier->getMultiCount($table, $column, $value, $extra);
  1199. }
  1200. return $verifier->getCount($table, $column, $value, null, null, $extra);
  1201. }
  1202. /**
  1203. * Get the extra exist conditions.
  1204. *
  1205. * @param array $parameters
  1206. * @return array
  1207. */
  1208. protected function getExtraExistConditions(array $parameters)
  1209. {
  1210. return $this->getExtraConditions(array_values(array_slice($parameters, 2)));
  1211. }
  1212. /**
  1213. * Get the extra conditions for a unique / exists rule.
  1214. *
  1215. * @param array $segments
  1216. * @return array
  1217. */
  1218. protected function getExtraConditions(array $segments)
  1219. {
  1220. $extra = [];
  1221. $count = count($segments);
  1222. for ($i = 0; $i < $count; $i = $i + 2) {
  1223. $extra[$segments[$i]] = $segments[$i + 1];
  1224. }
  1225. return $extra;
  1226. }
  1227. /**
  1228. * Guess the database column from the given attribute name.
  1229. *
  1230. * @param string $attribute
  1231. * @return string
  1232. */
  1233. public function guessColumnForQuery($attribute)
  1234. {
  1235. if (in_array($attribute, array_collapse($this->implicitAttributes))
  1236. && ! is_numeric($last = last(explode('.', $attribute)))) {
  1237. return $last;
  1238. }
  1239. return $attribute;
  1240. }
  1241. /**
  1242. * Validate that an attribute is a valid IP.
  1243. *
  1244. * @param string $attribute
  1245. * @param mixed $value
  1246. * @return bool
  1247. */
  1248. protected function validateIp($attribute, $value)
  1249. {
  1250. return filter_var($value, FILTER_VALIDATE_IP) !== false;
  1251. }
  1252. /**
  1253. * Validate that an attribute is a valid e-mail address.
  1254. *
  1255. * @param string $attribute
  1256. * @param mixed $value
  1257. * @return bool
  1258. */
  1259. protected function validateEmail($attribute, $value)
  1260. {
  1261. return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
  1262. }
  1263. /**
  1264. * Validate that an attribute is a valid URL.
  1265. *
  1266. * @param string $attribute
  1267. * @param mixed $value
  1268. * @return bool
  1269. */
  1270. protected function validateUrl($attribute, $value)
  1271. {
  1272. /*
  1273. * This pattern is derived from Symfony\Component\Validator\Constraints\UrlValidator (2.7.4).
  1274. *
  1275. * (c) Fabien Potencier <fabien@symfony.com> http://symfony.com
  1276. */
  1277. $pattern = '~^
  1278. ((aaa|aaas|about|acap|acct|acr|adiumxtra|afp|afs|aim|apt|attachment|aw|barion|beshare|bitcoin|blob|bolo|callto|cap|chrome|chrome-extension|cid|coap|coaps|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-playcontainer|dlna-playsingle|dns|dntp|dtn|dvb|ed2k|example|facetime|fax|feed|feedready|file|filesystem|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|ham|hcp|http|https|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris.beep|iris.lwz|iris.xpc|iris.xpcs|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|ms-help|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|msnim|msrp|msrps|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|oid|opaquelocktoken|pack|palm|paparazzi|pkcs11|platform|pop|pres|prospero|proxy|psyc|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|secondlife|service|session|sftp|sgn|shttp|sieve|sip|sips|skype|smb|sms|smtp|snews|snmp|soap.beep|soap.beeps|soldat|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|things|thismessage|tip|tn3270|turn|turns|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|videotex|view-source|wais|webcal|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s)):// # protocol
  1279. (([\pL\pN-]+:)?([\pL\pN-]+)@)? # basic auth
  1280. (
  1281. ([\pL\pN\pS-\.])+(\.?([\pL]|xn\-\-[\pL\pN-]+)+\.?) # a domain name
  1282. | # or
  1283. \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # a IP address
  1284. | # or
  1285. \[
  1286. (?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::))))
  1287. \] # a IPv6 address
  1288. )
  1289. (:[0-9]+)? # a port (optional)
  1290. (/?|/\S+) # a /, nothing or a / with something
  1291. $~ixu';
  1292. return preg_match($pattern, $value) === 1;
  1293. }
  1294. /**
  1295. * Validate that an attribute is an active URL.
  1296. *
  1297. * @param string $attribute
  1298. * @param mixed $value
  1299. * @return bool
  1300. */
  1301. protected function validateActiveUrl($attribute, $value)
  1302. {
  1303. if (! is_string($value)) {
  1304. return false;
  1305. }
  1306. if ($url = parse_url($value, PHP_URL_HOST)) {
  1307. return count(dns_get_record($url, DNS_A | DNS_AAAA)) > 0;
  1308. }
  1309. return false;
  1310. }
  1311. /**
  1312. * Validate the given value is a valid file.
  1313. *
  1314. * @param string $attribute
  1315. * @param mixed $value
  1316. * @return bool
  1317. */
  1318. protected function validateFile($attribute, $value)
  1319. {
  1320. return $this->isAValidFileInstance($value);
  1321. }
  1322. /**
  1323. * Validate the MIME type of a file is an image MIME type.
  1324. *
  1325. * @param string $attribute
  1326. * @param mixed $value
  1327. * @return bool
  1328. */
  1329. protected function validateImage($attribute, $value)
  1330. {
  1331. return $this->validateMimes($attribute, $value, ['jpeg', 'png', 'gif', 'bmp', 'svg']);
  1332. }
  1333. /**
  1334. * Validate the dimensions of an image matches the given values.
  1335. *
  1336. * @param string $attribute
  1337. * @param mixed $value
  1338. * @param array $parameters
  1339. * @return bool
  1340. */
  1341. protected function validateDimensions($attribute, $value, $parameters)
  1342. {
  1343. if (! $sizeDetails = getimagesize($value->getRealPath())) {
  1344. return false;
  1345. }
  1346. $this->requireParameterCount(1, $parameters, 'dimensions');
  1347. list($width, $height) = $sizeDetails;
  1348. $parameters = $this->parseNamedParameters($parameters);
  1349. if (
  1350. isset($parameters['width']) && $parameters['width'] != $width ||
  1351. isset($parameters['min_width']) && $parameters['min_width'] > $width ||
  1352. isset($parameters['max_width']) && $parameters['max_width'] < $width ||
  1353. isset($parameters['height']) && $parameters['height'] != $height ||
  1354. isset($parameters['min_height']) && $parameters['min_height'] > $height ||
  1355. isset($parameters['max_height']) && $parameters['max_height'] < $height
  1356. ) {
  1357. return false;
  1358. }
  1359. if (isset($parameters['ratio'])) {
  1360. list($numerator, $denominator) = array_pad(sscanf($parameters['ratio'], '%d/%d'), 2, 1);
  1361. return $numerator / $denominator == $width / $height;
  1362. }
  1363. return true;
  1364. }
  1365. /**
  1366. * Validate the guessed extension of a file upload is in a set of file extensions.
  1367. *
  1368. * @param string $attribute
  1369. * @param mixed $value
  1370. * @param array $parameters
  1371. * @return bool
  1372. */
  1373. protected function validateMimes($attribute, $value, $parameters)
  1374. {
  1375. if (! $this->isAValidFileInstance($value)) {
  1376. return false;
  1377. }
  1378. return $value->getPath() != '' && in_array($value->guessExtension(), $parameters);
  1379. }
  1380. /**
  1381. * Validate the MIME type of a file upload attribute is in a set of MIME types.
  1382. *
  1383. * @param string $attribute
  1384. * @param mixed $value
  1385. * @param array $parameters
  1386. * @return bool
  1387. */
  1388. protected function validateMimetypes($attribute, $value, $parameters)
  1389. {
  1390. if (! $this->isAValidFileInstance($value)) {
  1391. return false;
  1392. }
  1393. return $value->getPath() != '' && in_array($value->getMimeType(), $parameters);
  1394. }
  1395. /**
  1396. * Check that the given value is a valid file instance.
  1397. *
  1398. * @param mixed $value
  1399. * @return bool
  1400. */
  1401. public function isAValidFileInstance($value)
  1402. {
  1403. if ($value instanceof UploadedFile && ! $value->isValid()) {
  1404. return false;
  1405. }
  1406. return $value instanceof File;
  1407. }
  1408. /**
  1409. * Validate that an attribute contains only alphabetic characters.
  1410. *
  1411. * @param string $attribute
  1412. * @param mixed $value
  1413. * @return bool
  1414. */
  1415. protected function validateAlpha($attribute, $value)
  1416. {
  1417. return is_string($value) && preg_match('/^[\pL\pM]+$/u', $value);
  1418. }
  1419. /**
  1420. * Validate that an attribute contains only alpha-numeric characters.
  1421. *
  1422. * @param string $attribute
  1423. * @param mixed $value
  1424. * @return bool
  1425. */
  1426. protected function validateAlphaNum($attribute, $value)
  1427. {
  1428. if (! is_string($value) && ! is_numeric($value)) {
  1429. return false;
  1430. }
  1431. return preg_match('/^[\pL\pM\pN]+$/u', $value);
  1432. }
  1433. /**
  1434. * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores.
  1435. *
  1436. * @param string $attribute
  1437. * @param mixed $value
  1438. * @return bool
  1439. */
  1440. protected function validateAlphaDash($attribute, $value)
  1441. {
  1442. if (! is_string($value) && ! is_numeric($value)) {
  1443. return false;
  1444. }
  1445. return preg_match('/^[\pL\pM\pN_-]+$/u', $value);
  1446. }
  1447. /**
  1448. * Validate that an attribute passes a regular expression check.
  1449. *
  1450. * @param string $attribute
  1451. * @param mixed $value
  1452. * @param array $parameters
  1453. * @return bool
  1454. */
  1455. protected function validateRegex($attribute, $value, $parameters)
  1456. {
  1457. if (! is_string($value) && ! is_numeric($value)) {
  1458. return false;
  1459. }
  1460. $this->requireParameterCount(1, $parameters, 'regex');
  1461. return preg_match($parameters[0], $value);
  1462. }
  1463. /**
  1464. * Validate th