Reputation: 85
I'm having this strange issue where when certain conditions are met my PHP code is run twice. My code adds a watermark to a JPEG image (done in PHP to allow me to change the watermark quickly if necessary), and resized if requested. To speed up requests the processed images are cached. Whenever the image is loaded I'm incrementing a view counter, however when the following happens the counter is increased by 2:
header()
call runs the script as expectedimagecreatefromjpeg()
is called and the image is resized - when these lines are commented out the script runs normally. The script also runs normally if the image is not resized.Here's my code:
<?php
require_once("../config.php");
if (empty($_GET['photoid'])) {
header("Location: /photos");
die();
}
$photoId = intval($_GET['photoid']);
$photo = getPhotoData($photoId);
if ($photo == null) {
http_response_code(404);
echo "That photo doesn't exist.";
} else {
$filename = $photo['photo_filename'];
$largePath = "large/";
$cachePath = $largePath . "view_cache/";
$cache = false;
if (!isset($_GET['admin']) && !isset($_GET['thumb']) && !isset($_GET['tile'])) {
incrementPhotoViewCount($photoId);
}
if (isset($_GET['height'])) {
list($originalWidth, $originalHeight) = getimagesize($largePath . $photo['photo_filename']);
$height = min(intval($_GET['height']), $originalHeight);
if (file_exists($cachePath . $height . "h" . $filename)) {
$im = imagecreatefromjpeg($cachePath . $height . "h" . $filename);
$cache = true;
} else {
$im = resizeImage($largePath . $photo['photo_filename'], $originalWidth, $height);
}
} else if (isset($_GET['width'])) {
list($originalWidth, $originalHeight) = getimagesize($largePath . $photo['photo_filename']);
$width = min(intval($_GET['width']), $originalWidth);
if (file_exists($cachePath . $width . "w" . $filename)) {
$im = imagecreatefromjpeg($cachePath . $width . "w" . $filename);
$cache = true;
} else {
$im = resizeImage($largePath . $photo['photo_filename'], $width, $originalHeight);
}
} else {
if (file_exists($cachePath . $filename)) {
$im = imagecreatefromjpeg($cachePath . $filename);
$cache = true;
} else {
$im = imagecreatefromjpeg($largePath . $photo['photo_filename']);
}
}
if (!$cache && ((!isset($height) || $height > 400) && (!isset($width) || $width > 350))) {
$watermark = imagecreatefrompng("../images/watermark.png");
//Preserve original watermark transparency
imagealphablending($watermark, true); // setting alpha blending on
imagesavealpha($watermark, true); // save alphablending setting (important)
//Set the margins for the watermark and get the height/width of the stamp image
$marginLeft = 20;
$marginBottom = 20;
$sx = imagesx($watermark);
$sy = imagesy($watermark);
//Merge the stamp onto our photo
imagecopy($im, $watermark, $marginLeft, imagesy($im) - $sy - $marginBottom, 0, 0, $sx, $sy);
}
//Output the image and free memory
header("Content-Type: image/jpeg");
imagejpeg($im);
if (!$cache) {
if (isset($_GET['height'])) {
imagejpeg($im, $cachePath . $height . "h" . $filename);
} else if (isset($_GET['width'])) {
imagejpeg($im, $cachePath . $width . "w" . $filename);
} else {
imagejpeg($im, $cachePath . $filename);
}
}
imagedestroy($im);
}
function resizeImage($file, $w, $h, $crop = false) {
list($width, $height) = getimagesize($file);
$r = $width / $height;
if ($crop) {
if ($width > $height) {
$width = ceil($width-($width*abs($r-$w/$h)));
} else {
$height = ceil($height-($height*abs($r-$w/$h)));
}
$newwidth = $w;
$newheight = $h;
} else {
if ($w/$h > $r) {
$newwidth = $h*$r;
$newheight = $h;
} else {
$newheight = $w/$r;
$newwidth = $w;
}
}
$src = imagecreatefromjpeg($file);
$dst = imagecreatetruecolor($newwidth, $newheight);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
return $dst;
}
Here's the code that updates the view counter:
function incrementPhotoViewCount($photoId) {
$photoId = intval($photoId);
if (!($stmt = $GLOBALS['mysqli']->prepare("UPDATE `Photo` SET `view_count` = `view_count` + 1 WHERE `photo_id` = ?"))) {
error_log("Prepare failed: (" . $GLOBALS['mysqli']->errno . ") " . $GLOBALS['mysqli']->error);
return false;
}
if (!$stmt->bind_param("i", $photoId)) {
error_log("Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error);
return false;
}
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
return false;
}
}
What's going on here?
Upvotes: 0
Views: 149
Reputation: 85
Some extra late-night Googling answered my question - turns out Firefox has a bug which causes it to load dynamically generated images twice when loaded directly. It's fine when loaded through an <img>
tag, and all other browsers behave normally. Something to look at for anyone else having this issue :)
Upvotes: 1