1 <?php
2
3 /**
4 * The MIT License
5 *
6 * Copyright 2014 George Marques <george at georgemarques.com.br>.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 namespace Flikore\Validator\Validators;
28
29 /**
30 * Validates if a string is a valid URI.
31 *
32 * @customKey <i>%protocol%</i> The valid(s) protocol(s) set in the constructor.
33 *
34 * @author George Marques <george at georgemarques.com.br>
35 * @version 0.5.2
36 * @since 0.3
37 * @license http://opensource.org/licenses/MIT MIT
38 * @copyright (c) 2014, George Marques
39 * @package Flikore\Validator
40 */
41 class UriValidator extends \Flikore\Validator\Validator
42 {
43
44 /**
45 * The error message for this validator.
46 * @var string The error message for this validator.
47 */
48 protected $message = 'The %key% must be a valid URI.';
49
50 /**
51 * An alternative error message for this validator for when the protocol is set.
52 * @var string An alternative error message for this validator for when the protocol is set.
53 */
54 protected $message_protocol = 'The %key% must be a valid URI and use the %protocol% protocol.';
55
56 /**
57 * The valid(s) protocol(s).
58 * @var mixed The valid(s) protocol(s).
59 */
60 protected $protocol;
61
62 /**
63 * Creates a new Uri Validator.
64 * @param mixed $protocol The valid(s) protocol(s) (string or array).
65 */
66 public function __construct($protocol = null)
67 {
68 if (is_array($protocol) && empty($protocol))
69 {
70 throw new \InvalidArgumentException('The valid procotol list cannot be empty');
71 }
72 elseif (is_object($protocol) && (!($protocol instanceof \Traversable)))
73 {
74 throw new \InvalidArgumentException('The protocol argument cannot be a noniterable object');
75 }
76 elseif ($protocol !== null)
77 {
78 $this->setErrorMessage($this->message_protocol);
79 }
80
81 if (!empty($protocol) && !is_scalar($protocol))
82 {
83 if (!$this->testInputList($protocol))
84 {
85 throw new \InvalidArgumentException('The list of protocols must be a collection of strings');
86 }
87
88 $this->addKeyValue('protocol', implode(', ', $protocol));
89 }
90 else
91 {
92 $this->addKeyValue('protocol', $protocol);
93 }
94 $this->protocol = $protocol;
95 }
96
97 /**
98 * Executes the real validation so it can be reused.
99 * @param mixed $value The value to validate.
100 * @return boolean Whether the value pass the validation.
101 */
102 protected function doValidate($value)
103 {
104 // ignore empty values
105 if ($this->isEmpty($value))
106 {
107 return true;
108 }
109 $uri_valid = $value === filter_var($value, FILTER_VALIDATE_URL);
110 if (empty($this->protocol))
111 {
112 return $uri_valid;
113 }
114 else
115 {
116 if (is_array($this->protocol) || $this->protocol instanceof \Traversable)
117 {
118 $protocol_valid = false;
119 foreach ($this->protocol as $pt)
120 {
121 if (strpos($value, $pt . '://') === 0)
122 {
123 $protocol_valid = true;
124 }
125 }
126 return $uri_valid && $protocol_valid;
127 }
128 else
129 {
130 if (strpos($value, $this->protocol . '://') !== 0)
131 {
132 return false;
133 }
134 else
135 {
136 return $uri_valid;
137 }
138 }
139 }
140 }
141
142 /**
143 * Tests the input list of protocols to check if all elements are valid.
144 *
145 * @param mixed $list Array or Traversable to test.
146 * @return boolean Returns true if the list is valid.
147 */
148 private function testInputList($list)
149 {
150 foreach ($list as $value)
151 {
152 if (!is_scalar($value))
153 {
154 return false;
155 }
156 }
157 return true;
158 }
159
160 }
161