I'm having an issue getting the line folding to work the way it's specified. I'm obviously misunderstanding something about the documentation, so I was hoping I could get some help. The validator at https://icalendar.org/validator.html is saying
Lines not delimited by CRLF sequence near line # 1
Reference: RFC 5545 3.1. Content Lines
This is my function to generate the .ics files for download:
public function getCalendarFile($event) {
header("Content-Type: text/Calendar; charset=utf-8");
header("Content-Disposition: attachment; filename="ExampleFile.ics");
$icsFile = "BEGIN:VCALENDAR\r\n";
$icsFile .= "VERSION:2.0\r\n";
$icsFile .= "PRODID:Example Event" . $event->name . "\r\n";
$icsFile .= "METHOD:PUBLISH\r\n";
$icsFile .= "BEGIN:VEVENT\r\n";
$icsFile .= "UID:". $event->name . gmdate("Ymd\THis\Z", strtotime(Carbon::now())) . "\r\n";
$icsFile .= "DTSTAMP:" . gmdate("Ymd\THis\Z", strtotime(Carbon::now())) . "\r\n";
$icsFile .= "DTSTART:" . gmdate("Ymd\THis\Z", strtotime($event->begin)) . "\r\n";
$icsFile .= "DTEND:" . gmdate("Ymd\THis\Z", strtotime($event->end)) . "\r\n";
$icsFile .= "LOCATION:" . strip_tags($event->location) . "\r\n";
$icsFile .= "SUMMARY:" . $event->name . "\r\n";
$icsFile .= "DESCRIPTION:" . $this->foldCalendarDescription(strip_tags($event->description)) . "\r\n";
$icsFile .= "END:VEVENT\r\n";
$icsFile .= "END:VCALENDAR\r\n";
echo $icsFile;
}
public function foldCalendarDescription($description) {
return wordwrap($description, 75, "\r\n\t", TRUE);
}
I'm not sure if it has something to do with strip_tags possibly? The event description is stored as a wysiwyg html input. But the issue says with line # 1 and line # 1 looks fine to me.
Here's a wrapper for ICAL strings that works for me:
function format_ical_string( $s ) {
$r = wordwrap(
preg_replace(
array( '/,/', '/;/', '/[\r\n]/' ),
array( '\,', '\;', '\n' ),
$s
), 73, "\n", TRUE
);
// Indent all lines but first:
$r = preg_replace( '/\n/', "\n ", $r );
return $r;
}
As I wrote in the comment beneath kmoser's answer, people seem to be really hard pressed to get exactly 75 bytes on a line and create very convoluted code to do that. But why not just sometimes less than 75 bytes? A simple wordwrap will give you that because it just looks for whitespace to break and is not multi-byte aware. You'll possibly have a few more linebreaks in the iCal object code than strictly neccessary, but does that matter? This is why I upvoted kmoser's answer. It's a nice and simple solution.
I've tried to create an even simpler and faster version of kmoser's answer:
function format_ical_string( $str ) {
$str = str_replace(
[ "\r\n", '\\', ',', ';', "\n" ], // replacement order is important
[ "\n", '\\\\', '\,', '\;', '\n' ], $str );
return wordwrap( $str, 73, "\n ", false );
}
The replacements (just a str_replace, because nothing fancy is needed here) are:
replace CRLF's with just LF's
replace literal backslashes with escaped backslashes
escape comma's
escape semicolons
replace newlines with a literal \n (per rfc5545)
Then wordwrap with a LF + space (per rfc5545).
After this, strictly you should replace all LF's with CRLF's (rfc5545 line ending). I tend to format the entire iCal object with just LF's, and only at the very end replace all LF's with CRLF's to make the result compliant. This saves me the hassle of repeatedly inserting these Windows line endings (who uses those these days?) during the composition of my iCal objects.
It is unclear from rfc5545 if the property name itself is counted in the 75 bytes line limit, as in https://www.rfc-editor.org/rfc/rfc5545#section-3.1:
Lines of text SHOULD NOT be longer than 75 octets, excluding the line break.
But just to be sure, I feed the property name to the function, as in:
$line = format_ical_string( 'SUMMARY:Really long text here' );
IMPORTANT: my function above will fail on single words (!) that are longer than 75 bytes. I'm not sure how common that is. If you have an 18-character word completely made of 4-byte characters, you'd be at the limit. This seems very unlikely to me.
Related
I have a php script that is generating a tab delimited .txt file that works great but I need to output a field that contains a . (full stop/ period) within the $model field i.e itemname.1 it affects the formatting of the file.
$csv_output .= $model . "\t";
$csv_output .= '' . "\t";
$csv_output .= '' . "\t";
$csv_output .= '' . "\t";
$csv_output .= $totalstock . "\t";
$csv_output .= $leadtime . "\t";
$csv_output .= "\n";
$csv_handler = fopen('../outputfile.txt','w');
fwrite ($csv_handler,$csv_output);
fclose ($csv_handler);
I have tried enclosing in double quotes and various other variations but the output is inserting newlines
example output
itemname.1
20 1
any ideas how i can output the fields with the . in them without it affecting the tabs/lines.
Could you show us your code that encloses the variable in quotes please?
The not-very-well-informed solution appears to be use replace() to test if the . is indeed causing the new line, or if it's "something else". You might just be able to replace new line straight up even.
It Was a school boy error.
The issue was the data imported into db had carriage returns on each line entry, although the data appeared correct in the db and in excel the problem only manifested in the output file.
Thanks for your help guys made me go back to source and identify the issue.
I've got the following code which outputs two different strings sent from a php contact form.
$email_message .= "Module: ".clean_string($modcode_1_from)."\s".clean_string($modcode_2_from)."\r\n";
is meant to display module code 1 and module code 2.
Currently looks likes this
1001\s2002
However i want it to look like:
1001 2002
So i added \s to add white space between the strings but it does not do anything for me.
use non-breaking space or you can use \t to add a tab char. And the best one is just a space:
$email_message .= "Module: " . clean_string($modcode_1_from). " ". clean_string($modcode_2_from) . "\r\n";
$email_message .= "Module: " . clean_string($modcode_1_from) . "\t" . clean_string($modcode_2_from) . "\r\n";
$email_message .= "Module: " . clean_string($modcode_1_from) . " " . clean_string($modcode_2_from) . "\r\n";
You can use this:
$email_message .= "Module: ".clean_string($modcode_1_from)." ".clean_string($modcode_2_from)."\r\n";
What I did: I removed the \s and put a space in its place.
IMPORTANT NOTE: DO NOT USE " ", it will echo/add between 1001 and 2002.
Resulting in:
1001 2002
Therefore, replace \s with an actual space using your spacebar.
Footnote (other options):
If you wish to later use your data in Excel for example, you could use a comma ,
(CSV, comma seperated value) as the seperating character or a tab for a tab-seperated value \t i.e. "\t", or a semi-colon ; i.e. "; ".
You may need/want to add a space after the comma; i.e. ", " for use as a CSV.
Example output of using a comma: 1001, 1002.
Can you try changing the \s to
' '
and see if this works for you?
Try this,
$email_message .= "Module: ".clean_string($modcode_1_from)." ".clean_string($modcode_2_from)."\r\n";
I have a strange problem with the PHP mail(); function.
Using it like this
$header = "MIME-Version: 1.0" . "\r\n";
$header .= "Content-type: text/html; charset=utf-8" . "\r\n";
$header .= "Content-Transfer-Encoding: quoted-printable" . "\r\n";
$header .= "Reply-To:" . $email . "\r\n";
$header .= "From: Kontaktformular <noreply#thomas-glaser-foto.de>" . "\r\n";
mail( "mail.me#mail.com", "Message from " . $name . " through your website!", $message, $header );
everything works as expected. The mail gets send, everything is encoded correctly and the subject is also ok.
But when I change the double quotes with single quotes like this:
$header = 'MIME-Version: 1.0' . '\r\n';
$header .= 'Content-type: text/html; charset=utf-8' . '\r\n';
$header .= 'Content-Transfer-Encoding: quoted-printable' . '\r\n';
$header .= 'Reply-To:' . $email . '\r\n';
$header .= 'From: Kontaktformular <noreply#thomas-glaser-foto.de>' . '\r\n';
mail( 'mail.me#mail.com', 'Message from ' . $name . ' through your website!', $message, $header );
The mail still gets send, but without the set subject. Instead, it is
www-data#domain.com
and the special characters are also destroyed. What is happening there?
Single quotes are for literal strings, no variables are replaced/expanded, and no escape sequences other than \' and \\ are respected. The way you've written your code you can leave the single-quotes as-is except you must have the line breaks double quoted as "\r\n".
Double quotes are needed to put in the special linebreak characters ("\r\n"). They are not treated as linebreaks when you use single quotes, instead they will be treated as literal text.
The PHP interpreter will evaluate material in double quotes, but it doesn't do so to single quotes. Because of this, the best practice is to only use double quotes when something needs to be evaluated (like a variable, when concatenation isn't possible, or special characters like line breaks).
Please read the manual:
http://php.net/manual/en/language.types.string.php
Single quoted
To specify a literal single quote, escape it with a backslash (). To
specify a literal backslash, double it (\). All other instances of
backslash will be treated as a literal backslash: this means that the
other escape sequences you might be used to, such as \r or \n, will be
output literally as specified rather than having any special meaning.
This code retrieves information from another site:
<?php
$location = $ident;
get_taf($location);
function get_taf($location) {
$fileName = "ftp://tgftp.nws.noaa.gov/data/forecasts/taf/stations/$location.TXT";
$taf = '';
$fileData = #file($fileName);
if ($fileData != false) {
list($i, $date) = each($fileData);
$utc = strtotime(trim($date));
$time = date("D, jS M Y Hi",$utc);
while (list($i, $line) = each($fileData)) {
$taf .= ' ' . trim($line);
}
$taf = trim(str_replace(' ', ' ', $taf));
}
if(!empty($taf)){
echo "Issued: $time Z
<br><br>
$taf";
} else {
echo 'TAF not available';
}
}
?>
What its suppose to look like:
TAF KLBX 160541Z 1606/1706 15009KT P6SM FEW009 BKN013 OVC030
FM160900 15005KT P6SM SCT010 BKN035
FM161600 16010KT P6SM VCSH SCT012 BKN030
FM161900 18012KT P6SM SCT025 BKN040
FM170000 16005KT P6SM SCT012 BKN022
What it ends up looking like:
TAF KLBX 160541Z 1606/1706 15009KT P6SM FEW009 BKN013 OVC030 FM160900 15005KT P6SM SCT010 BKN035 FM161600 16010KT P6SM VCSH SCT012 BKN030 FM161900 18012KT P6SM SCT025 BKN040 FM170000 16005KT P6SM SCT012 BKN022
How do I maintain the spacing with the rows???
It is putting all the info on 1 line and it looks like a paragraoh instead a list.
Thanks
Your output contains newline bytes, but in webpages those line breaks are usually treated as regular spacing characters and not as an actual line break (the br tag is used for hard breaks instead). PHP has a function to convert line breaks to br tags called nl2br, so you could do this:
$taf = nl2br(trim(str_replace(' ', ' ', $taf)), false);
Since you're trimming the line endings of every line you'll also have to modify something to either preserve them (by using trim with two parameters or by using just ltrim) or re-add them manually like this:
$taf .= ' ' . trim($line) . "\n";
You could also append the <br> tags directly, that would save you the conversion. Another possibility would be to just preserve/add the line endings and wrap the output in a <pre> section, this will eliminate the need of break-tags.
Modify the following line
$taf .= ' ' . trim($line);
Using the PHP End of Line constant, like so:
$taf .= ' ' . trim($line).PHP_EOL;
I'm trying to send with function mail(); rich text containing links ; I'm sending this kind of code...
Please, access Contact to send all these information
throw firebug i can see that link tags was removed , code becoming like this
Please, access <a>Contact</a> to send all these information
I need this script , after banning the person who violated rules , to send email to tell the reason why we banned him .
On another email services email comes without problems , what is my mistake , sorry for my English , down i'll show a part from script for sending email , the important one..
// Set and wordwrap message body
$body = "From: $name\n\n";
$body .= "Message: $message";
$body = wordwrap($body, 70);
// Build header
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=utf-8' . "\r\n";
$headers .= "From: $email\n";
if ($cc == 1) {
$headers .= "Cc: $email\n";
}
$headers .= "X-Mailer: PHP/Contact";
// Send email
if(!#mail($to, $subject, $body, $headers)) {
echo '<b> ERROR ! </b> Unfortunately, a server issue prevented delivery of your message<br />'; }
Unless you are doing something to $body in the code you have not posted here, my guess is that it is wordwrap() that causes the problem. In the php manual is a user-contributed function which might help:
http://www.php.net/manual/en/function.wordwrap.php#89782
Part of the problem is the long lines, but wordwrap() is not sufficient to solve that.
An email could have arbitrarily long lines, but these are transmitted over a protocol which only allows short lines. So long lines have to be split. The protocol tags lines which have been split by adding = to then end of them so what starts out looking like this.
Characters 2 3 4 5 6 7
12346790123456789012345678901234567890132456789012345678901234567890123456789
This is a long line with text which goes beyond the 78 character limit imposed by the protocol
ends up looking like this
This is a long line with text which goes beyond the 78 character limit=
imposed by the protocol
Using = like that though means that = can't be used in your message, so it has to be escaped. So you need to replace = in your message with =3D (where 3D is the hex code for =).
It's also wise to replace any control characters (with ascii code < 32) with =xx and anything with ascii code over 126 too. I use these functions to do this, you then just need to do $message=encodeText($message) before you send and the problem should go away.
function encodeText($input) {
// split input into lines, split by \r\n, \r or \n
$lines=preg_split("/(?:\r\n|\r|\n)/", $input);
$text="";
// for each line, encode it into a 78 char max line.
for ($i=0; $i<count($lines); $i++) {
$text.=encodeLine($lines[$i]);
}
return $text;
}
/**
* This splits a line into a number of pieces, each shorter than the 78 char
* limit. It also add continuation marks (i.e. =) to then end of each piece
* of the resulting line, and escapes any = characters, control characters
* or characters with bit 8 set, and backspace.
* #return a multiline string (with /r/n linebreaks)
*/
function encodeLine($line) {
$split=Array();
$result="";
$piece='';
$j=0;
for ($i=0; $i<strlen($line); $i++) {
// if you've just split a line, you'll need to add an = to the
// end of the previous one
if ($j>0 && $piece=="") $split[$j-1].="=";
// replace = and not printable ascii characters with =XX
if (ord($line{$i})==0x3D) {
$piece.="=3D";
} else if (ord($line{$i})<32) {
$piece.="=".bin2hex($line{$i});
} else if (ord($line{$i})>126) {
$piece.="=".bin2hex($line{$i});
} else {
$piece.=$line{$i};
}
// if the resulting line is longer than 71 characters split the line
if (strlen($piece)>=72) {
$split[$j]=$piece;
$piece="";
$j++;
}
}
// the last piece being assembled should be added to the array of pieces
if (strlen($piece)>0) $split[]=$piece;
// if a piece ends in whitespace then replace that whitespace with =20
// for a space or =09 for a tab.
for ($i=0; $i<count($split); $i++) {
$last=substr($split[$i],-1);
if ($last=="\t") $last="=09";
if ($last==" ") $last="=20";
$split[$i]=substr($split[$i],0,strlen($split[$i])-1).$last;
}
// assemble pieces into a single multiline string.
for ($i=0; $i<count($split); $i++) {
$result.=$split[$i]."\r\n";
}
return $result;
}
This might be to late but, oh well just figure it out. At least that's what I'm seeing here.
Basically I'm generating the Newsletter dynamic based on some data and when I found inside a string a specific syntax I had to replace it with a anchor tag. Anyway, here it is:
Bad formatting:
"<a href='" + url + "'>" + name + "</a>";
Good formatting:
'' + name + '';
Straight answer, use double-quotes for href attribute.
Try this out , Use stripslashes() with the email body and it should worked perfectly fine
$body= stripslashes($mail_message);