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 | * @copyright 2016-2018, Aleksandr Bushlanov |
||
4 | * @package gtvolk\WorkingTime |
||
5 | * @link https://github.com/GT-Volk/ |
||
6 | * @license https://github.com/GT-Volk/working-time/blob/master/LICENSE.md |
||
7 | */ |
||
8 | |||
9 | namespace gtvolk\WorkingTime; |
||
10 | |||
11 | use DateTime; |
||
12 | |||
13 | /** |
||
14 | * Класс рассчитывает временнЫе интервалы, учитывая рабочие часы и выходные дни. |
||
15 | * |
||
16 | * @property DateTime $dateTime |
||
17 | * @property array $workingDays |
||
18 | * @property array $weekends |
||
19 | * @property array $holidays |
||
20 | * |
||
21 | * @since 1.0.5 |
||
22 | * |
||
23 | * @author Aleksandr Bushlanov <[email protected]> |
||
24 | */ |
||
25 | class WorkingTime |
||
26 | { |
||
27 | /** |
||
28 | * @var DateTime |
||
29 | */ |
||
30 | public $dateTime; |
||
31 | |||
32 | /** |
||
33 | * @var array |
||
34 | */ |
||
35 | public $workingDays; |
||
36 | |||
37 | /** |
||
38 | * @var null|array |
||
39 | */ |
||
40 | public $weekends; |
||
41 | |||
42 | /** |
||
43 | * @var null|array |
||
44 | */ |
||
45 | public $holidays; |
||
46 | |||
47 | /** |
||
48 | * WorkingTime constructor. |
||
49 | * |
||
50 | * @param array $workTimeConfig |
||
51 | * @param string $dateTime |
||
52 | * @throws \Exception |
||
53 | */ |
||
54 | 16 | public function __construct(array $workTimeConfig, string $dateTime = 'now') |
|
55 | { |
||
56 | 16 | $this->dateTime = new DateTime($dateTime); |
|
57 | 16 | foreach ($workTimeConfig as $name => $value) { |
|
58 | 16 | $this->$name = $value; |
|
59 | } |
||
60 | 16 | } |
|
61 | |||
62 | /** |
||
63 | * Фурмирует строку дня. |
||
64 | * |
||
65 | * @param null|string $date |
||
66 | * @param string $format |
||
67 | * @return string |
||
68 | */ |
||
69 | 12 | private function buildDataPartString(?string $date, string $format): string |
|
70 | { |
||
71 | 12 | return null === $date ? $this->dateTime->format($format) : date($format, strtotime($date)); |
|
72 | } |
||
73 | |||
74 | /** |
||
75 | * Формирует дату из строки. |
||
76 | * |
||
77 | * @param string $date |
||
78 | * @return DateTime |
||
79 | * @throws \Exception |
||
80 | */ |
||
81 | 7 | private function buildDate(string $date = null): DateTime |
|
82 | { |
||
83 | 7 | if (null === $date) { |
|
84 | 1 | $date = $this->dateTime->format('Y-m-d H:i'); |
|
85 | } |
||
86 | |||
87 | 7 | return new DateTime($date); |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * Проверяет является ли дата праздничным днём. |
||
92 | * |
||
93 | * @param string $date |
||
94 | * @return bool |
||
95 | */ |
||
96 | 11 | public function isHoliday(string $date = null): bool |
|
97 | { |
||
98 | 11 | if (empty($this->holidays)) { |
|
99 | 1 | return false; // Если не указаны праздничные дни, то день рабочий. |
|
100 | } |
||
101 | 11 | $day = $this->buildDataPartString($date, 'm-d'); |
|
102 | |||
103 | 11 | return \in_array($day, $this->holidays, false); |
|
104 | } |
||
105 | |||
106 | /** |
||
107 | * Проверяет является ли дата выходным днём. |
||
108 | * |
||
109 | * @param string $date |
||
110 | * @return bool |
||
111 | */ |
||
112 | 11 | public function isWeekend(string $date = null): bool |
|
113 | { |
||
114 | 11 | if (empty($this->weekends)) { |
|
115 | 1 | return false; // Если не указаны выходные дни, то день рабочий. |
|
116 | } |
||
117 | 11 | $day = $this->buildDataPartString($date, 'w'); |
|
118 | |||
119 | 11 | return \in_array($day, $this->weekends, false); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Проверяет евляется ли дата рабочим днём. |
||
124 | * |
||
125 | * Формат даты - "Y-m-d" |
||
126 | * @param string $date |
||
127 | * @return bool |
||
128 | */ |
||
129 | 10 | public function isWorkingDate(string $date = null): bool |
|
130 | { |
||
131 | 10 | return !($this->isWeekend($date) || $this->isHoliday($date)); |
|
132 | } |
||
133 | |||
134 | /** |
||
135 | * Проверяет евляется ли время рабочим. |
||
136 | * |
||
137 | * @param string|null $time Формат времени - "H:i" или полный "Y-m-d H:i" |
||
138 | * @return bool |
||
139 | * @throws \InvalidArgumentException |
||
140 | * @throws \Exception |
||
141 | */ |
||
142 | 2 | public function isWorkingTime(string $time = null): bool |
|
143 | { |
||
144 | 2 | if (null === $time) { |
|
145 | 1 | $dateTime = $this->dateTime; |
|
146 | 2 | } elseif (self::validateDate($time, 'H:i')) { |
|
147 | 1 | $dateTime = new DateTime($this->dateTime->format('Y-m-d') . ' ' . $time); |
|
148 | 2 | } elseif (self::validateDate($time, 'Y-m-d H:i')) { |
|
149 | 1 | $dateTime = new DateTime($time); |
|
150 | } else { |
||
151 | 1 | throw new \InvalidArgumentException("Date `{$time}` isn't a valid date. Dates should be formatted as Y-m-d or H:i, e.g. `2016-10-27` or `17:30`."); |
|
152 | } |
||
153 | |||
154 | 1 | [$jobStart, $jobEnd] = explode('-', $this->workingDays[$dateTime->format('w')]); |
|
0 ignored issues
–
show
|
|||
155 | |||
156 | 1 | $dtStart = new DateTime($dateTime->format('Y-m-d') . ' ' . $jobStart); |
|
157 | 1 | $dtEnd = new DateTime($dateTime->format('Y-m-d') . ' ' . $jobEnd); |
|
158 | |||
159 | 1 | return $dateTime > $dtStart && $dateTime < $dtEnd; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * Возвращает следующий рабочий день. |
||
164 | * |
||
165 | * @param string|null $date Формат даты - "Y-m-d" |
||
166 | * @return string |
||
167 | * @throws \Exception |
||
168 | */ |
||
169 | 6 | public function nextWorkingDay(string $date = null): string |
|
170 | { |
||
171 | 6 | if (null === $date) { |
|
172 | 1 | $date = $this->dateTime->format('Y-m-d'); |
|
173 | } |
||
174 | 6 | $dateTime = new DateTime($date); |
|
175 | |||
176 | do { |
||
177 | 6 | $dateTime->modify('+1 day'); |
|
178 | 6 | } while (!$this->isWorkingDate($dateTime->format('Y-m-d'))); |
|
179 | |||
180 | 6 | return $dateTime->format('Y-m-d'); |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * Возвращает ближайшее рабочее время. Либо null если текущее время уже рабочее. |
||
185 | * |
||
186 | * @param string|null $date |
||
187 | * @return null|string |
||
188 | * @throws \Exception |
||
189 | */ |
||
190 | 7 | public function nextWorkingTime(string $date = null): ?string |
|
191 | { |
||
192 | 7 | $dateTime = $this->buildDate($date); |
|
193 | 7 | $nextWorkingTime = null; |
|
194 | |||
195 | // Если дня нет в конфиге считаем его выходным |
||
196 | 7 | if (!array_key_exists($dateTime->format('w'), $this->workingDays)) { |
|
197 | 1 | $nextWorkingDay = $this->nextWorkingDay($dateTime->format('Y-m-d')); |
|
198 | 1 | $nWDateTime = new DateTime($nextWorkingDay); |
|
199 | 1 | $workTime = explode('-', $this->workingDays[$nWDateTime->format('w')]); |
|
200 | |||
201 | 1 | return $nextWorkingDay . ' ' . $workTime[0]; |
|
202 | } |
||
203 | |||
204 | 7 | [$jobStart, $jobEnd] = explode('-', $this->workingDays[$dateTime->format('w')]); |
|
0 ignored issues
–
show
|
|||
205 | |||
206 | 7 | if ($this->isWorkingDate($dateTime->format('Y-m-d'))) { // Если день рабочий проверяем время |
|
207 | |||
208 | 7 | $dtStart = new DateTime($dateTime->format('Y-m-d') . ' ' . $jobStart); |
|
209 | 7 | $dtEnd = new DateTime($dateTime->format('Y-m-d') . ' ' . $jobEnd); |
|
210 | |||
211 | // Если начало дня еще не наступило (утро) возвращаем указанную дату + время |
||
212 | 7 | if ($dateTime < $dtStart) { |
|
213 | 6 | $nextWorkingTime = $dateTime->format('Y-m-d') . ' ' . $jobStart; |
|
214 | 6 | } elseif ($dateTime >= $dtEnd) { // Если рабочий день уже закончился |
|
215 | // Ищем следующий рабочий день и выводим его + время начало дня |
||
216 | 7 | $nextWorkingTime = $this->nextWorkingDay($dateTime->format('Y-m-d')) . ' ' . $jobStart; |
|
217 | } |
||
218 | } else { // Если день не рабочий |
||
219 | |||
220 | // Ищем следующий рабочий день и выводим его + время начало дня |
||
221 | 1 | $nextWorkingTime = $this->nextWorkingDay($dateTime->format('Y-m-d')) . ' ' . $jobStart; |
|
222 | } |
||
223 | |||
224 | 7 | return $nextWorkingTime; |
|
225 | } |
||
226 | |||
227 | /** |
||
228 | * Возвращает дату время начала следующего дня. |
||
229 | * |
||
230 | * @param string|null $date |
||
231 | * @return string |
||
232 | * @throws \Exception |
||
233 | */ |
||
234 | 2 | public function nextWorkingDayStart(string $date = null): string |
|
235 | { |
||
236 | 2 | $nextWorkingDayDT = new DateTime($this->nextWorkingDay($date)); |
|
237 | 2 | $day = $nextWorkingDayDT->format('w'); |
|
238 | 2 | $jobStart = explode('-', $this->workingDays[$day])[0]; |
|
239 | |||
240 | 2 | return $nextWorkingDayDT->format('Y-m-d') . ' ' . $jobStart; |
|
241 | } |
||
242 | |||
243 | /** |
||
244 | * Возвращает дату время начала следующего дня. |
||
245 | * |
||
246 | * @param string|null $date |
||
247 | * @return string |
||
248 | * @throws \Exception |
||
249 | */ |
||
250 | 1 | private function nextWorkingDayEnd(string $date = null): string |
|
251 | { |
||
252 | 1 | $nextWorkingDayDT = new DateTime($this->nextWorkingDay($date)); |
|
253 | 1 | $day = $nextWorkingDayDT->format('w'); |
|
254 | 1 | $jobEnd = explode('-', $this->workingDays[$day])[1]; |
|
255 | |||
256 | 1 | return $nextWorkingDayDT->format('Y-m-d') . ' ' . $jobEnd; |
|
257 | } |
||
258 | |||
259 | /** |
||
260 | * Возвращает длинну рабочего дня в минутах. |
||
261 | * |
||
262 | * @param string|null $date Формат даты - "Y-m-d" |
||
263 | * @return int |
||
264 | * @throws \Exception |
||
265 | */ |
||
266 | 6 | public function getJobMinutesInDay(string $date = null): int |
|
267 | { |
||
268 | 6 | $day = $this->buildDataPartString($date, 'w'); |
|
269 | 6 | $nextWorkingTime = $this->nextWorkingTime($date ?? $this->dateTime->format('Y-m-d H:i')); |
|
270 | |||
271 | 6 | [$jobStart, $jobEnd] = explode('-', $this->workingDays[$day]); |
|
0 ignored issues
–
show
The variable
$jobStart seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() |
|||
272 | // Считаем остаток рабочего времени |
||
273 | 6 | if ($nextWorkingTime === null) { |
|
274 | 5 | $jobStart = ($date === null ? date('H:i', $this->dateTime->getTimestamp()) : date('H:i', strtotime($date))); |
|
275 | } |
||
276 | |||
277 | 6 | $dtStart = new DateTime($jobStart); |
|
0 ignored issues
–
show
The variable
$jobStart does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
278 | 6 | $dtEnd = new DateTime($jobEnd); |
|
279 | 6 | $diff = $dtEnd->diff($dtStart); |
|
280 | |||
281 | 6 | return ($diff->h * 60 + $diff->i); |
|
282 | } |
||
283 | |||
284 | /** |
||
285 | * Прибавляет заданное количество минут к дате с учетом рабочего времени. |
||
286 | * |
||
287 | * @param int $minutes |
||
288 | * @param string $date |
||
289 | * @return DateTime |
||
290 | * @throws \Exception |
||
291 | */ |
||
292 | 3 | private function modifyDate(int $minutes, string $date): DateTime |
|
293 | { |
||
294 | 3 | $dateTime = new DateTime($date); |
|
295 | 3 | $jobMinutesInDay = $this->getJobMinutesInDay($date); |
|
296 | |||
297 | // Если длинна дня больше чем время модификации |
||
298 | 3 | if ($jobMinutesInDay > $minutes) { |
|
299 | 3 | $dateTime->modify("+$minutes minutes"); |
|
300 | } else { // Если длинна дня меньше чем время модификации |
||
301 | do { |
||
302 | 2 | $dateTime->modify("+$jobMinutesInDay minutes"); |
|
303 | 2 | $minutes -= $jobMinutesInDay; |
|
304 | 2 | $nextWorkingTime = $this->nextWorkingTime($dateTime->format('Y-m-d H:i')); |
|
305 | 2 | $dateTime = new DateTime($nextWorkingTime); |
|
306 | 2 | $jobMinutesInDay = $this->getJobMinutesInDay($dateTime->format('Y-m-d H:i')); |
|
307 | 2 | if ($jobMinutesInDay > $minutes) { |
|
308 | 2 | $dateTime->modify("+$minutes minutes"); |
|
309 | 2 | $minutes = 0; |
|
310 | } |
||
311 | 2 | } while ($minutes > 0); |
|
312 | } |
||
313 | |||
314 | 3 | return $dateTime; |
|
315 | } |
||
316 | |||
317 | /** |
||
318 | * Прибавляет заданное количество минут к дате с учетом рабочего времени. |
||
319 | * |
||
320 | * @param int $minutes |
||
321 | * @param string $date |
||
322 | * @return string |
||
323 | * @throws \Exception |
||
324 | */ |
||
325 | 3 | public function modify(int $minutes, string $date = null): string |
|
326 | { |
||
327 | 3 | $nextWorkingTime = $this->nextWorkingTime($date); |
|
328 | // Если дата вне рабочего времени |
||
329 | 3 | if ($nextWorkingTime !== null) { |
|
330 | 3 | $dateTime = $this->modifyDate($minutes, $nextWorkingTime); |
|
331 | } else { // если дата в пределах рабочего времени |
||
332 | 2 | $dateTime = $this->modifyDate($minutes, $date ?? $this->dateTime->format('Y-m-d H:i')); |
|
333 | } |
||
334 | |||
335 | 3 | if (null === $date) { |
|
336 | 1 | $this->dateTime->setTimestamp($dateTime->getTimestamp()); |
|
337 | } |
||
338 | |||
339 | 3 | return $dateTime->format('Y-m-d H:i'); |
|
340 | } |
||
341 | |||
342 | /** |
||
343 | * Возвращает рабочее время в минутах в заданном временном интервале. |
||
344 | * |
||
345 | * @param string $startDate |
||
346 | * @param string $endDate |
||
347 | * @return int |
||
348 | * @throws \InvalidArgumentException |
||
349 | * @throws \Exception |
||
350 | */ |
||
351 | 2 | public function calculatingWorkingTime(string $startDate, string $endDate): int |
|
352 | { |
||
353 | 2 | if (!self::validateDate($startDate) || !self::validateDate($endDate)) { |
|
354 | 1 | throw new \InvalidArgumentException("Date isn't a valid date. Dates should be formatted as Y-m-d H:i:s, e.g. `2016-10-27 17:30:00`."); |
|
355 | } |
||
356 | |||
357 | 1 | $dtStart = $this->buildDate($startDate); |
|
358 | 1 | $dtEnd = $this->buildDate($endDate); |
|
359 | |||
360 | // Проверяем находится ли промежуток до наступления рабочего времени |
||
361 | 1 | $nextWorkingTime = $this->nextWorkingTime($dtStart->format('Y-m-d H:i')); |
|
362 | 1 | if ((null !== $nextWorkingTime) && $this->buildDate($nextWorkingTime) > $dtEnd) { |
|
363 | 1 | return 0; |
|
364 | } |
||
365 | |||
366 | 1 | $diff = $dtEnd->diff($dtStart); |
|
367 | 1 | $diffMinutes = $diff->d * 1440 + $diff->h * 60 + $diff->i; // Разница между датами в минутах |
|
368 | 1 | $jobMinutesInDay = $this->getJobMinutesInDay($dtStart->format('Y-m-d H:i')); // Длинна рабочего дня |
|
369 | |||
370 | // Если разница во времени меньше длинны рабочего дня |
||
371 | 1 | if ($diffMinutes < $jobMinutesInDay) { |
|
372 | 1 | return $diffMinutes; |
|
373 | } |
||
374 | |||
375 | 1 | $workingTime = 0; |
|
376 | // Если разница больше то перебираем дни |
||
377 | 1 | $nextWorkingDayStartDT = new DateTime($this->nextWorkingDayStart($dtStart->format('Y-m-d'))); |
|
378 | 1 | $nextWorkingDayEndDT = new DateTime($this->nextWorkingDayEnd($dtStart->format('Y-m-d'))); |
|
379 | do { |
||
380 | // Дата находится в промежутке ДО наступления следующего рабочего времени |
||
381 | 1 | if ($nextWorkingDayStartDT > $dtEnd) { |
|
382 | 1 | $workingTime = $jobMinutesInDay; |
|
383 | 1 | break; |
|
384 | } |
||
385 | // Дата в промежутке следующего рабочего дня |
||
386 | 1 | if ($nextWorkingDayStartDT < $dtEnd && $dtEnd < $nextWorkingDayEndDT && ($nextWorkingDayStartDT->format('Y-m-d') === $dtEnd->format('Y-m-d'))) { |
|
387 | 1 | $nextDiff = $dtEnd->diff($nextWorkingDayStartDT); |
|
388 | 1 | $nextDiffMinutes = $nextDiff->d * 1440 + $nextDiff->h * 60 + $nextDiff->i; |
|
389 | 1 | $workingTime = $nextDiffMinutes + $jobMinutesInDay; |
|
390 | 1 | break; |
|
391 | } |
||
392 | |||
393 | 1 | $jobMinutesInDay += $this->getJobMinutesInDay($nextWorkingDayStartDT->format('Y-m-d H:i')); // Длинна рабочего дня |
|
394 | 1 | $nextWorkingDayStartDT = new DateTime($this->nextWorkingDayStart($nextWorkingDayStartDT->format('Y-m-d'))); |
|
395 | 1 | $nextWorkingDayEndDT = new DateTime($this->nextWorkingDayEnd($nextWorkingDayStartDT->format('Y-m-d'))); |
|
396 | 1 | } while (true); |
|
397 | |||
398 | 1 | return $workingTime; |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * Проверяет является ли строка корректной датой. |
||
403 | * |
||
404 | * @param $date |
||
405 | * @param string $format |
||
406 | * @return bool |
||
407 | */ |
||
408 | 5 | public static function validateDate(string $date, string $format = 'Y-m-d H:i:s'): bool |
|
409 | { |
||
410 | 5 | $vDate = DateTime::createFromFormat($format, $date); |
|
411 | 5 | return $vDate && $vDate->format($format) === $date; |
|
412 | } |
||
413 | } |
||
414 |
This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.