PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

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