This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace mindplay\kissform\Fields; |
||
4 | |||
5 | use DateTime; |
||
6 | use DateTimeZone; |
||
7 | use InvalidArgumentException; |
||
8 | use mindplay\kissform\Facets\ParserInterface; |
||
9 | use mindplay\kissform\Fields\Base\TimeZoneAwareField; |
||
10 | use mindplay\kissform\InputModel; |
||
11 | use mindplay\kissform\InputRenderer; |
||
12 | use mindplay\kissform\Validators\CheckParser; |
||
13 | use mindplay\lang; |
||
14 | use UnexpectedValueException; |
||
15 | |||
16 | /** |
||
17 | * This field type implements a date-picker using three (year/month/day) drop-downs. |
||
18 | */ |
||
19 | class DateSelectField extends TimeZoneAwareField implements ParserInterface |
||
20 | { |
||
21 | const KEY_YEAR = 'year'; |
||
22 | const KEY_MONTH = 'month'; |
||
23 | const KEY_DAY = 'day'; |
||
24 | |||
25 | /** |
||
26 | * @var int first year available for selection in year drop-down |
||
27 | */ |
||
28 | public $year_min; |
||
29 | |||
30 | /** |
||
31 | * @var int last year available for selection in year drop-down |
||
32 | */ |
||
33 | public $year_max; |
||
34 | |||
35 | /** |
||
36 | * @var string[] list of month names |
||
37 | */ |
||
38 | public $months; |
||
39 | |||
40 | /** |
||
41 | * @var string label for the year drop-down |
||
42 | */ |
||
43 | public $label_year; |
||
44 | |||
45 | /** |
||
46 | * @var string label for the year drop-down |
||
47 | */ |
||
48 | public $label_month; |
||
49 | |||
50 | /** |
||
51 | * @var string label for the year drop-down |
||
52 | */ |
||
53 | public $label_day; |
||
54 | |||
55 | /** |
||
56 | * @var string[] field order, e.g. KEY_* constants in the desired input order |
||
57 | */ |
||
58 | public $order = [ |
||
59 | self::KEY_DAY, |
||
60 | self::KEY_MONTH, |
||
61 | self::KEY_YEAR, |
||
62 | ]; |
||
63 | |||
64 | /** |
||
65 | * @var string CSS class-name for the year drop-down |
||
66 | */ |
||
67 | public $year_class = self::KEY_YEAR; |
||
68 | |||
69 | /** |
||
70 | * @var string CSS class-name for the year drop-down |
||
71 | */ |
||
72 | public $month_class = self::KEY_MONTH; |
||
73 | |||
74 | /** |
||
75 | * @var string CSS class-name for the year drop-down |
||
76 | */ |
||
77 | public $day_class = self::KEY_DAY; |
||
78 | |||
79 | /** |
||
80 | * @param string $name field name |
||
81 | * @param DateTimeZone|string|null $timezone input time-zone (or NULL to use the current default timezone) |
||
82 | */ |
||
83 | 2 | public function __construct($name, $timezone = null) |
|
84 | { |
||
85 | 2 | parent::__construct($name); |
|
86 | |||
87 | 2 | $this->setTimeZone($timezone); |
|
88 | |||
89 | 2 | $this->setYearRange(0, -100); |
|
90 | |||
91 | 2 | $t = lang::domain("mindplay/kissform"); |
|
92 | |||
93 | 2 | $this->months = explode('|', $t("months")); |
|
94 | |||
95 | 2 | $this->label_year = $t("year"); |
|
96 | 2 | $this->label_month = $t("month"); |
|
97 | 2 | $this->label_day = $t("day"); |
|
98 | 2 | } |
|
99 | |||
100 | /** |
||
101 | * Set the range of years available in the year drop-down. |
||
102 | * |
||
103 | * Values are relative to current year - e.g. 0 is the current year, -1 is last |
||
104 | * year, 10 is 10 years from now, etc. |
||
105 | * |
||
106 | * @param int $min |
||
107 | * @param int $max |
||
108 | * |
||
109 | * @return void |
||
110 | */ |
||
111 | 2 | public function setYearRange($min, $max) |
|
112 | { |
||
113 | 2 | $date = new DateTime(); |
|
114 | 2 | $date->setTimezone($this->timezone); |
|
115 | |||
116 | 2 | $year = (int) $date->format('Y'); |
|
117 | |||
118 | 2 | $this->year_min = $year + $min; |
|
119 | 2 | $this->year_max = $year + $max; |
|
120 | 2 | } |
|
121 | |||
122 | /** |
||
123 | * Attempt to parse the given form input and convert to integer timestamp. |
||
124 | * |
||
125 | * @param string $input |
||
126 | * |
||
127 | * @return int|null integer timestamp on success; NULL on failure |
||
128 | */ |
||
129 | 1 | public function parseInput($input) |
|
130 | { |
||
131 | 1 | if (!isset($input[self::KEY_YEAR], $input[self::KEY_MONTH], $input[self::KEY_DAY])) { |
|
132 | return null; |
||
133 | } |
||
134 | |||
135 | 1 | $year = (int) $input[self::KEY_YEAR]; |
|
136 | 1 | $month = (int) $input[self::KEY_MONTH]; |
|
137 | 1 | $day = (int) $input[self::KEY_DAY]; |
|
138 | |||
139 | 1 | if (! checkdate($month, $day, $year)) { |
|
140 | return null; // invalid date |
||
141 | } |
||
142 | |||
143 | 1 | $date = new DateTime(); |
|
144 | 1 | $date->setTimezone($this->timezone); |
|
145 | 1 | $date->setDate($year, $month, $day); |
|
146 | 1 | $date->setTime(0, 0, 0); |
|
147 | |||
148 | 1 | return $date->getTimestamp(); |
|
149 | } |
||
150 | |||
151 | /** |
||
152 | * @param InputModel $model |
||
153 | * |
||
154 | * @return int|null timestamp |
||
155 | * |
||
156 | * @throws UnexpectedValueException if the input is invalid (assumes valid input) |
||
157 | */ |
||
158 | 1 | public function getValue(InputModel $model) |
|
159 | { |
||
160 | 1 | $input = $model->getInput($this); |
|
161 | |||
162 | 1 | if ($input === null) { |
|
163 | return null; |
||
164 | } |
||
165 | |||
166 | 1 | $value = $this->parseInput($input); |
|
0 ignored issues
–
show
|
|||
167 | |||
168 | 1 | if ($value === null) { |
|
169 | throw new UnexpectedValueException("invalid date input"); |
||
170 | } |
||
171 | |||
172 | 1 | return $value; |
|
0 ignored issues
–
show
The return type of
return $value; (integer ) is incompatible with the return type of the parent method mindplay\kissform\Field::getValue of type string|array|null .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
173 | } |
||
174 | |||
175 | /** |
||
176 | * @param InputModel $model |
||
177 | * @param int|null $value timestamp |
||
178 | * |
||
179 | * @return void |
||
180 | * |
||
181 | * @throws InvalidArgumentException if the given value is unacceptable. |
||
182 | */ |
||
183 | 1 | public function setValue(InputModel $model, $value) |
|
184 | { |
||
185 | 1 | if (is_int($value)) { |
|
186 | 1 | $date = new Datetime(); |
|
187 | 1 | $date->setTimestamp($value); |
|
188 | 1 | $date->setTimezone($this->timezone); |
|
189 | |||
190 | 1 | $model->setInput( |
|
191 | 1 | $this, [ |
|
192 | 1 | self::KEY_YEAR => $date->format('Y'), |
|
193 | 1 | self::KEY_MONTH => $date->format('n'), |
|
194 | 1 | self::KEY_DAY => $date->format('j'), |
|
195 | ] |
||
196 | ); |
||
197 | 1 | } elseif ($value === null) { |
|
198 | 1 | $model->setInput($this, null); |
|
199 | } else { |
||
200 | throw new InvalidArgumentException("string expected"); |
||
201 | } |
||
202 | 1 | } |
|
203 | |||
204 | /** |
||
205 | * @inheritdoc |
||
206 | * |
||
207 | * @throws UnexpectedValueException |
||
208 | */ |
||
209 | 1 | public function renderInput(InputRenderer $renderer, InputModel $model, array $attr) |
|
210 | { |
||
211 | 1 | $years = range($this->year_min, $this->year_max); |
|
212 | 1 | $months = range(1, 12); |
|
213 | 1 | $days = range(1, 31); |
|
214 | |||
215 | 1 | $year = new SelectField(self::KEY_YEAR, array_combine($years, $years)); |
|
216 | 1 | $month = new SelectField(self::KEY_MONTH, array_combine($months, $this->months)); |
|
217 | 1 | $day = new SelectField(self::KEY_DAY, array_combine($days, $days)); |
|
218 | |||
219 | 1 | if (! $this->isRequired()) { |
|
220 | 1 | $year->disabled = $this->label_year; |
|
221 | 1 | $month->disabled = $this->label_month; |
|
222 | 1 | $day->disabled = $this->label_day; |
|
223 | } |
||
224 | |||
225 | 1 | $html = ''; |
|
226 | |||
227 | 1 | $renderer->visit($this, function () use ($renderer, $year, $month, $day, &$html) { |
|
228 | 1 | foreach ($this->order as $key) { |
|
229 | switch ($key) { |
||
230 | 1 | case DateSelectField::KEY_YEAR: |
|
231 | 1 | $html .= $renderer->render($year, ['class' => $this->year_class]); |
|
232 | 1 | break; |
|
233 | |||
234 | 1 | case DateSelectField::KEY_MONTH: |
|
235 | 1 | $html .= $renderer->render($month, ['class' => $this->month_class]); |
|
236 | 1 | break; |
|
237 | |||
238 | 1 | case DateSelectField::KEY_DAY: |
|
239 | 1 | $html .= $renderer->render($day, ['class' => $this->day_class]); |
|
240 | 1 | break; |
|
241 | |||
242 | default: |
||
243 | 1 | throw new UnexpectedValueException("expected 'year', 'month' or 'day' - got: {$key}"); |
|
244 | } |
||
245 | } |
||
246 | 1 | }); |
|
247 | |||
248 | 1 | return $html; |
|
249 | } |
||
250 | |||
251 | /** |
||
252 | * {@inheritdoc} |
||
253 | */ |
||
254 | 1 | public function createValidators() |
|
255 | { |
||
256 | 1 | $validators = parent::createValidators(); |
|
257 | |||
258 | 1 | $validators[] = new CheckParser($this, "datetime"); |
|
259 | |||
260 | 1 | return $validators; |
|
261 | } |
||
262 | } |
||
263 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.