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 | namespace Agavi\Date; |
||
3 | |||
4 | // +---------------------------------------------------------------------------+ |
||
5 | // | This file is part of the Agavi package. | |
||
6 | // | Copyright (c) 2005-2011 the Agavi Project. | |
||
7 | // | | |
||
8 | // | For the full copyright and license information, please view the LICENSE | |
||
9 | // | file that was distributed with this source code. You can also view the | |
||
10 | // | LICENSE file online at http://www.agavi.org/LICENSE.txt | |
||
11 | // | vi: set noexpandtab: | |
||
12 | // | Local Variables: | |
||
13 | // | indent-tabs-mode: t | |
||
14 | // | End: | |
||
15 | // +---------------------------------------------------------------------------+ |
||
16 | use Agavi\Exception\AgaviException; |
||
17 | use Agavi\Translation\TranslationManager; |
||
18 | use Agavi\Util\Toolkit; |
||
19 | |||
20 | /** |
||
21 | * A time zone based on the Olson database. Olson time zones change behavior |
||
22 | * over time. The raw offset, rules, presence or absence of daylight savings |
||
23 | * time, and even the daylight savings amount can all vary. |
||
24 | * |
||
25 | * Ported from ICU: |
||
26 | * icu/trunk/source/i18n/olsontz.cpp r19133 |
||
27 | * icu/trunk/source/i18n/olsontz.h r18762 |
||
28 | * |
||
29 | * @package agavi |
||
30 | * @subpackage date |
||
31 | * |
||
32 | * @author Dominik del Bondio <[email protected]> |
||
33 | * @author The ICU Project |
||
34 | * @copyright Authors |
||
35 | * @copyright The Agavi Project |
||
36 | * |
||
37 | * @since 0.11.0 |
||
38 | * |
||
39 | * @version $Id$ |
||
40 | */ |
||
41 | class OlsonTimeZone extends TimeZone |
||
42 | { |
||
43 | /** |
||
44 | * The transitions |
||
45 | * |
||
46 | * @var array |
||
47 | * @since 0.11.0 |
||
48 | */ |
||
49 | protected $transitions; |
||
50 | |||
51 | /** |
||
52 | * The types, 1..255 |
||
53 | * |
||
54 | * @var array |
||
55 | * @since 0.11.0 |
||
56 | */ |
||
57 | protected $types; |
||
58 | |||
59 | /** |
||
60 | * The last year for which the transitions data are to be used |
||
61 | * rather than the finalZone. If there is no finalZone, then this |
||
62 | * is set to INT32_MAX. NOTE: This corresponds to the year _before_ |
||
63 | * the one indicated by finalMillis. |
||
64 | * |
||
65 | * @var int |
||
66 | * @since 0.11.0 |
||
67 | */ |
||
68 | protected $finalYear; |
||
69 | |||
70 | /** |
||
71 | * The millis for the start of the first year for which finalZone |
||
72 | * is to be used, or DBL_MAX if finalZone is 0. NOTE: This is |
||
73 | * 0:00 GMT Jan 1, <finalYear + 1> (not <finalMillis>). |
||
74 | * |
||
75 | * @var float |
||
76 | * @since 0.11.0 |
||
77 | */ |
||
78 | protected $finalMillis; |
||
79 | |||
80 | /** |
||
81 | * A SimpleTimeZone that governs the behavior for years > finalYear. |
||
82 | * If and only if finalYear == INT32_MAX then finalZone == 0. |
||
83 | * |
||
84 | * @var SimpleTimeZone |
||
85 | * @since 0.11.0 |
||
86 | */ |
||
87 | protected $finalZone; // owned, may be NULL |
||
88 | |||
89 | const MAX_INT = 2147483647; |
||
90 | const MAX_DBL = Calendar::MAX_MILLIS; |
||
91 | |||
92 | /** |
||
93 | * Constructor |
||
94 | * |
||
95 | * @see AgaviOlsonTimeZone::constructor() |
||
96 | * @see AgaviOlsonTimeZone::constructorOSA() |
||
97 | * |
||
98 | * @author Dominik del Bondio <[email protected]> |
||
99 | * @author The ICU Project |
||
100 | * @since 0.11.0 |
||
101 | */ |
||
102 | public function __construct() |
||
103 | { |
||
104 | $arguments = func_get_args(); |
||
105 | if (count($arguments) == 1) { |
||
106 | parent::__construct($arguments[0]); |
||
107 | return; |
||
108 | } |
||
109 | $fName = Toolkit::overloadHelper(array( |
||
110 | array('name' => 'constructorOSA', |
||
111 | 'parameters' => array('object', 'string', 'array')), |
||
112 | ), |
||
113 | $arguments |
||
114 | ); |
||
115 | call_user_func_array(array($this, $fName), $arguments); |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Default constructor. Creates a time zone with an empty ID and |
||
120 | * a fixed GMT offset of zero. |
||
121 | * |
||
122 | * @author Dominik del Bondio <[email protected]> |
||
123 | * @author The ICU Project |
||
124 | * @since 0.11.0 |
||
125 | */ |
||
126 | protected function constructor() |
||
127 | { |
||
128 | $this->finalYear = self::MAX_INT; |
||
129 | $this->finalMillis = self::MAX_DBL; |
||
130 | $this->finalZone = null; |
||
131 | |||
132 | $this->constructEmpty(); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Construct a GMT+0 zone with no transitions. This is done when a |
||
137 | * constructor fails so the resultant object is well-behaved. |
||
138 | * |
||
139 | * @author Dominik del Bondio <[email protected]> |
||
140 | * @author The ICU Project |
||
141 | * @since 0.11.0 |
||
142 | */ |
||
143 | protected function constructEmpty() |
||
144 | { |
||
145 | $this->transitionCount = 0; |
||
0 ignored issues
–
show
|
|||
146 | $this->transitions = array(); |
||
147 | // TODO: this should probably contain at least one item |
||
148 | $this->types = array(); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Construct with info from an array. |
||
153 | * |
||
154 | * @param TranslationManager $tm The translation manager. |
||
155 | * @param string $id The id. |
||
156 | * @param array $zoneInfo The zone info data. |
||
157 | * |
||
158 | * @author Dominik del Bondio <[email protected]> |
||
159 | * @author The ICU Project |
||
160 | * @since 0.11.0 |
||
161 | */ |
||
162 | protected function constructorOSA(TranslationManager $tm, $id, array $zoneInfo) |
||
163 | { |
||
164 | parent::__construct($tm, $id); |
||
0 ignored issues
–
show
It seems like you call parent on a different method (
__construct() instead of constructorOSA() ). Are you sure this is correct? If so, you might want to change this to $this->__construct() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The ![]() |
|||
165 | |||
166 | $this->finalYear = self::MAX_INT; |
||
167 | $this->finalMillis = self::MAX_DBL; |
||
168 | $this->finalZone = null; |
||
169 | |||
170 | foreach ($zoneInfo['rules'] as $rule) { |
||
171 | $this->transitions[] = $rule; |
||
172 | } |
||
173 | |||
174 | $this->types = $zoneInfo['types']; |
||
175 | |||
176 | if (!isset($zoneInfo['finalRule'])) { |
||
177 | throw new AgaviException($id); |
||
178 | } |
||
179 | |||
180 | // Subtract one from the actual final year; we actually store final year - 1, |
||
181 | // and compare using > rather than >=. This allows us to use INT32_MAX as |
||
182 | // an exclusive upper limit for all years, including INT32_MAX. |
||
183 | $rawOffset = $zoneInfo['finalRule']['offset'] * DateDefinitions::MILLIS_PER_SECOND; |
||
184 | $this->finalYear = $zoneInfo['finalRule']['startYear'] - 1; |
||
0 ignored issues
–
show
It seems like
$zoneInfo['finalRule']['startYear'] - 1 can also be of type double . However, the property $finalYear is declared as type integer . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
185 | // Also compute the millis for Jan 1, 0:00 GMT of the finalYear. This reduces runtime computations. |
||
186 | $this->finalMillis = CalendarGrego::fieldsToDay($zoneInfo['finalRule']['startYear'], 0, 1) * DateDefinitions::MILLIS_PER_DAY; |
||
187 | |||
188 | if ($zoneInfo['finalRule']['type'] == 'dynamic') { |
||
189 | $fr = $zoneInfo['finalRule']; |
||
190 | $this->finalZone = new SimpleTimeZone( |
||
191 | $tm, $rawOffset, $id, |
||
192 | $fr['start']['month'], $fr['start']['date'], $fr['start']['day_of_week'], $fr['start']['time'], $fr['start']['type'], |
||
193 | $fr['end']['month'], $fr['end']['date'], $fr['end']['day_of_week'], $fr['end']['time'], $fr['end']['type'], |
||
194 | $fr['save'] * DateDefinitions::MILLIS_PER_SECOND |
||
195 | ); |
||
196 | } else { |
||
197 | $this->finalZone = new SimpleTimeZone($tm, $rawOffset, $id); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Returns true if the two TimeZone objects are equal. |
||
203 | * |
||
204 | * @param TimeZone $that The timezone to compare against. |
||
205 | * |
||
206 | * @author Dominik del Bondio <[email protected]> |
||
207 | * @author The ICU Project |
||
208 | * @since 0.11.0 |
||
209 | */ |
||
210 | View Code Duplication | function __is_equal(TimeZone $that) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
211 | { |
||
212 | // TODO: we need to compare finalyear and the transitions and finalzone |
||
213 | return ($this === $that || |
||
214 | (get_class($this) == get_class($that) && |
||
215 | TimeZone::__is_equal($that) |
||
216 | )); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * TimeZone API. |
||
221 | * |
||
222 | * @see TimeZone::getOffsetIIIIII() |
||
223 | * |
||
224 | * @author Dominik del Bondio <[email protected]> |
||
225 | * @author The ICU Project |
||
226 | * @since 0.11.0 |
||
227 | */ |
||
228 | View Code Duplication | protected function getOffsetIIIIII($era, $year, $month, $dom, $dow, $millis) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
229 | { |
||
230 | if ($month < DateDefinitions::JANUARY || $month > DateDefinitions::DECEMBER) { |
||
231 | throw new \InvalidArgumentException('Month out of range'); |
||
232 | } else { |
||
233 | return $this->getOffsetIIIIIII($era, $year, $month, $dom, $dow, $millis, CalendarGrego::monthLength($year, $month)); |
||
234 | } |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * TimeZone API. |
||
239 | * |
||
240 | * @see TimeZone::getOffsetIIIIIII() |
||
241 | * |
||
242 | * @author Dominik del Bondio <[email protected]> |
||
243 | * @author The ICU Project |
||
244 | * @since 0.11.0 |
||
245 | */ |
||
246 | protected function getOffsetIIIIIII($era, $year, $month, $dom, $dow, $millis, $monthLength) |
||
247 | { |
||
248 | if (($era != GregorianCalendar::AD && $era != GregorianCalendar::BC) |
||
249 | || $month < DateDefinitions::JANUARY |
||
250 | || $month > DateDefinitions::DECEMBER |
||
251 | || $dom < 1 |
||
252 | || $dom > $monthLength |
||
253 | || $dow < DateDefinitions::SUNDAY |
||
254 | || $dow > DateDefinitions::SATURDAY |
||
255 | || $millis < 0 |
||
256 | || $millis >= DateDefinitions::MILLIS_PER_DAY |
||
257 | || $monthLength < 28 |
||
258 | || $monthLength > 31) { |
||
259 | throw new \InvalidArgumentException('One of the supplied parameters is out of range'); |
||
260 | } |
||
261 | |||
262 | if ($era == GregorianCalendar::BC) { |
||
263 | $year = -$year; |
||
264 | } |
||
265 | |||
266 | if ($year > $this->finalYear) { // [sic] >, not >=; see above |
||
267 | return $this->finalZone->getOffset($era, $year, $month, $dom, $dow, $millis, $monthLength); |
||
268 | } |
||
269 | |||
270 | // Compute local epoch seconds from input fields |
||
271 | $time = CalendarGrego::fieldsToDay($year, $month, $dom) * DateDefinitions::SECONDS_PER_DAY + floor($millis / DateDefinitions::MILLIS_PER_SECOND); |
||
272 | |||
273 | $transition = $this->findTransition($time, true); |
||
274 | return ($this->types[$transition['type']]['dstOffset'] + $this->types[$transition['type']]['rawOffset']) * DateDefinitions::MILLIS_PER_SECOND; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * TimeZone API. |
||
279 | * |
||
280 | * @see TimeZone::getOffsetRef() |
||
281 | * |
||
282 | * @author Dominik del Bondio <[email protected]> |
||
283 | * @author The ICU Project |
||
284 | * @since 0.11.0 |
||
285 | */ |
||
286 | public function getOffsetRef($date, $local, &$rawoff, &$dstoff) |
||
287 | { |
||
288 | // The check against finalMillis will suffice most of the time, except |
||
289 | // for the case in which finalMillis == DBL_MAX, date == DBL_MAX, |
||
290 | // and finalZone == 0. For this case we add "&& finalZone != 0". |
||
291 | if ($date >= $this->finalMillis && $this->finalZone !== null) { |
||
292 | $millis = 0; |
||
293 | $days = Toolkit::floorDivide($date, DateDefinitions::MILLIS_PER_DAY, $millis); |
||
294 | |||
295 | $year = 0; |
||
296 | $month = 0; |
||
297 | $dom = 0; |
||
298 | $dow = 0; |
||
299 | |||
300 | CalendarGrego::dayToFields($days, $year, $month, $dom, $dow); |
||
301 | |||
302 | $rawoff = $this->finalZone->getRawOffset(); |
||
303 | |||
304 | if (!$local) { |
||
305 | // Adjust from GMT to local |
||
306 | $date += $rawoff; |
||
307 | $days2 = Toolkit::floorDivide($date, DateDefinitions::MILLIS_PER_DAY, $millis); |
||
308 | if ($days2 != $days) { |
||
309 | CalendarGrego::dayToFields($days2, $year, $month, $dom, $dow); |
||
310 | } |
||
311 | } |
||
312 | |||
313 | $dstoff = $this->finalZone->getOffset(GregorianCalendar::AD, $year, $month, $dom, $dow, $millis) - $rawoff; |
||
314 | return; |
||
315 | } |
||
316 | |||
317 | $secs = floor($date / DateDefinitions::MILLIS_PER_SECOND); |
||
318 | $transition = $this->findTransition($secs, $local); |
||
319 | $rawoff = $this->types[$transition['type']]['rawOffset'] * DateDefinitions::MILLIS_PER_SECOND; |
||
320 | $dstoff = $this->types[$transition['type']]['dstOffset'] * DateDefinitions::MILLIS_PER_SECOND; |
||
321 | } |
||
322 | |||
323 | /** |
||
324 | * TimeZone API. |
||
325 | * |
||
326 | * @see TimeZone::setRawOffset() |
||
327 | * |
||
328 | * @author Dominik del Bondio <[email protected]> |
||
329 | * @author The ICU Project |
||
330 | * @since 0.11.0 |
||
331 | */ |
||
332 | public function setRawOffset($offsetMillis) |
||
333 | { |
||
334 | // We don't support this operation, since OlsonTimeZones are |
||
335 | // immutable (except for the ID, which is in the base class). |
||
336 | |||
337 | // Nothing to do! |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * TimeZone API. |
||
342 | * |
||
343 | * @see TimeZone::getRawOffset() |
||
344 | * |
||
345 | * @author Dominik del Bondio <[email protected]> |
||
346 | * @author The ICU Project |
||
347 | * @since 0.11.0 |
||
348 | */ |
||
349 | public function getRawOffset() |
||
350 | { |
||
351 | $raw = 0; |
||
352 | $dst = 0; |
||
353 | $this->getOffsetRef(Calendar::getNow(), false, $raw, $dst); |
||
354 | return $raw; |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Find the smallest i (in 0..transitionCount-1) such that time >= |
||
359 | * transition(i), where transition(i) is either the GMT or the local |
||
360 | * transition time, as specified by `local'. |
||
361 | * |
||
362 | * @param float $time epoch seconds, either GMT or local wall |
||
363 | * @param bool $local if TRUE, `time' is in local wall units, otherwise it |
||
364 | * is GMT |
||
365 | * |
||
366 | * @return int an index i, where 0 <= i < transitionCount, and |
||
367 | * transition(i) <= time < transition(i+1), or i == 0 if |
||
368 | * transitionCount == 0 or time < transition(0). |
||
369 | * |
||
370 | * @author Dominik del Bondio <[email protected]> |
||
371 | * @author The ICU Project |
||
372 | * @since 0.11.0 |
||
373 | */ |
||
374 | protected function findTransition($time, $local) |
||
375 | { |
||
376 | $i = 0; |
||
377 | |||
378 | if (count($this->transitions) > 0) { |
||
379 | // Linear search from the end is the fastest approach, since |
||
380 | // most lookups will happen at/near the end. |
||
381 | for ($i = count($this->transitions) - 1; $i > 0; --$i) { |
||
382 | $transition = $this->transitions[$i]; |
||
383 | if ($local) { |
||
384 | $prevType = $this->transitions[$i - 1]['type']; |
||
385 | $zoneOffsetPrev = $this->types[$prevType]['dstOffset'] + $this->types[$prevType]['rawOffset']; |
||
386 | $currType = $transition['type']; |
||
387 | $zoneOffsetCurr = $this->types[$currType]['dstOffset'] + $this->types[$currType]['rawOffset']; |
||
388 | |||
389 | // use the lowest offset ( == standard time ). as per tzregts.cpp which says: |
||
390 | |||
391 | /** |
||
392 | * @bug 4084933 |
||
393 | * The expected behavior of TimeZone around the boundaries is: |
||
394 | * (Assume transition time of 2:00 AM) |
||
395 | * day of onset 1:59 AM STD = display name 1:59 AM ST |
||
396 | * 2:00 AM STD = display name 3:00 AM DT |
||
397 | * day of end 0:59 AM STD = display name 1:59 AM DT |
||
398 | * 1:00 AM STD = display name 1:00 AM ST |
||
399 | */ |
||
400 | if ($zoneOffsetPrev < $zoneOffsetCurr) { |
||
401 | $transition['time'] += $zoneOffsetPrev; |
||
402 | } else { |
||
403 | $transition['time'] += $zoneOffsetCurr; |
||
404 | } |
||
405 | } |
||
406 | |||
407 | if ($time >= $transition['time']) { |
||
408 | break; |
||
409 | } |
||
410 | } |
||
411 | } |
||
412 | |||
413 | return $this->transitions[$i]; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * TimeZone API. |
||
418 | * |
||
419 | * @see TimeZone::useDaylightTime() |
||
420 | * |
||
421 | * @author Dominik del Bondio <[email protected]> |
||
422 | * @author The ICU Project |
||
423 | * @since 0.11.0 |
||
424 | */ |
||
425 | public function useDaylightTime() |
||
426 | { |
||
427 | // If DST was observed in 1942 (for example) but has never been |
||
428 | // observed from 1943 to the present, most clients will expect |
||
429 | // this method to return FALSE. This method determines whether |
||
430 | // DST is in use in the current year (at any point in the year) |
||
431 | // and returns TRUE if so. |
||
432 | |||
433 | $days = floor(Calendar::getNow() / DateDefinitions::MILLIS_PER_DAY); // epoch days |
||
434 | |||
435 | $year = 0; |
||
436 | $month = 0; |
||
437 | $dom = 0; |
||
438 | $dow = 0; |
||
439 | |||
440 | CalendarGrego::dayToFields($days, $year, $month, $dom, $dow); |
||
441 | |||
442 | if ($year > $this->finalYear) { // [sic] >, not >=; see above |
||
443 | if ($this->finalZone) { |
||
444 | return $this->finalZone->useDaylightTime(); |
||
445 | } else { |
||
446 | return true; |
||
447 | } |
||
448 | } |
||
449 | |||
450 | // Find start of this year, and start of next year |
||
451 | $start = (int) CalendarGrego::fieldsToDay($year, 0, 1) * DateDefinitions::SECONDS_PER_DAY; |
||
452 | $limit = (int) CalendarGrego::fieldsToDay($year + 1, 0, 1) * DateDefinitions::SECONDS_PER_DAY; |
||
453 | |||
454 | // Return TRUE if DST is observed at any time during the current year. |
||
455 | for ($i = 0, $transitionCount = count($this->transitions); $i < $transitionCount; ++$i) { |
||
456 | if ($this->transitions[$i]['time'] >= $limit) { |
||
457 | break; |
||
458 | } |
||
459 | if (($this->transitions[$i]['time'] >= $start && $this->types[$this->transitions[$i]['type']]['dstOffset'] != 0) || ($this->transitions[$i]['time'] > $start && $i > 0 && $this->types[$this->transitions[$i-1]['type']]['dstOffset'] != 0)) { |
||
460 | return true; |
||
461 | } |
||
462 | } |
||
463 | |||
464 | return false; |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * TimeZone API. |
||
469 | * |
||
470 | * @see TimeZone::getDSTSavings() |
||
471 | * |
||
472 | * @author Dominik del Bondio <[email protected]> |
||
473 | * @author The ICU Project |
||
474 | * @since 0.11.0 |
||
475 | */ |
||
476 | public function getDSTSavings() |
||
477 | { |
||
478 | if ($this->finalZone !== null) { |
||
479 | return $this->finalZone->getDSTSavings(); |
||
480 | } |
||
481 | return parent::getDSTSavings(); |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * TimeZone API. |
||
486 | * |
||
487 | * @see TimeZone::inDaylightTime() |
||
488 | * |
||
489 | * @author Dominik del Bondio <[email protected]> |
||
490 | * @author The ICU Project |
||
491 | * @since 0.11.0 |
||
492 | */ |
||
493 | public function inDaylightTime($date) |
||
494 | { |
||
495 | $raw = 0; |
||
496 | $dst = 0; |
||
497 | $this->getOffsetRef($date, false, $raw, $dst); |
||
498 | return $dst != 0; |
||
499 | } |
||
500 | } |
||
501 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: