This question already has an answer here:
PHP attachment in email is empty
(1 answer)
Closed 9 years ago.
Im trying to take data from the database and display it in a CSV file which is both downloadable and emailed to someone. I have managed to get the downloadable file working and it displays all of the correct data. It also sends a CSV file to the necessary person but that CSV file is empty and no data is displayed in it.
Here is my code:
$myroot = "../../";
include($myroot . "inc/functions.php");
// output headers so that the file is downloaded rather than displayed
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=surveys.csv');
$output = fopen('php://output', 'w');
// Create CSV file
fputcsv($output, array('Name', 'Branch', 'Website','Company', 'Question1', 'Question2', 'Question3', 'Question4', 'Question5'));
$mysql_connection = db_connect_enhanced('*****','*****','*****','*****');
$query='SELECT * FROM *****.*****';
$surveys = db_query_into_array_enhanced($mysql_connection, $query);
$count = count($surveys);
$data = array();
for($i=0; $i<=$count; $i++){
$data[] = array($surveys[$i]['FeedbackName'], $surveys[$i]['BranchName'], $surveys[$i]['FeedbackWebsite'], $surveys[$i]['FeedbackCompany'], $surveys[$i]['Question1'], $surveys[$i]['Question2'], $surveys[$i]['Question3'], $surveys[$i]['Question4'], $surveys[$i]['Question5']);
}
foreach( $data as $row )
{
fputcsv($output, $row, ',', '"');
}
fclose($output);
$encoded = chunk_split(base64_encode($output));
// create the email and send it off
$subject = "File you requested from RRWH.com";
$from = "*****#*****.com";
$headers = 'MIME-Version: 1.0' . "\n";
$headers .= 'Content-Type: multipart/mixed;
boundary="----=_NextPart_001_0011_1234ABCD.4321FDAC"' . "\n";
$message = '
This is a multi-part message in MIME format.
------=_NextPart_001_0011_1234ABCD.4321FDAC
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Hello
We have attached for you the PHP script that you requested from http://rrwh.com/scripts.php
as a zip file.
Regards
------=_NextPart_001_0011_1234ABCD.4321FDAC
Content-Type: application/octet-stream; name="';
$message .= "surveys.csv";
$message .= '"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="';
$message .= "surveys.csv";
$message .= '"
';
$message .= $encoded;
$message .= '
------=_NextPart_001_0011_1234ABCD.4321FDAC--
';
mail("*****#*****.com", $subject, $message, $headers, "-f$from");
I've spent a day and a half on this but I cant see the problem. Could someone please point it out to me as to why the attached CSV file is empty?
i'm getting kind of desperate and stressed out :( please someone help me.
base64_encode() expects the parameter to be a string and you give it a (closed) resource.
Try to read the resource into a string, or use file_get_contents or build your string while you write into the resource.
Update:
Try and replace
foreach( $data as $row )
{
fputcsv($output, $row, ',', '"');
}
fclose($output);
$encoded = chunk_split(base64_encode($output));
by
$myoutput = '"Name","Branch","Website","Company","Question1","Question2","Question3","Question4","Question5"';
foreach( $data as $row )
{
$myoutput .= "\"".implode('","',$row)."\"\n";
fputcsv($output, $row, ',', '"');
}
fclose($output);
$encoded = chunk_split(base64_encode($myoutput));
This way, everything you write into your output you also write into a new variable ($myoutput). Since this is a string you can use it with base64_encode().
Related
I am working on my PHP to extract the binary data that I stored the email header in the mysql database. I need some help with extract the binary data to get the attachment binary data.
Example:
UEsDBBQAAAAIAEpZrEjPyoXURw....etc
I don't know how do you extract the binary data if you are looking for a filename, example: email_example1.zip.
Here is the header:
Return-Path: <sender#domain.com>
Delivered-To: chris#domain.com
Received: from domain.com
------=_Part_4094373_1508330616.1564422111167
Content-Type: application/zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="email_example1.zip"
Content-ID: <05063d19-5033-af14-87e2-d2fbf22d5857#yahoo.com>
UEsDBBQAAAAIAEpZrEjPyoXURw....etc
------=_Part_4094373_1508330616.1564422111167
Content-Type: application/zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="example2.zip"
Content-ID: <3b2c4fee-2b28-778b-b27f-c63881d64e17#domain.com>
UEsDBBQAAAAIALtk6U5W+XzU7iM....etc
Here is the PHP:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
//Connect to the database
include('config.php');
$id = $_GET['id'];
$attid = $_GET['attid'];
$message_id = $_GET['msgid'];
$mailbox_sql = 'SELECT * FROM ' . $mailfolder . ' WHERE email_id = ? AND message_id = ?';
$mailbox = $link->prepare($mailbox_sql);
$mailbox->execute([$id,$message_id]);
// set the resulting array to associative
$row = $mailbox->fetch(PDO::FETCH_ASSOC);
if (is_array($row)) {
$attached = $row['attached_files'];
$attached_arr = explode("\n", $attached);
}
foreach ($attached_arr as $files) {
$attached_file = 'attid: ' . $attid . ' filename:';
$attached = '';
if (strpos($files, ' attid: ') !== false) {
$filename = trim(strrchr($files, ':'), ': ');
$files = 'attid: ' . $attid . ' filename: ' . $filename;
}
if (strpos($files, $attached_file) !== false) {
$attached = trim(strrchr($files, ':'), ': ');
}
mailbox = null;
?>
Do you know how I can search the filename in the email header to extract the binary data?
Any advice would be much appreicated.
You need get the input stream directly from the body because your content is application/zip Content-Type: application/zip .
To do that u can use php://input :
$input = file_get_contents('php://input');
$binary = base64ToBinary($input);
function base64ToBinary(string $string): string {
if (strpos($string, ';base64,') !== false) {
$string = explode(';base64,', $string)[1];
}
return base64_decode($string);
}
The file name is exposed via Content-Disposition Header:
In your post you have Content-Disposition: attachment; filename="email_example1.zip" you can just parse it from there.
EDIT
How to parse your file name from Header:
$value = $_SERVER['HTTP_CONTENT_DISPOSITION'];
$filename = 'default_name.zip';
if (preg_match('/filename="-(.*?)-"/', $value, $match) == 1) {
$filename = $match[1];
}
The code I provided works 100% for the Content Disposition Header you provided:
If it doesn't work for you that means the format you posted is wrong and check this Question for an answer on how to get file name from content disposition header .
Otherwise your request has nothing to do about Binary data it's parsing about parsing value from string. Please update your question description to match what you want to achieve.
I need to store images into an MSSQL database as part of a form processing which is handled by PHP.
Before that, my client did this task with following C# code:
Dim content As Byte() = ImageToStream(fName)
cnn.Open()
Dim cmd As New SqlCommand("UPDATE lide SET pictPostava = #img WHERE ID = '" & GetValueToTextBox(iRow, "ID") & "'", cnn)
cmd.Parameters.AddWithValue("#img", content)
cmd.ExecuteNonQuery()
cnn.Close()
content = Nothing
Public Function ImageToStream(ByVal fileName As String) As Byte()
Dim stream As New MemoryStream()
tryagain:
Try
Dim image As New Bitmap(fileName)
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg)
Catch ex As Exception
GoTo tryagain
End Try
Return stream.ToArray()
End Function
I tried to replicate it via unpack() function based on http://php.net/manual/en/function.mssql-query.php#31688
// convert file
$file = file_get_contents('http://www.sunagency.cz/wp-content/uploads/2017/01/1745083-150x150.jpg');
$unpacked = "0x" . unpack("H*hex", $file);
// get the hexcode of image
print_r( $unpacked['hex'] );
However, he can't restore it. And to be honest, I'm not sure how to revert it back with PHP either - changing header into Image doesn't solve the problem.
// view the packed file
header("Content-type: image/jpeg;");
echo $unpacked['hex'];
Could you help? I have never done this before and would be more than happy to solve the problem.
If somebody gets the same trouble as I did, the way is to completely fake the form values:
$boundary = wp_generate_password(24);
$url = "issues/$issue_id/files.json";
$this->content_type = "multipart/form-data; boundary=$boundary";
$payload = '';
$n = 1;
// Upload files
foreach ($files as $file) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="attachments['.$n.'][file]"; filename="' . basename($file) . '"' . "\r\n";
// $payload .= 'Content-Type: image/jpeg' . "\r\n";
// $payload .= 'Content-Transfer-Encoding: binary' . "\r\n";
$payload .= "\r\n";
$payload .= file_get_contents($file);
$payload .= "\r\n";
$n++;
}
$payload .= '--' . $boundary . '--';
Here are the resources that helped me at that time (answering the question way later than I solved it), but maybe it will help someone in the future.
https://gist.github.com/UmeshSingla/40b5f7b0fb7e0ade0438
Posting raw image data as multipart/form-data in curl
I have an AngularJS app that sends emails using a PHP document.
The email body includes two links to images that are populated with a JS variables.
Most of the emails arrive good and the links work, but in some of them, the links (both or one of them) will come out broken, looking like this:
https://blabla.com/register/uploads/Frankfurt2018-22-03-2018-16-07-52.!
Or like this:
https://blabla.com/register/uploads/KoelnerListe2%21
Or like this:
https://blabla.com/register/upload!
It's weird cause sometimes is both links, sometimes is only one, and most of the times are correct.
The link variable comes from the Angular app and looks like this:
$scope.sendapplication = function(){
$scope.photoor = "https://blabla.com/register/uploads/"+$scope.photoor;
$scope.photosmall = "https://blabla.com/register/uploads/"+$scope.photo;
$scope.exhibitor = {
'img':$scope.photosmall,
'imgoriginal':$scope.photoor,
};
var $promise=$http.post('emailtest.php',$scope.exhibitor);
$promise.then(function (data) {
...
});
};
And in the php file I do this:
$contentType = explode(';', $_SERVER['CONTENT_TYPE']); // Check all available Content-Type
$rawBody = file_get_contents("php://input"); // Read body
$data = array(); // Initialize default data array
if(in_array('application/json', $contentType)) {
$data = json_decode($rawBody); // Then decode it
$photo = $data->img;
$photooriginal = $data->imgoriginal;
} else {
parse_str($data, $data); // If not JSON, just do same as PHP default method
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array( // Return data
'data' => $data
));
$sabine = 'blabla#gmail.com';
$headerss = "From: ".$galleryname."<".$email.">\r\nReturn-path: ".$email."";
$headerss .= "Reply-To: ".$galleryname."<".$email.">";
$headerss .= "MIME-Version: 1.0\r\n";
$headerss .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$recipient = $sabine;
$subjects = "Registration for ".$fairumlaut." - ".$galleryname."";
$bodys .= "<p><strong>Original photo</strong>: Link</p>";
$bodys .= "<p><strong>Web resized photo</strong>: Link</p>";
$bodys .= "<p></p>";
mail($recipient, $subjects, $bodys, $headerss);
What could cause such weird behaviour?
wrap the link in urlencode function. This will solve your issue.
update: or if I read your code I would have seen that the links are coming from JS. Try encodeURI().. ;)
I have a script that access the specified email and fetches mail. $temp->getContent() echos the following..
----boundary_2710_edfb8b44-71c8-49ff-a8cb-88c83382c4ee
Content-Type: multipart/alternative;
boundary=--boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750 --boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
PGZvcm0gbWV0aG9k.........this part is base64 encoded and it works fine if i copy and decode it separately.......AgICAgICAgICAgDQoNCjwvZm9ybT4=
----boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750-- ----boundary_2710_edfb8b44-71c8-49ff-a8cb-88c83382c4ee
Content-Type: multipart/mixed; boundary=--boundary_2711_eca4cfc3-fc62-43d6-b9fb-e5295abbfbe8 ----boundary_2711_eca4cfc3-fc62-43d6-b9fb-e5295abbfbe8 Content-Type: application/pdf;
name=redBusTicket.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment Content-ID: JVBERi0xLjIgCiXi48/TIAoxIDAgb2JqIAo8PCAKL1R5cGUgL0NhdGFsb2cgCi9QYWdlcyAy IDAgUiAKL1BhZ2VNb2RlIC9Vc2VOb25lIAovVmlld2VyUHJlZ
Between this content there is base64 encoded part and it works fine if i copy and decode it separately. Also there is a attachment in the mail. How can i get the attached file. The following is my code. when i use the base64_decode directly i get no output.. just a blank page..
$storage = new Zend_Mail_Storage_Imap($imap);
$temp = $storage->getMessage($_GET['mailid']);
echo base64_decode($temp->getContent());
the documentation in zend website is not very good. Need some help!!
It works good for me:
foreach ($mail as $message) {
$content = null;
foreach (new RecursiveIteratorIterator($message) as $part) {
if (strtok($part->contentType, ';') == 'text/plain') {
$content = $part;
break;
}
}
if ($content) {
echo "\n encode: " . $content->contentTransferEncoding;
echo "\n date: " . $message->date;
echo "\n subject: \n" . iconv_mime_decode($message->subject, 0, 'UTF-8');
echo "\n plain text part: \n" . mb_convert_encoding(base64_decode($content), 'UTF-8', 'KOI8-R');
}
}
I have something like this to get the base_64 contents from an email. Try to filter out what you dont need.
if ($email->isMultipart() && $partsCount){
for($i = 1; $i < $email->countParts() +1; $i++) {
$part = $email->getPart($i);
$headers = $part->getHeaders();
if (
array_key_exists('content-description', $headers)
|| array_key_exists('content-disposition', $headers)
){
if (array_key_exists('content-description', $headers)) {
$att = $part->getContent();
$filepath = utf8_encode(DATA_PATH . '/' . $part->getHeader('content-description'));
if (is_file($filepath)) {
unlink($filepath); // deletes previous files with same name
}
$file = fopen($filepath, "w");
fwrite($file, base64_decode($att));
fclose($file);
$attachments[] = $filepath;
}
}
}
}
$httpsock = #socket_create_listen("9090");
if (!$httpsock) {
print "Socket creation failed!\n";
exit;
}
while (1) {
$client = socket_accept($httpsock);
$input = trim(socket_read ($client, 4096));
$input = explode(" ", $input);
$input = $input[1];
$fileinfo = pathinfo($input);
switch ($fileinfo['extension']) {
default:
$mime = "text/html";
}
if ($input == "/") {
$input = "index.html";
}
$input = ".$input";
if (file_exists($input) && is_readable($input)) {
echo "Serving $input\n";
$contents = file_get_contents($input);
$output = "HTTP/1.0 200 OK\r\nServer: APatchyServer\r\nConnection: close\r\nContent-Type: $mime\r\n\r\n$contents";
} else {
//$contents = "The file you requested doesn't exist. Sorry!";
//$output = "HTTP/1.0 404 OBJECT NOT FOUND\r\nServer: BabyHTTP\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n$contents";
function openfile()
{
$filename = "a.pl";
$file = fopen($filename, 'r');
$filesize = filesize($filename);
$buffer = fread($file, $filesize);
$array = array("Output"=>$buffer,"filesize"=>$filesize,"filename"=>$filename);
return $array;
}
$send = openfile();
$file = $send['filename'];
$filesize = $send['filesize'];
$output = 'HTTP/1.0 200 OK\r\n';
$output .= "Content-type: application/octet-stream\r\n";
$output .= 'Content-Disposition: attachment; filename="'.$file.'"\r\n';
$output .= "Content-Length:$filesize\r\n";
$output .= "Accept-Ranges: bytes\r\n";
$output .= "Cache-Control: private\n\n";
$output .= $send['Output'];
$output .= "Content-Transfer-Encoding: binary";
$output .= "Connection: Keep-Alive\r\n";
}
socket_write($client, $output);
socket_close ($client);
}
socket_close ($httpsock);
Hello, I am snikolov i am creating a miniwebserver with php and i would like to know how i can send the client a file to download with his browser such as firefox or internet explore i am sending a file to the user to download via sockets, but the cleint is not getting the filename and the information to download can you please help me here,if i declare the file again i get this error in my server
Fatal error: Cannot redeclare openfile() (previously declared in C:\User
s\fsfdsf\sfdsfsdf\httpd.php:31) in C:\Users\hfghfgh\hfghg\httpd.php on li
ne 29, if its possible, i would like to know if the webserver can show much banwdidth the user request via sockets, perl has the same option as php but its more hardcore than php i dont understand much about perl, i even saw that a miniwebserver can show much the client user pulls from the server would it be possible that you can assist me with this coding, i much aprreciate it thank you guys.
You are not sending the filename to the client, so how should it know which filename to use?
There is a drawback, you can provide the desired filename in the http header, but some browsers ignore that and always suggest the filename based on the last element in URL.
For example http://localhost/download.php?help.me would result in the sugested filename help.me in the file download dialogue.
see: http://en.wikipedia.org/wiki/List_of_HTTP_headers
Everytime you run your while (1) loop you declare openfile function. You can declare function only once. Try to move openfile declaration outside loop.
$httpsock = #socket_create_listen("9090");
if (!$httpsock) {
print "Socket creation failed!\n";
exit;
}
while (1) {
$client = socket_accept($httpsock);
$input = trim(socket_read ($client, 4096));
$input = explode(" ", $input);
$input = $input[1];
$fileinfo = pathinfo($input);
switch ($fileinfo['extension']) {
default:
$mime = "text/html";
}
if ($input == "/") {
$input = "index.html";
}
$input = ".$input";
if (file_exists($input) && is_readable($input)) {
echo "Serving $input\n";
$contents = file_get_contents($input);
$output = "HTTP/1.0 200 OK\r\nServer: APatchyServer\r\nConnection: close\r\nContent-Type: $mime\r\n\r\n$contents";
} else {
//$contents = "The file you requested doesn't exist. Sorry!";
//$output = "HTTP/1.0 404 OBJECT NOT FOUND\r\nServer: BabyHTTP\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n$contents";
$filename = "dada";
$file = fopen($filename, 'r');
$filesize = filesize($filename);
$buffer = fread($file, $filesize);
$send = array("Output"=>$buffer,"filesize"=>$filesize,"filename"=>$filename);
$file = $send['filename'];
$output = 'HTTP/1.0 200 OK\r\n';
$output .= "Content-type: application/octet-stream\r\n";
$output .= "Content-Length: $filesize\r\n";
$output .= 'Content-Disposition: attachment; filename="'.$file.'"\r\n';
$output .= "Accept-Ranges: bytes\r\n";
$output .= "Cache-Control: private\n\n";
$output .= $send['Output'];
$output .= "Pragma: private\n\n";
// $output .= "Content-Transfer-Encoding: binary";
//$output .= "Connection: Keep-Alive\r\n";
}
socket_write($client, $output);
socket_close ($client);
}
socket_close ($httpsock);