Skip to main content
4 of 4
update explanation to include citation and reference to php docs

The feedback below won't likely prevent time out errors, but hopefully will clean up the code.

###Description-code mismatch

The narrative in your post states:

Basically this is what it does :

  • checks if the images exist. If it does it generates the <picture> element.

But the first few lines of the function are:

public static function picturebuilder($imgUrl, $imageAlt, $params) {
    // check if the image exists
    if (!file_exists($imgUrl)) {
      echo "<script>console.log( 'Cannot find : " . $imgUrl . "' );</script>";
      return false;
    }

So the code appears to actually add a JavaScript console.log() call on the client side, instead of adding a <picture> element...

###Outputting JavaScript with echo If you are going to add JavaScript to the client side and echo the image path (i.e. $imgUrl) it would be wise to sanitize that value so it won't break the JavaScript. One technique for that is to use json_encode() or htmlspecialchars().

echo "<script>console.log( 'Cannot find : " . htmlspecialchars($imgUrl) . "' );</script>";

You didn't specify which file system the files are coming from, but some systems allow single-quotes and semi-colons in file names (e.g. the MS NT file system - refer to this answer for a summary).

So it may seem unlikely but possibly that a filename like the following would be passed:

$imgUrl = "photo1';compressed.png";

See how well that works with the echo statement from your code in this playground example. In the browser console, there should be an error:

Uncaught SyntaxError: missing ) after argument list

###incrementing a counter variable inside a foreach The foreach statement has "two syntaxes"1 and because the array indexes of $thumbWidths are numeric, the second one can be used to have the value of $i updated automatically (i.e. to have each numeric index assigned , starting at 0), reducing the initial assignment of the counter variable (i.e. $i = 0;) and updating the counter value at the end of each block (i.e. $i++;).

foreach (array_expression as $key => $value)

So blocks like this:

$i = 0;
$thumbPaths = array();
foreach ($thumbWidths as $thumbWidth) {
  $thumbHeight = $thumbHeights[$i];
  $thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
  array_push($thumbPaths,$thumbPath);
  $i++;
}

Can be simplified like so:

$thumbPaths = array();
foreach ($thumbWidths as $i => $thumbWidth) {
  $thumbHeight = $thumbHeights[$i];
  $thumbPath = $thumbDir . '/' . $imgName . '-' . $thumbWidth . 'x' . $thumbHeight . 'q' . $thumbQuality . $imgExtension;
  array_push($thumbPaths,$thumbPath);
}

And array_map() could also allow it to be simplified even further, though the variables outside the foreach loop would have to be imported into the callback function with the use statement, which might seem a bit wonky:

$prefix = $thumbDir . '/' . $imgName . '-';
$suffix = 'q' . $thumbQuality . $imgExtension
$thumbPaths = array_map(function($thumbWidth, $i) use ($thumbHeights, $prefix, $suffix) {
    $thumbHeight = $thumbHeights[$i];
    return $prefix . $thumbWidth . 'x' . $thumbHeight . $suffix;
}, $thumbWidths, array_keys($thumbWidths));

###Repeated code when writing images The code in the if-else blocks near the end is very identical... the only thing that changes is if $crop evaluates to true then there is a call to cropThumbnailImage(), otherwise resizeImage() is called. Outside of that, the rest of the code appears identical:

if($crop) {
    foreach ($thumbWidths as $thumbWidth) {
      $imagick = new imagick($imgUrl);
      $thumbHeight = $thumbHeights[$i];
      $imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
      $imagick->setImageCompressionQuality($thumbQuality);
      $imagick->writeImage($thumbPaths[$i]);
      $imagick->clear();
      $imagick->destroy();
      $i++;
    }
  } else {
    foreach ($thumbWidths as $thumbWidth) {
      $imagick = new imagick($imgUrl);
      $thumbHeight = $thumbHeights[$i];
      $imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
      $imagick->setImageCompressionQuality($thumbQuality);
      $imagick->writeImage($thumbPaths[$i]);
      $imagick->clear();
      $imagick->destroy();
      $i++;
    }
  }

So that could be simplified to the following (also uses the numerical-index array syntax - see above):

foreach ($thumbWidths as $i => $thumbWidth) {
    $imagick = new imagick($imgUrl);
    $thumbHeight = $thumbHeights[$i];
    if ($crop) {
        $imagick->cropThumbnailImage($thumbWidth,$thumbHeight);
    }
    else {
        $imagick->resizeImage($thumbWidth,$thumbHeight,imagick::FILTER_LANCZOS, 1, true);
    }
    $imagick->setImageCompressionQuality($thumbQuality);
    $imagick->writeImage($thumbPaths[$i]);
    $imagick->clear();
    $imagick->destroy();
}