fusonic /
webapp
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 | /* |
||
| 4 | * This file is part of the fusonic/webapp package. |
||
| 5 | * |
||
| 6 | * (c) Fusonic GmbH <[email protected]> |
||
| 7 | * |
||
| 8 | * For the full copyright and license information, please view the LICENSE |
||
| 9 | * file that was distributed with this source code. |
||
| 10 | */ |
||
| 11 | |||
| 12 | namespace Fusonic\WebApp; |
||
| 13 | |||
| 14 | use Fusonic\WebApp\Generators\ManifestGenerator; |
||
| 15 | use Fusonic\WebApp\Generators\TagGenerator; |
||
| 16 | use Fusonic\WebApp\Objects\Image; |
||
| 17 | |||
| 18 | /** |
||
| 19 | * Contains all data of a web application to create different assets and/or tags. |
||
| 20 | * |
||
| 21 | * @package Fusonic\WebApp |
||
| 22 | * |
||
| 23 | * @see ManifestGenerator |
||
| 24 | * @see TagGenerator |
||
| 25 | */ |
||
| 26 | final class AppConfiguration |
||
| 27 | { |
||
| 28 | const DIRECTION_LEFT_TO_RIGHT = "ltr"; |
||
| 29 | const DIRECTION_RIGHT_TO_LEFT = "rtl"; |
||
| 30 | const DIRECTION_AUTO = "auto"; |
||
| 31 | |||
| 32 | const DISPLAY_FULLSCREEN = "fullscreen"; |
||
| 33 | const DISPLAY_STANDALONE = "standalone"; |
||
| 34 | const DISPLAY_MINIMAL_UI = "minimal-ui"; |
||
| 35 | const DISPLAY_BROWSER = "browser"; |
||
| 36 | |||
| 37 | const ORIENTATION_ANY = "any"; |
||
| 38 | const ORIENTATION_NATURAL = "natural"; |
||
| 39 | const ORIENTATION_LANDSCAPE = "landscape"; |
||
| 40 | const ORIENTATION_LANDSCAPE_PRIMARY = "landscape-primary"; |
||
| 41 | const ORIENTATION_LANDSCAPE_SECONDARY = "landscape-secondary"; |
||
| 42 | const ORIENTATION_PORTRAIT = "portrait"; |
||
| 43 | const ORIENTATION_PORTRAIT_PRIMARY = "portrait-primary"; |
||
| 44 | const ORIENTATION_PORTRAIT_SECONDARY = "portrait-secondary"; |
||
| 45 | |||
| 46 | const PLATFORM_ANDROID = "android"; |
||
| 47 | const PLATFORM_IOS = "ios"; |
||
| 48 | const PLATFORM_WEB = "web"; |
||
| 49 | |||
| 50 | private $backgroundColor; |
||
| 51 | private $description; |
||
| 52 | private $direction; |
||
| 53 | private $display; |
||
| 54 | private $icons = [ ]; |
||
| 55 | private $language; |
||
| 56 | private $name; |
||
| 57 | private $orientation; |
||
| 58 | private $scope; |
||
| 59 | private $screenshots = [ ]; |
||
| 60 | private $shortName; |
||
| 61 | private $startUrl; |
||
| 62 | private $themeColor; |
||
| 63 | |||
| 64 | private $manifestUrl; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Returns the manifest URL. |
||
| 68 | * |
||
| 69 | * @return string |
||
| 70 | */ |
||
| 71 | 1 | public function getManifestUrl() |
|
| 72 | { |
||
| 73 | 1 | if ($this->manifestUrl === null) { |
|
| 74 | throw new \LogicException("Manifest URL cannot be null."); |
||
| 75 | } |
||
| 76 | |||
| 77 | 1 | return $this->manifestUrl; |
|
| 78 | } |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Sets the manifest URL. You MUST set one for proper deployment. |
||
| 82 | * |
||
| 83 | * @param string $url |
||
| 84 | * |
||
| 85 | * @return AppConfiguration |
||
| 86 | */ |
||
| 87 | 1 | public function setManifestUrl($url) |
|
| 88 | { |
||
| 89 | 1 | $this->manifestUrl = $url; |
|
| 90 | 1 | return $this; |
|
| 91 | } |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Returns the expected background color for the web application. |
||
| 95 | * |
||
| 96 | * @return string|null |
||
| 97 | */ |
||
| 98 | 2 | public function getBackgroundColor() |
|
| 99 | { |
||
| 100 | 2 | return $this->backgroundColor; |
|
| 101 | } |
||
| 102 | |||
| 103 | /** |
||
| 104 | * Sets the expected background color for the web application. Will also be used by Chrome 47 and later to |
||
| 105 | * auto-generate a splash screen. |
||
| 106 | * |
||
| 107 | * <p> |
||
| 108 | * This value repeats what is already available in the application stylesheet, but can be used by browsers to draw |
||
| 109 | * the background color of a web application when the manifest is available before the style sheet has loaded. |
||
| 110 | * |
||
| 111 | * <p> |
||
| 112 | * This creates a smooth transition between launching the web application and loading the application's content. |
||
| 113 | * |
||
| 114 | * @param string $backgroundColor |
||
| 115 | * |
||
| 116 | * @return AppConfiguration |
||
| 117 | * |
||
| 118 | * @see https://www.w3.org/TR/appmanifest/#background_color-member |
||
| 119 | */ |
||
| 120 | 3 | public function setBackgroundColor($backgroundColor) |
|
| 121 | { |
||
| 122 | 3 | $this->backgroundColor = $backgroundColor; |
|
| 123 | 3 | return $this; |
|
| 124 | } |
||
| 125 | |||
| 126 | /** |
||
| 127 | * Returns the general description of what the web application does. |
||
| 128 | * |
||
| 129 | * @return string|null |
||
| 130 | */ |
||
| 131 | 2 | public function getDescription() |
|
| 132 | { |
||
| 133 | 2 | return $this->description; |
|
| 134 | } |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Sets a general description of what the web application does. |
||
| 138 | * |
||
| 139 | * @param string $description |
||
| 140 | * |
||
| 141 | * @return AppConfiguration |
||
| 142 | * |
||
| 143 | * @see https://www.w3.org/TR/appmanifest/#description-member |
||
| 144 | */ |
||
| 145 | 3 | public function setDescription($description) |
|
| 146 | { |
||
| 147 | 3 | $this->description = $description; |
|
| 148 | 3 | return $this; |
|
| 149 | } |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Returns the primary text direction for the {@link $name}, {@link $shortName}, and {@link $description} members. |
||
| 153 | * |
||
| 154 | * @return string|null |
||
| 155 | */ |
||
| 156 | 1 | public function getDirection() |
|
| 157 | { |
||
| 158 | 1 | return $this->direction; |
|
| 159 | } |
||
| 160 | |||
| 161 | /** |
||
| 162 | * Sets the primary text direction for the {@link $name}, {@link $shortName}, and {@link $description} members. |
||
| 163 | * |
||
| 164 | * @param string $direction One of AppConfiguration::DIRECTION_* constants. |
||
| 165 | * |
||
| 166 | * @return AppConfiguration |
||
| 167 | * |
||
| 168 | * @see https://www.w3.org/TR/appmanifest/#dir-member |
||
| 169 | */ |
||
| 170 | 3 | View Code Duplication | public function setDirection($direction) |
| 171 | { |
||
| 172 | 3 | if (!in_array( |
|
| 173 | 3 | $direction, |
|
| 174 | [ |
||
| 175 | 3 | self::DIRECTION_LEFT_TO_RIGHT, |
|
| 176 | 3 | self::DIRECTION_RIGHT_TO_LEFT, |
|
| 177 | self::DIRECTION_AUTO |
||
| 178 | 3 | ] |
|
| 179 | 3 | )) { |
|
| 180 | throw new \InvalidArgumentException("Use one of AppConfiguration::DIRECTION_* constants."); |
||
| 181 | } |
||
| 182 | |||
| 183 | 3 | $this->direction = $direction; |
|
| 184 | 3 | return $this; |
|
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Returns the preferred display mode. |
||
| 189 | * |
||
| 190 | * @return string|null |
||
| 191 | */ |
||
| 192 | 3 | public function getDisplay() |
|
| 193 | { |
||
| 194 | 3 | return $this->display; |
|
| 195 | } |
||
| 196 | |||
| 197 | /** |
||
| 198 | * Sets the preferred display mode. |
||
| 199 | * |
||
| 200 | * @param string $display One of AppConfiguration::DISPLAY_* constants. |
||
| 201 | * |
||
| 202 | * @return AppConfiguration |
||
| 203 | * |
||
| 204 | * @see https://www.w3.org/TR/appmanifest/#display-member |
||
| 205 | */ |
||
| 206 | 3 | View Code Duplication | public function setDisplay($display) |
| 207 | { |
||
| 208 | 3 | if (!in_array( |
|
| 209 | 3 | $display, |
|
| 210 | [ |
||
| 211 | 3 | self::DISPLAY_FULLSCREEN, |
|
| 212 | 3 | self::DISPLAY_MINIMAL_UI, |
|
| 213 | 3 | self::DISPLAY_STANDALONE, |
|
| 214 | self::DISPLAY_BROWSER |
||
| 215 | 3 | ] |
|
| 216 | 3 | )) { |
|
| 217 | throw new \InvalidArgumentException("Use one of AppConfiguration::DISPLAY_* constants."); |
||
| 218 | } |
||
| 219 | |||
| 220 | 3 | $this->display = $display; |
|
| 221 | 3 | return $this; |
|
| 222 | } |
||
| 223 | |||
| 224 | /** |
||
| 225 | * Returns an array of all application icons. |
||
| 226 | * |
||
| 227 | * @return Image[] |
||
| 228 | */ |
||
| 229 | 3 | public function getIcons() |
|
| 230 | { |
||
| 231 | 3 | return $this->icons; |
|
| 232 | } |
||
| 233 | |||
| 234 | /** |
||
| 235 | * Adds an application icon. |
||
| 236 | * |
||
| 237 | * @param Image $icon |
||
| 238 | * |
||
| 239 | * @return AppConfiguration |
||
| 240 | * |
||
| 241 | * @see https://www.w3.org/TR/appmanifest/#icons-member |
||
| 242 | */ |
||
| 243 | 3 | public function addIcon(Image $icon) |
|
| 244 | { |
||
| 245 | 3 | $this->icons[] = $icon; |
|
| 246 | 3 | return $this; |
|
| 247 | } |
||
| 248 | |||
| 249 | /** |
||
| 250 | * Returns the application's language. |
||
| 251 | * |
||
| 252 | * @return string|null |
||
| 253 | */ |
||
| 254 | 2 | public function getLanguage() |
|
| 255 | { |
||
| 256 | 2 | return $this->language; |
|
| 257 | } |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Sets the application's language. Must be a RFC5646 compliant string. |
||
| 261 | * |
||
| 262 | * @param string $language |
||
| 263 | * |
||
| 264 | * @return AppConfiguration |
||
| 265 | * |
||
| 266 | * @see https://www.w3.org/TR/appmanifest/#lang-member |
||
| 267 | */ |
||
| 268 | 3 | public function setLanguage($language) |
|
| 269 | { |
||
| 270 | 3 | $this->language = $language; |
|
| 271 | 3 | return $this; |
|
| 272 | } |
||
| 273 | |||
| 274 | /** |
||
| 275 | * Returns the application's name. |
||
| 276 | * |
||
| 277 | * @return string|null |
||
| 278 | */ |
||
| 279 | 2 | public function getName() |
|
| 280 | { |
||
| 281 | 2 | return $this->name; |
|
| 282 | } |
||
| 283 | |||
| 284 | /** |
||
| 285 | * Sets the application's name. |
||
| 286 | * |
||
| 287 | * @param string $name |
||
| 288 | * |
||
| 289 | * @return AppConfiguration |
||
| 290 | * |
||
| 291 | * @see https://www.w3.org/TR/appmanifest/#name-member |
||
| 292 | */ |
||
| 293 | 3 | public function setName($name) |
|
| 294 | { |
||
| 295 | 3 | $this->name = $name; |
|
| 296 | 3 | return $this; |
|
| 297 | } |
||
| 298 | |||
| 299 | /** |
||
| 300 | * Returns the default device orientation. |
||
| 301 | * |
||
| 302 | * @return string|null |
||
| 303 | */ |
||
| 304 | 2 | public function getOrientation() |
|
| 305 | { |
||
| 306 | 2 | return $this->orientation; |
|
| 307 | } |
||
| 308 | |||
| 309 | /** |
||
| 310 | * Sets the default device orientation.. |
||
| 311 | * |
||
| 312 | * @param string $orientation One of AppConfiguration::ORIENTATION_* constants. |
||
| 313 | * |
||
| 314 | * @return AppConfiguration |
||
| 315 | * |
||
| 316 | * @see https://www.w3.org/TR/appmanifest/#orientation-member |
||
| 317 | */ |
||
| 318 | 3 | public function setOrientation($orientation) |
|
| 319 | { |
||
| 320 | 3 | if (!in_array( |
|
| 321 | 3 | $orientation, |
|
| 322 | [ |
||
| 323 | 3 | self::ORIENTATION_ANY, |
|
| 324 | 3 | self::ORIENTATION_NATURAL, |
|
| 325 | 3 | self::ORIENTATION_LANDSCAPE, |
|
| 326 | 3 | self::ORIENTATION_LANDSCAPE_PRIMARY, |
|
| 327 | 3 | self::ORIENTATION_LANDSCAPE_SECONDARY, |
|
| 328 | 3 | self::ORIENTATION_PORTRAIT, |
|
| 329 | 3 | self::ORIENTATION_PORTRAIT_PRIMARY, |
|
| 330 | 3 | self::ORIENTATION_PORTRAIT_SECONDARY, |
|
| 331 | ] |
||
| 332 | 3 | )) { |
|
| 333 | throw new \InvalidArgumentException("Use one of AppConfiguration::ORIENTATION_* constants."); |
||
| 334 | } |
||
| 335 | |||
| 336 | 3 | $this->orientation = $orientation; |
|
| 337 | 3 | return $this; |
|
| 338 | } |
||
| 339 | |||
| 340 | /** |
||
| 341 | * Returns the application's navigation scope. |
||
| 342 | * |
||
| 343 | * @return string|null |
||
| 344 | */ |
||
| 345 | 2 | public function getScope() |
|
| 346 | { |
||
| 347 | 2 | return $this->scope; |
|
| 348 | } |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Sets the application's navigation scope. |
||
| 352 | * |
||
| 353 | * <p> |
||
| 354 | * This basically restricts what web pages can be viewed while the manifest is applied. If the user navigates the |
||
| 355 | * application outside the scope, it returns to being a normal web page. |
||
| 356 | * |
||
| 357 | * @param string $scope |
||
| 358 | * |
||
| 359 | * @return AppConfiguration |
||
| 360 | * |
||
| 361 | * @see https://www.w3.org/TR/appmanifest/#scope-member |
||
| 362 | */ |
||
| 363 | 3 | public function setScope($scope) |
|
| 364 | { |
||
| 365 | 3 | $this->scope = $scope; |
|
| 366 | 3 | return $this; |
|
| 367 | } |
||
| 368 | |||
| 369 | /** |
||
| 370 | * Returns an array of all application screenshots. |
||
| 371 | * |
||
| 372 | * @return Image[] |
||
| 373 | */ |
||
| 374 | 2 | public function getScreenshots() |
|
| 375 | { |
||
| 376 | 2 | return $this->screenshots; |
|
| 377 | } |
||
| 378 | |||
| 379 | /** |
||
| 380 | * Adds an application screenshot. |
||
| 381 | * |
||
| 382 | * @param Image $screenshot |
||
| 383 | * |
||
| 384 | * @return AppConfiguration |
||
| 385 | * |
||
| 386 | * @see https://www.w3.org/TR/appmanifest/#screenshots-member |
||
| 387 | */ |
||
| 388 | 3 | public function addScreenshot(Image $screenshot) |
|
| 389 | { |
||
| 390 | 3 | $this->screenshots[] = $screenshot; |
|
| 391 | 3 | return $this; |
|
| 392 | } |
||
| 393 | |||
| 394 | /** |
||
| 395 | * Returns the application's short name. |
||
| 396 | * |
||
| 397 | * @return string|null |
||
| 398 | */ |
||
| 399 | 3 | public function getShortName() |
|
| 400 | { |
||
| 401 | 3 | return $this->shortName; |
|
| 402 | } |
||
| 403 | |||
| 404 | /** |
||
| 405 | * Sets the application's short name. |
||
| 406 | * |
||
| 407 | * @param string $shortName |
||
| 408 | * |
||
| 409 | * @return AppConfiguration |
||
| 410 | * |
||
| 411 | * @see https://www.w3.org/TR/appmanifest/#short_name-member |
||
| 412 | */ |
||
| 413 | 3 | public function setShortName($shortName) |
|
| 414 | { |
||
| 415 | 3 | $this->shortName = $shortName; |
|
| 416 | 3 | return $this; |
|
| 417 | } |
||
| 418 | |||
| 419 | /** |
||
| 420 | * Returns the application's start URL. |
||
| 421 | * |
||
| 422 | * @return string|null |
||
| 423 | */ |
||
| 424 | 3 | public function getStartUrl() |
|
| 425 | { |
||
| 426 | 3 | return $this->startUrl; |
|
| 427 | } |
||
| 428 | |||
| 429 | /** |
||
| 430 | * Sets the application's start URL. |
||
| 431 | * |
||
| 432 | * @param string $startUrl |
||
| 433 | * |
||
| 434 | * @return AppConfiguration |
||
| 435 | * |
||
| 436 | * @see https://www.w3.org/TR/appmanifest/#start_url-member |
||
| 437 | */ |
||
| 438 | 3 | public function setStartUrl($startUrl) |
|
| 439 | { |
||
| 440 | 3 | $this->startUrl = $startUrl; |
|
| 441 | 3 | return $this; |
|
| 442 | } |
||
| 443 | |||
| 444 | /** |
||
| 445 | * Returns the theme color. |
||
| 446 | * |
||
| 447 | * @return string|null |
||
| 448 | */ |
||
| 449 | 3 | public function getThemeColor() |
|
| 450 | { |
||
| 451 | 3 | return $this->themeColor; |
|
| 452 | } |
||
| 453 | |||
| 454 | /** |
||
| 455 | * Sets the theme color. Will be used by Android's task switcher, for example. |
||
| 456 | * |
||
| 457 | * @param string $color |
||
| 458 | * |
||
| 459 | * @return AppConfiguration |
||
| 460 | * |
||
| 461 | * @see https://www.w3.org/TR/appmanifest/#theme_color-member |
||
| 462 | */ |
||
| 463 | 3 | public function setThemeColor($color) |
|
| 464 | { |
||
| 465 | 3 | $this->themeColor = $color; |
|
| 466 | 3 | return $this; |
|
| 467 | } |
||
| 468 | |||
| 469 | /** |
||
| 470 | * Creates an instance of the {@link AppConfiguration} class based on the values in the provided manifest file. Use |
||
| 471 | * the {@link fromManifest} method to use a JSON string as source. |
||
| 472 | * |
||
| 473 | * @param string $path Path to a file containing an application manifest compatible |
||
| 474 | * with the Web App Manifest specification. |
||
| 475 | * |
||
| 476 | * @return AppConfiguration |
||
| 477 | * |
||
| 478 | * @see https://www.w3.org/TR/appmanifest/ |
||
| 479 | */ |
||
| 480 | 2 | public static function fromManifestFile($path) |
|
| 481 | { |
||
| 482 | 2 | return self::fromManifest(file_get_contents($path)); |
|
| 483 | } |
||
| 484 | |||
| 485 | /** |
||
| 486 | * Creates an instance of the {@link AppConfiguration} class based on the values in the provided JSON string. Use |
||
| 487 | * the {@link fromManifestFile} method to use a file as source. |
||
| 488 | * |
||
| 489 | * @param string $json A JSON string that is compatible with the Web App Manifest |
||
| 490 | * specification. |
||
| 491 | * |
||
| 492 | * @return AppConfiguration |
||
| 493 | * |
||
| 494 | * @see https://www.w3.org/TR/appmanifest/ |
||
| 495 | */ |
||
| 496 | 3 | public static function fromManifest($json) |
|
| 497 | { |
||
| 498 | 3 | $app = new AppConfiguration(); |
|
| 499 | 3 | $data = json_decode($json, true); |
|
| 500 | |||
| 501 | 3 | if (isset($data["background_color"])) { |
|
| 502 | 3 | $app->setBackgroundColor($data["background_color"]); |
|
| 503 | 3 | } |
|
| 504 | |||
| 505 | 3 | if (isset($data["description"])) { |
|
| 506 | 3 | $app->setDescription($data["description"]); |
|
| 507 | 3 | } |
|
| 508 | |||
| 509 | 3 | if (isset($data["dir"])) { |
|
| 510 | 3 | $app->setDirection($data["dir"]); |
|
| 511 | 3 | } |
|
| 512 | |||
| 513 | 3 | if (isset($data["display"])) { |
|
| 514 | 3 | $app->setDisplay($data["display"]); |
|
| 515 | 3 | } |
|
| 516 | |||
| 517 | 3 | if (isset($data["icons"])) { |
|
| 518 | 3 | foreach ($data["icons"] as $icon) { |
|
| 519 | 3 | $app->addIcon(self::imageFromData($icon)); |
|
| 520 | 3 | } |
|
| 521 | 3 | } |
|
| 522 | |||
| 523 | 3 | if (isset($data["lang"])) { |
|
| 524 | 3 | $app->setLanguage($data["lang"]); |
|
| 525 | 3 | } |
|
| 526 | |||
| 527 | 3 | if (isset($data["name"])) { |
|
| 528 | 3 | $app->setName($data["name"]); |
|
| 529 | 3 | } |
|
| 530 | |||
| 531 | 3 | if (isset($data["orientation"])) { |
|
| 532 | 3 | $app->setOrientation($data["orientation"]); |
|
| 533 | 3 | } |
|
| 534 | |||
| 535 | 3 | if (isset($data["scope"])) { |
|
| 536 | 3 | $app->setScope($data["scope"]); |
|
| 537 | 3 | } |
|
| 538 | |||
| 539 | 3 | if (isset($data["screenshots"])) { |
|
| 540 | 3 | foreach ($data["screenshots"] as $screenshot) { |
|
| 541 | 3 | $app->addScreenshot(self::imageFromData($screenshot)); |
|
| 542 | 3 | } |
|
| 543 | 3 | } |
|
| 544 | |||
| 545 | 3 | if (isset($data["short_name"])) { |
|
| 546 | 3 | $app->setShortName($data["short_name"]); |
|
| 547 | 3 | } |
|
| 548 | |||
| 549 | 3 | if (isset($data["start_url"])) { |
|
| 550 | 3 | $app->setStartUrl($data["start_url"]); |
|
| 551 | 3 | } |
|
| 552 | |||
| 553 | 3 | if (isset($data["theme_color"])) { |
|
| 554 | 3 | $app->setThemeColor($data["theme_color"]); |
|
| 555 | 3 | } |
|
| 556 | |||
| 557 | 3 | return $app; |
|
| 558 | } |
||
| 559 | |||
| 560 | 3 | private static function imageFromData(array $data) |
|
| 561 | { |
||
| 562 | 3 | $image = new Image(); |
|
| 563 | |||
| 564 | 3 | if (isset($data["src"])) { |
|
| 565 | 3 | $image->setSrc($data["src"]); |
|
| 566 | 3 | } |
|
| 567 | |||
| 568 | 3 | if (isset($data["type"])) { |
|
| 569 | 3 | $image->setType($data["type"]); |
|
| 570 | 3 | } |
|
| 571 | |||
| 572 | 3 | if (isset($data["sizes"])) { |
|
| 573 | 3 | $sizes = []; |
|
| 574 | 3 | if (preg_match_all("/(\d+)x(\d+)/", $data["sizes"], $sizes)) { |
|
| 575 | 3 | for ($i = 0; $i < count($sizes[0]); $i++) { |
|
|
0 ignored issues
–
show
|
|||
| 576 | 3 | $image->addSize($sizes[1][$i], $sizes[2][$i]); |
|
| 577 | 3 | } |
|
| 578 | 3 | } |
|
| 579 | 3 | } |
|
| 580 | |||
| 581 | 3 | return $image; |
|
| 582 | } |
||
| 583 | } |
||
| 584 |
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: