i need to extract an URL from an IMAP message, so far i have been able to extract the message in plain text but not the link, i could really use some help here. Here's what i got so far
$section = empty( $attachments ) ? 1 : 1.2;
$text = imap_fetchbody($connection, $msgno, $section );
echo $text."<hr/>";
I tried changing the section number from 1 : 1.1 to 1: 1.2 but it didn't help.
I need to extract the mail as html so it contains the link, what do i need to change to get the link?
Some bugs in the code above:
Using 1.2 as a floating point number instead of a string. It's a string and it's only sheer luck that your 1.2 is not getting converted as 1.2000000001.
Having a hardcoded part number in case the mail comes with multiple body parts -- read the description in RFC 3501, p. 56 for details on what these body parts are, how they work and how to find out which ones are relevant for you
Not performing any decoding of the Content-Transfer-Encoding or dealing with character set conversions. You are apparently interested in text parts of a message, these can arrive in multiple encodings like quoted-printable or base64 which you will have to decode. If you'd like to play it safe (you should, it's 2013 already and there are funny characters in URLs, not speaking about the IDNs), also converted from their charset into unicode and only then matched for contents.
You should probably check the MIME types of at least all top-level body parts so that you do not try to detect "links" within the attached images or undecoded, binary representaiton of zip files, etc.
Related
I have a mail() function set up in PHP, when emailing to my email to test I noticed the subject was converting my ' into ’.
$subject="Please provide an updated copy of your company's certification";
result: Please provide an updated copy of your company’s certification.
I followed Getting ’ instead of an apostrophe(') in PHP adding mb_convert_encoding but now I am getting &rsquo instead of '.
$subjectBad="Please provide an updated copy of your company's certification";
$subject= mb_convert_encoding($subjectBad, "HTML-ENTITIES", 'UTF-8');
result: Please provide an updated copy of your company&rsquo ;s certification.
It comes through fine to my personal email, so is there a way to properly display a ' in Outlooks subject or am I at the whim of whatever their system settings are?
Whatever you used to type the subject did not use a simple apostrophe ' which has a common representation across virtually all single-byte encodings and UTF8, instead it used a "fancy" right single quote ’, which is represented differently between single-byte encodings and UTF-8.
mb_convert_encoding() is converting to an HTML entity because you are literally telling it to, and email headers are not HTML so it's going to display as the literal string ’. The only character set other than UTF-8 that has "smart quotes" is Microsoft's cp1252, and that is still the wrong answer for email headers.
The simplest answer is: Don't do that. Use a normal apostrophe. Everyone hates dealing with "smart" quotes.
The more complex answer is that email headers MUST be 7-bit safe "ASCII" text, and anything else requires additional handwaving. Ideally you should be using a proper email library that handles this, and the dozens of other annoyances that will malform your emails and impact deliverability.
If you're dead-set on eroding your sanity and using mail() directly, then you're going to want to properly encode your subject line and use an explicitly-defined character set, which you should be doing anyways. Eg:
$subject = 'Please provide an updated copy of your company’s certification';
var_dump(
sprintf('=?UTF-8?Q?%s?=', quoted_printable_encode($subject))
);
Output:
string(82) "=?UTF-8?Q?Please provide an updated copy of your company=E2=80=99s certification?="
I'd like to somehow obscure the contents of $url = "http://blah.somedomain.com/contents/somefolder/somefile.htm"; so I can use them for links but so that the URLs are not easily read by humans when looking at the page source. The obfuscated URL still needs to work in a browser when clicking on it though so other methods of obfuscation that I've looked at are no good.
What we're after is e.g. $obscureurl = "%3A%2F%2F"...etc
Any ideas? Thanks.
Edit: Thanks for suggestions so far, but to clarify, I should have said that I'm not after encoding into HTML entities (the # values), I'm after Percent-encoding (hex values in ASCII).
For example, to change hello#me.com into: %68%65%6c%6c%6f%40%6d%65%2e%63%6f%6d
ASCII table is here for the hex of each letter and symbol: http://ascii.cl/
Is this kind of complete conversion possible with PHP? Thanks
$url = '..';
$encoded = join(array_map(function ($byte) { return "%$byte"; }, str_split(bin2hex($url), 2)));
That's essentially the entire encoding mechanism. Take the raw bytes in hex (bin2hex), 2 characters per byte, and prepend a %.
Not that this will really do a whole lot for obfuscation. The browser may indeed not even display it in its encoded form, and even search engines may display only the decoded form. Further, you're still producing a canonical URL. It doesn't matter what exactly that URL contains; if people have a link to it, they have a link to it, regardless of how human readable that link may or may not be.
I can see 2 easy ways to achieve this:
Replace every character of your link by its html entity (see How to convert all characters to their html entity equivalent using PHP)
Use some kind of ids and save the matching url in your DB: (something like http://example.com/redirect/412)
I have forwarded a html message with pdf attachment from Thunderbird.
I receive multipart/mixed with multipart/alternative containing html and txt-plain, and the pdf base 64 encoded. The multipart/alternative is 8 bit, charset= UTF8.
I have tried nearly all proposals from comments on the imap:fetchstructure/fetchbody manual page on php.net. They include decoding (at least for encoding = 1, 3, 4), applying imap_8bit, imap_qprint and imap_base64. Looking manually at the txt/plain shows encoding = 1, so the imap_8bit is applied.
The example functions can't even decide whether the returned text is plain or html because in all cases, because the returned $str always is === "" (empty string).
next, I accidentally tried a print_r($str) (if imap_8bit is not done), and that has the required email text.
I thought this might be multibyte without imap_8bit and mb_detect_encoding returns UTF8 (just as I can see in the raw email text).
Trying mb_convert_encoding($str, "ASCII") again returns an empty string.
quoted_printable_decode doesn't help either neither before nor after imap_8bit.
netbeans PHP debugger (xdebug) declares all these strings to be empty but announces the variables are 'string'.
Does anybody have an idea how to get to the email text? print_r shows that it is there, but I am banging my head against a wall for days now without any result.
I could manually search and decode the boundaries etc., which wouldn't be toooo difficult, but ... why reinvent the wheel?
Code: primarily, I used two versions from the php.net fetch_structure page and othe r web ressources. I can add them to this post but don't want to blow it up too much at this moment.
*getTxtBody which calls get_part
*getmesg which calls getpart
If I look at the plain text, I clearly see the (nested) boundaries for plain, html and pdf.
any help is very much appreciated., Klaus
You can try using fetch library.
To decode headers you can use iconv_mime_decode
Im reading a log file pasted into the body of an email, some are in various different languages and all language characters seem to display correctly except for Russian.
Here is an example of what the Russian says in the log file:
Ссылка на объект не указывает на экземпляр объекта.
в
From what I have read I need to specify decoding or encoding something on the lines of mb_encoding (UTF-8) but I am a bit lost on how to actual structure it without affecting code that isnt russian. But when echoed out it gets converted to this:
СÑылка на объект не указывает на ÑкземплÑÑ€ объекта.
в
Here is the code im using already, I am a php beginner and some of this isnt my code, I have edited to suit but not 100% what everything is doing:
$mailbox = "xxx#gmail.com";
$mailboxPassword = "xxx";
$mailbox = imap_open("{imap.gmail.com:993/imap/ssl}INBOX",
$mailbox, $mailboxPassword);
mb_internal_encoding("UTF-8");
$subject = mb_decode_mimeheader(str_replace('_', ' ', $subject));
$body = imap_fetchbody($mailbox, $val, 1);
$body = base64_decode($body);
echo $body;
Once I echo out body it converts from Russian into that encoding, any pointers on similar code I can dissect to learn how to fix this?
Please bear in mind there is numerous languages been read from the email, for the most part its just a few snippets and the rest is basic logging but what I am worried about is if I set a new decode that it will mess up other language characters
Despite its large adoption, email is still tricky to work with. If your IMAP client has a limited set of requirements, your job will be easy. Otherwise, for truly a general-purpose GMail client, there's no silver bullet and you have to un understand how email wokrs: SMTP, MIME and finally IMAP.
Basic MIME knowledge is absolutely needed, and I won't paste the whole wikipedia article, but you should really read it and understand how it works. IMAP is somewhat easier to understand.
Usually, email messages contains either a single text/plain body, or a multipart/alternative body with both a text/plain and a text/html part. But, you know, there are attachments, so you can also likely find a multipart/mixed and it can really contain anything, and if it's binary content you should treat it differently than text. There are two headers (which you can find in the global message or in part inside a multipart envelope) somewhat involved in charset issues: Content-Type and Content-Transfer-Encoding.
From your code, we must assume that you are only interested in textual parts base64-encoded. Once you have decoded them, they are a sequence of byte representing text in the charset specified by the sender in the Content-Type header, which is non-ASCII here and thus looks like this:
Content-Type: text/plain; charset=ISO-8859-1
Note that charset may be utf8 or really any other you can think of, you have to check this in your program. You job is transcoding this piece of input in the output charset of your HTML page. If your page does not use a Unicode encoding (like UTF-8), chances are that you can't even be able to show the message correctly, and '?' will be printed instead of missing characters. Since you require your application to be used worldwide (not just in Russia), and since it's anyway good practice, you should use UTF-8 in your HTML responses, and thus when you want to echo the message body:
echo mb_convert_encoding(imap_base64($body), "UTF-8", $input_charset);
where $input_charset is the one found in the Content-Type header for the processed part. For the subject line, you should use imap_mime_header_decode(), which returns an array of tuples (binary string, charset) which you have to output in the same manner as above.
TL;DR
The bytes in the UTF-8 encoded input text map quite nicely to the output if we assume it's CP-1252 encoded (maybe you didn't copy some non printable ones). This means that the input is UTF-8, but the browser thinks the page is Windows-1252. Likely this is the default browser behavior for your locale, and you can easily correct it by sending the appropriate header before any other input:
header("Content-Type: text/html; charset=utf-8");
This should be enough to solve this issue, but will also likely cause problem with non-ASCII characters in string literals and the database (if any). If you want a multilingual application, Unicode is the way, but you have to transcode your database and your PHP files from CP-1252 to UTF-8.
I retrieve data from an email through IMAP and i want to
detect (via PHP) whether the body have characters in Chinese, Japanese, or Korean programmatically. I know to encoding but no to detect
$mbox = imap_open ("{localhost:995/pop3/ssl/novalidate-cert}", "info#***.com", "********");
$email=$_REQUEST['email'];
$num_mensaje = imap_search($mbox,"FROM $email");
// grab the body for the same message
$body = imap_fetchbody($mbox,$num_mensaje[0],"1");
//chinese for example
$str = mb_convert_encoding($body,"UTF-8","EUC-CN");
imap_close($mbox);
Any idea
Do you mean that you don't know which CJK encoding the incoming message is in?
The canonical place to find that information is the charset= parameter in the Content-Type: header.
Unfortunately extracting that is not as straightforward as you would hope. Really you'd think that the object returned by imap_header would contain the type information, but it doesn't. Instead, you have to use imap_fetchheader to grab the raw headers from the message, and parse them yourself.
Parsing RFC822 headers isn't completely straightforward. For simple cases you might be able to get away with matching each line against ^content-type:.*; *charset=([^;]+) (case-insensitively). But to do it really properly though you'd have to run the whole message headers and body through a proper RFC822-family parser like MailParse.
And then you've still got the problem of messages that neglect to include charset information. For that case you would need to use mb_detect_encoding.
Or are you just worried about which language the correctly-decoded characters represent?
In this case the header you want to read, using the same method as above, is Content-Language. However it is very often not present in which case you have to fall back to guessing again. CJK Unification means that all languages may use many of the same characters, but there are a few heuristics you can use to guess:
The encoding that the message was in, from the above. eg if it was EUC-CN, chances are your languages is going to be simplified Chinese.
The presence of any kana (U+3040–U+30FF -> Japanese) or Hangul (U+AC00–U+D7FF -> Korean) in the text.
The presence of simplified vs traditional Chinese characters. Although some characters can represent either, others (where there is a significant change to the strokes between the two variants) only fit one. The simple way to detect their presence is to attempt to encode the string to GBK and Big5 encodings and see if it fails. ie if you can't encode to GBK but you can to Big5, it'll be traditional Chinese.