PHPMailer addStringEmbeddedImage and adding the same image more than once - php

So in PHPmailer you can add a 64base coded image to the mail's body if you use addStringEmbeddedImage and in the data part you base64_decode the image. Ex:
$mail->addStringEmbeddedImage(base64_decode($str), "img_".$i, "img_".$i,"base64",$type);
I get the images from my text editor in base64 form and then replace the image with the respective container
<img src=\"cid:img_".$i."\" ".$height. " " .$width. ">"
And it works fine but for some reason, as soon as I add an image more than one time, it doesn't matter if its the very next image or first and last one, the mail will just save(?) the first image. Is not that it doesn't show it because in the original mail you can see that there's only 1 container specified in it.
--boundary
Content-Type: image/png; name="img_1"
Content-Transfer-Encoding: base64
Content-ID: <img_1>
Content-Disposition: inline; filename="img_1"
As you can see, each image has a different id (which is the order they are in the email) and the only way it can tell it is the same image is by the decoded base64 image so i really dont know why this only happens when its the same image. I could add img1----img2----img1----img3 and it will show img1 ---- img2---- |emptycontainer|---- img3
Edit: So for reference, this is the while I use to extract all the images
//$body of the mail, all the images i want to replace have that alt"" at the start
while(strstr($body, "<img alt")){
$i++;
$start= strpos($body, "<img alt");
$end= strpos($body,">",$start);
$str = substr($body,$start,$end-$start);
$height = "";
$width = "";
if (strstr($str, "height:")){
$ini = strpos($str, "height:")+7;
$fin = strpos($str,";",$ini);
$height = "height= \"".substr($str,$ini,$fin-$ini-2)."\"";
}
if (strstr($str, "width:")){
$ini = strpos($str, "width:")+6;
$fin = strpos($str,"\"",$ini);
$width = "width= \"".substr($str,$ini,$fin-$ini-2)."\"";
}
//here i replace the whole image with a container
$body= substr_replace($body, "<img src=\"cid:img_".$i."\" ".$height. " " .$width. ">", $start,$end-$start+1);
//get the type after data:
$start= strpos($str, "data:");
$end= strpos($str,";",$start);
$type= substr($str, $start+5, $end-$start-5);
//and this is where i get the base64 string
$start= strpos($str, "base64,");
$end= strpos($str,"\"",$start);
$str = substr($str, $start+7, $end-$start-7);
$mail->addStringEmbeddedImage(base64_decode($str), "img_".$i, "img_".$i,"base64",$type);
}
I appreciate any help and thanks for reading

I can see why you would use the same image more than one in a message, but why would you attach the same image more than once to achieve that? Much of the point of cid values is that they allow you to reference the same image from multiple places, so if say you have a logo image that appears in both header and footer, you can attach it once and reference it from both places, reducing message size. I suspect your issue is that you're trying to work around this and failing by attaching the same image data with two cid values, but PHPMailer is noticing the data is the same and not doing the second attachment, leaving your second cid pointing at nothing. You can fix it by using the same cid value for both image tags.
This should have the problem you mention:
$img = base64_decode($str);
$mail->addStringEmbeddedImage($img, "img_1", "img_1", "base64", $type);
$mail->addStringEmbeddedImage($img, "img_2", "img_2", "base64", $type);
<img src="cid:img_1">
<img src="cid:img_2">
This should work:
$img = base64_decode($str);
$mail->addStringEmbeddedImage($img, "img_1", "img_1", "base64", $type);
<img src="cid:img_1">
<img src="cid:img_1">
The code calculates an SHA256 hash of the content and uses that to check whether they are the same.

Related

jpeg rotation using imagerotate

I have a database which includes a table of jpeg photo data. This data has been sent to the database from an iPad app and can be displayed in a webpage using the following:
$photo_query = "SELECT photoID, photoData FROM tblPhotos;";
$resultPhotos = mysqli_query($connect, $photo_query);
while($rowPhotos = mysqli_fetch_array($resultPhotos)) { ?>
<div id="photo"> <?php
echo '<img src="data:image/jpeg;base64,' . base64_encode($row['photoData']) .'"/>';
</div>
}
This works fine and the image displays correctly.
I am now looking to add a simple tool to rotate this image. Below the image is a simple and when this is clicked the javascript function updatePhoto is called with the photoID:
<div onclick="updatePhoto('<?php echo $photoID; ?>')">Rotate</div>
JAVASCRIPT
function updatePhoto(photoID) {
$.post("photoChange.php", {
photoToChange: photoID
},
function(data, status){
document.getElementById('photo').innerHTML = "<img src='data:image/jpeg;base64, base64_encode(" + data + ")'/>";
});
}
PHOTOCHANGE.PHP
$photoID = $_POST['photoToChange');
$select_photo_query = "Select photoData From tblPhotos where photoID= '" . $photoID ."';";
$resultPhotos = mysqli_query($connect, $select_photo_query);
while($rowPhotos = mysqli_fetch_array($resultPhotos)) {
$source = $rowPhotos['photoData'];
}
$degrees=90;
$image = imagecreatefromstring ($source);
$rotate = imagerotate($image, $degrees, 0);
$finalImage = imagejpeg($rotate);
//step to convert jpeg back to binary needed?
echo $finalImage;
This all works in that the photoID is sent to photoChange.php, the source is retrieved from the database etc and data is sent back and placed into the page. But it does not display an image, just lots of data. I know I have a coding issue here but I am not sure exactly what.
I have tried removing all the rotation detail and simply echoing the $source unchanged and this does not replace the image with itself but with lines of data instead. So I wonder if there is an issue when posting data and echoing data back whether I need to stipulate a coding method being used?
Any assistance much appreciated.
Go to: http://php.net/imagejpeg
It returns a boolean value and directly dumps the image to the output.
$finalImage = imagejpeg($rotate);
//step to convert jpeg back to binary needed?
echo $finalImage;
Instead of this, add the content type and let the image render straight (you don't need echo, echo is implicit on imagejpeg()):
header('Content-Type: image/jpeg');
imagejpeg($rotate);
More problems:
You have <div id="photo"> in a while loop, which makes your ID not unique, it can't work when you have more than 1 picture
Another problem:
You interpolate PHP in Javascript a way it won't work ever. Replace the line by this with fixed concatenation:
.innerHTML = "<img src='data:image/jpeg;base64, " + data + "'/>";
Put the base64 encode in the image creation step, we make use of output buffer there:
header('Content-Type: text/plain');
ob_start();
imagejpeg($rotate);
$binary = ob_get_contents();
echo base64_encode($binary);
ob_end();

Embedding image data inline html

I'm trying to embed an image with it's data inline.however when I don't encode my data as base64 it doesn't work and some random characters are displayed.here are the two variations in php:
....
//$img-->image data read from database
$data = stream_get_contents($img);
$data64 = base64_encode($data);//when I don't use this it doesn't work
$image64 = '<img src="data:image/jpeg;base64,'.$data64.'>';
$image = '<img src="data:image/jpeg,'.$data.'>';
$img64 works but `$img' doesn't.what's the problem?
That's to be expected. JPEG data will naturally contain > and " and other HTML metacharacters. As soon as a " and then > are encounter, your browser will think the <img> tag has been closed, and everything else will be treated as text
e.g, if you don't base64_encode, you'll get something like
<img src="data:image/jpeg,randomgarbagewitha"andthena>andsome more random garbage">
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the binary contents of the jpg here
^--end of src attribute
^---end of img tag

Rotated image wont display in php

So i am trying to create a compass to show wind direction.
Function rotate($angle) {
$original = imagecreatefrompng("img/Arrow.png");
$compass = imagerotate($original, $angle, 0);
return $compass;
}
That will be displayed using some html that i am echoing. The variable angle is being passed from a database. The html on the php script looks like this:
<img src='".rotate($row['wind_dir'])."'/>
The image never displays, and clearly the browser does not know where it is.
When i view the html in my browser, the above line shows as
<img src="Resource id #4"/>
and when i click on it, it navigates to a 404.
What am i doing wrong? Have i forgotten a line in the image rotation function?
EDIT:
Having tried some of the responses below, i get an image, but it only shows as a black box!
EDIT2:
Well after much fiddling, it turns out all that was needed was to the third value of imagerotate() to -1 as follows:
$original = imagecreatefrompng("img/goog.png");
$compass = imagerotate($original, $angle, -1);
imagealphablending($compass, true);
imagesavealpha($compass, true);
header('Content-Type: image/png');
imagepng($compass);
imagedestroy($compass);
I posted a comment about using CSS or JS rotation instead but since then I've had a better idea.
The compass is always going to be Arrow.png in one of 360 positions.
Use a batch process in Photoshop or PHP to create 360 versions. One for each degree. Then you can just call Arrow_120.png for example for 120 degrees. You remove the issue with your existing code of creating images on the fly while avoiding compatibility issues with CSS / JS.
You have to execute the function and send header: try like below, say our php file name is rotate.php :
rotate.php
function rotate($angle) {
$original = imagecreatefrompng("test.png");
$compass = imagerotate($original, $angle, 0);
header('Content-Type: image/png');
imagepng($compass);
imagedestroy($compass);
}
if(isset($_GET['angle'])){
rotate($_GET['angle']);
}
THen in your html you can call the web resource i.e you php file as:
<img src="url_to_rotate.php?angle=90" />
Also remember to sanitize the GET input before executing it.
The displayed image should be a image file. To achieve this you should use imagejpeg();
So basically you should have 2 php files:
1: Creates the image file using your code and imagejpeg();
<?php
$original = imagecreatefrompng("img/Arrow.png");
$compass = imagerotate($original, $_GET['angle'], 0);
header('Content-Type: image/jpeg');
imagejpeg($compass);
?>
2: The php file that displays the image.
<img src='image.php?angle=".$row['wind_dir']."'/>
if you want just one file you could do the following:
<?php
$original = imagecreatefrompng("img/Arrow.png");
$compass = imagerotate($original, $_GET['angle'], 0);
ob_start();
imagepng($compass);
$stringdata = ob_get_contents();
ob_end_clean();
$imageData = base64_encode($stringdata);
$src = 'data: image/png;base64,'.$imageData;
echo '<img src="',$src,'">';
?>

Random image creating script trouble

I have created a script which takes a random IMAGE ID from the database, converts it to a valid file name and then I use it to generate random images from a link.
This is how such a link looks like (works - try it):
http://imgit.org/roll.php?image=3J9N0Y4k8g4l4G7
When you reload that link, you'll notice the image changes. If I add this image to <img src="THAT LINK" /> it works, however, it doesn't work on message board like phpBB or vBulletin when I put that link inside [img][/img] BBCode tags.
I suppose there is a problem with my script, because there are various services out there that do exactly the same thing (link on forums) and it works.
Here is my roll.php script:
<?php
$imgit_root_path = '.';
include("{$imgit_root_path}/common.php");
if ($config['disable_roll'])
{
redirect('index.php');
}
$roll_key = request_var('image', '');
$roll_key = substr($roll_key, 0, 15);
if (!$roll_key)
{
redirect('index.php?action=404');
}
if (!$image->roll_key_exists($roll_key))
{
redirect('index.php?action=404');
}
$images = $image->roll_info($roll_key);
$images = explode('|', $images);
$count = sizeof($images);
$index = mt_rand(0, $count - 1);
$extList = array();
$extList['gif'] = 'image/gif';
$extList['jpg'] = 'image/jpeg';
$extList['jpeg'] = 'image/jpeg';
$extList['png'] = 'image/png';
$image_url = generate_site_url() . IMAGES_PATH . $image->get_name($images[$index]);
$image_inf = pathinfo($image_url);
header('Content-type: ' . $extList[$image_inf['extension']]);
readfile($image_url);
?>
I believe the problem may be that phpBB will disallow links which aren't confirmed as images. That is, don't have a known image extension, such as .jpg;
https://www.phpbb.com/community/viewtopic.php?f=46&t=1285255
For security reasons, images whose extensions cannot be confirmed
(such as in the first example) aren't allowed by BBCode. Instead of an
image, it's fully possible for someone to embed a JavaScript script,
or even worse, onto a page which could be a security risk to anyone
visiting the page, or possibly even the server.
This is most likely the same in vBulletin.
Seems you can override it in the forum settings maybe?
Alternatively, if you can change you script, so that you can append a ".jpg" extension to the end, then that may also work!
I think what happens is browser caches image. Try adding header('Cache-Control: max-age=0'); before readfile($image_url);

Base64 image doesn't show when using PHP

I need to display an image which is in Base64 format. When I build the img tag in PHP it doesn't show the image (just the defualt 'broken image' icon). When I view the page source and click on the Base64 data is shows the picture as expected. Also, if I copy and paste the page source and save it as an HTML file it displays as expected. I also tried a random image and that worked however as my image works from a .html file I assume it is OK and should work?
The .php code:
header('content-type: text/html');
...
echo "<html><head></head><body>";
echo "Name = $name<br/>";
echo "<img src=\"data:image/jpg;base64,$photo\"/>";
echo "</body></html>";
The HTML from View Source:
<html>
<head></head>
<body>Name = Andrea Pilipczuk<br/>
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAyADIAA...{too big to fit here].../9k="/>
</body>
</html>
EDIT:
This didn't come up in View Source but digging around Chrome, I inspected the image element and found at the end was "9k=�������". Is this some kind of padding? When I edited the element to remove these the image showed up as expected.
The following code removes the random characters and displays the image correctly but seems a bit hacky, would obviously prefer to solve the underlying issue.
$unpadded = explode("=", $photo);
$padding = strlen($unpadded[0]) % 3;
$padded = $unpadded[0];
while ($padding > 0) {
$padded .= "=";
$padding--;
}
echo "<img src=\"data:image/jpeg;base64,$padded\"/>";

Categories