I need to extract the certificate from a signed PDF file with a .p7m extension. I have no problem doing it with xml.p7m file but I can't do it with the pdf.p7m file. Following part of the code (working) to extract the certificate from xml file
// I receive the certified array
function der2smime($file)
{
$to=<<<TXT
MIME-Version: 1.0
Content-Disposition: attachment; filename=“smime.p7m”
Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name=“smime.p7m”
Content-Transfer-Encoding: base64
\n
TXT;
$from=file_get_contents($file);
$to.=chunk_split(base64_encode($from));
return file_put_contents("smime.p7m-b6m",$to);
}
$file = "prova.pdf.p7m";
$filenobom = "pr.pdf.p7m";
$str = file_get_contents($file);
$str = str_replace("\xEF\xBB\xBF",'',$str);
file_put_contents($filenobom, $str);
$response = der2smime($filenobom);
$output = openssl_pkcs7_verify ("smime.p7m-b6m" , 0 , "pippo.crt" ,array("CA.pem"),"CA.pem","prova.pdf");
echo openssl_error_string();
$pemdata="pippo.crt";
$data = openssl_x509_parse(file_get_contents($pemdata));
echo openssl_error_string();
print_r($data);
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.
im really struggling now and I dont know what im doing wrong.
I have regex for analyzing imap_body. It works perfectly fine in my test case but completly fails in a function.
Heres the test case:
$type = "base64";
$regex_html = "/(?<=Content-Type: text\/html;).*?(Content-Transfer-Encoding:).*?(".$type.").*?(\);).(.*?)(?= --_)/";
$email = "--_004_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_ Content-Type: multipart/alternative; boundary="_000_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_" X-Microsoft-Exchange-Diagnostics: 1;DB6P192MB0231;27:wPFlVOQ8iMAXT+N6591mBRfClfXdhMLmsxh/Y7d1LVbWrHPkVIxvj9+3g1ttW81Vi7Xh16wwzAIakEj5LqQ7s3r7Kr3/lVOL94eT9Ky+Tm+IqokcaiD5Q9lLzBrvUIz0CJDh27WR+m3qUDN87HH0jA== X-Microsoft-Antispam-Mailbox-Delivery: abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ex:0;auth:1;dest:I;WIMS-SenderIP:40.92.69.49;WIMS-SPF:windowslive%2ecom;WIMS-DKIM:windowslive%2ecom;WIMS-822:trojak3d%40windowslive%2ecom;WIMS-PRA:trojak3d%40windowslive%2ecom;WIMS-AUTH:PASS;ENG:(400001000128)(400125000095)(5062000261)(5061607266)(5061608174)(4900095)(4921089)(4950112)(4990090)(102400140)(400001001223)(400125100095)(61617095)(400001002128)(400125200095); --_000_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 X-Microsoft-Exchange-Diagnostics: 1;DB6P192MB0231;27:wPFlVOQ8iMAXT+N6591mBRfClfXdhMLmsxh/Y7d1LVbWrHPkVIxvj9+3g1ttW81Vi7Xh16wwzAIakEj5LqQ7s3r7Kr3/lVOL94eT9Ky+Tm+IqokcaiD5Q9lLzBrvUIz0CJDh27WR+m3qUDN87HH0jA== X-Microsoft-Antispam-Mailbox-Delivery: abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ex:0;auth:1;dest:I;WIMS-SenderIP:40.92.69.49;WIMS-SPF:windowslive%2ecom;WIMS-DKIM:windowslive%2ecom;WIMS-822:trojak3d%40windowslive%2ecom;WIMS-PRA:trojak3d%40windowslive%2ecom;WIMS-AUTH:PASS;ENG:(400001000128)(400125000095)(5062000261)(5061607266)(5061608174)(4900095)(4921089)(4950112)(4990090)(102400140)(400001001223)(400125100095)(61617095)(400001002128)(400125200095); DQoNCkZyb206IFNlcnZpY2VAcGF5cGFJLmNvbSBbbWFpbHRvOmthaG5paWp1bGVAamlhbnNrb2wu Y29tXQ0KU2VudDogMjggSnVseSAyMDE3IDEwOjE2DQpUbzogdHJvamFrM2RAd2luZG93c2xpdmUu Y29tDQpTdWJqZWN0OiBbUGF5UGFJIGxuY10gU3RhdGVtZW50IGFjY291bnQgdW51c3VhbCBhY3Rp dml0eSBsb2dpbiB0byByZWFjdGl2YXRlZCAwNy8yOC8xNw0KDQpbSW1hZ2UgcmVtb3ZlZCBieSBz ZW5kZXIuIFNpbXBsZUFwcF0NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQpXZSBuZWVkIHlvdXIgaGVs cCB0byByZXNvbHZlIHVuYXV0aG9yaXplZCBhY3Rpdml0ZXMNCg0KRGVhciBDbGllbnQsDQoNCldl IGp1c3Qgd2FudGVkIHRvIGNvbmZpcm0gdGhhdCB5b3UndmUgY2hhbmdlZCB5b3VyIHBhc3N3b3Jk LiBJZiB5b3UgZGlkbid0IG1ha2UgdGhpcyBjaGFuZ2UsIHBsZWFzZSBjaGVjayBpbmZvcm1hdGlv biBpbiBoZXJlLiBJdCdzIGltcG9ydGFudCB0aGF0IHlvdSBsZXQgdXMga25vdyBiZWNhdXNlIGl0 IGhlbHBzIHVzIHByZXZlbnQgdW5hdXRob3Jpc2VkIHBlcnNvbnMgZnJvbSBhY2Nlc3NpbmcgdGhl IFBheVBhbCBuZXR3b3JrIGFuZCB5b3VyIGFjY291bnQgaW5mb3JtYXRpb24uDQoNCldlJ3ZlIG5v dGljZWQgc29tZSBjaGFuZ2VzIHRvIHlvdXIgdW5zdWFsIHNlbGxpbmcgYWN0aXZpdGllcyBhbmQg d2lsbCBuZWVkIHNvbWUgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB5b3VyIHJlY2VudCBzYWxlcy4N CkNvbmZpcm0geW91ciBlbWFpbDxodHRwOi8vb3cubHkvcWVMMzMwZFl6TzI+DQoNCg0KVGhhbmsg eW91IGZvciB5b3VyIHVuZGVyc3RhbmRpbmcgYW5kIGNvb3BlcmF0aW9uLiBJZiB5b3UgbmVlZCBm dXJ0aGVyIGFzc2lzdGFuY2UsIHBsZWFzZSBjbGljayBDb250YWN0IGF0IHRoZSBib3R0b20gb2Yg YW55IFBheVBhbCBwYWdlLg0KDQpTaW5jZXJlbHksDQoNClBheVBhbA0KDQoNCg0KDQoNCkhlbHAg PGh0dHA6Ly9wYXlwYWwuY29tPiB8IFJlc29sdXRpb24gPGh0dHA6Ly9wYXlwYWwuY29tPiB8IFNl Y3VyaXR5IENlbnRyZTxodHRwOi8vcGF5cGFsLmNvbT4NCg0KUGxlYXNlIGRvIG5vdCByZXBseSB0 byB0aGlzIGVtYWlsLiBUbyBnZXQgaW4gdG91Y2ggd2l0aCB1cywgY2xpY2sgSGVscCAmIENvbnRh Y3QuPGh0dHA6Ly9wYXlwYWwuY29tPg0KDQpDb3B5cmlnaHQgwqkgMTk5OSDigJMgMjAxNyBQYXlQ YWwuIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCkNvbnN1bWVyIGFkdmlzb3J5IC0gUGF5UGFsIFB0 ZS4gTHRkLiB0aGUgaG9sZGVyIG9mIFBheVBhbCdzIHN0b3JlZCB2YWx1ZSBmYWNpbGl0eSwgZG9l cyBub3QgcmVxdWlyZSB0aGUgYXBwcm92YWwgb2YgdGhlIE1vbmV0YXJ5IEF1dGhvcml0eSBvZiBT aW5nYXBvcmUuIFVzZXJzIGFyZSBhZHZpc2VkIHRvIHJlYWQgdGhlIHRlcm1zIGFuZCBjb25kaXRp b25zIGNhcmVmdWxseS4NCg0KUGF5UGFsIFBQWDAwMTg4OToyMTNlZTFiZjYxODdlDQoNCg0KDQoN Cg0KDQo= --_000_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: base64 X-Microsoft-Exchange-Diagnostics: 1;DB6P192MB0231;27:wPFlVOQ8iMAXT+N6591mBRfClfXdhMLmsxh/Y7d1LVbWrHPkVIxvj9+3g1ttW81Vi7Xh16wwzAIakEj5LqQ7s3r7Kr3/lVOL94eT9Ky+Tm+IqokcaiD5Q9lLzBrvUIz0CJDh27WR+m3qUDN87HH0jA== X-Microsoft-Antispam-Mailbox-Delivery: abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ex:0;auth:1;dest:I;WIMS-SenderIP:40.92.69.49;WIMS-SPF:windowslive%2ecom;WIMS-DKIM:windowslive%2ecom;WIMS-822:trojak3d%40windowslive%2ecom;WIMS-PRA:trojak3d%40windowslive%2ecom;WIMS-AUTH:PASS;ENG:(400001000128)(400125000095)(5062000261)(5061607266)(5061608174)(4900095)(4921089)(4950112)(4990090)(102400140)(400001001223)(400125100095)(61617095)(400001002128)(400125200095); PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv VFIvUkVDLWh0bWw0MCI+PGhlYWQ+DQo8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNv bnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCI+DQo8bWV0YSBuYW1lPSJHZW5lcmF0b3Ii IGNvbnRlbnQ9Ik1pY3Jvc29mdCBXb3JkIDE1IChmaWx0ZXJlZCBtZWRpdW0pIj4NCjwhLS1baWYg IW1zb10+PHN0eWxlPnZcOioge2JlaGF2aW9yOnVybCgjZGVmYXVsdCNWTUwpO30NCm9cOioge2Jl aGF2aW9yOnVybCgjZGVmYXVsdCNWTUwpO30NCndcOioge2JlaGF2aW9yOnVybCgjZGVmYXVsdCNW TUwpO30NCi5zaGFwZSB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0KPC9zdHlsZT48IVtl bmRpZl0tLT48c3R5bGU+PCEtLQ0KLyogRm9udCBEZWZpbml0aW9ucyAqLw0KQGZvbnQtZmFjZQ0K CXtmb250LWZhbWlseTpIZWx2ZXRpY2E7DQoJcGFub3NlLTE6MiAxMSA2IDQgMiAyIDIgMiAyIDQ7 fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseToiQ2FtYnJpYSBNYXRoIjsNCglwYW5vc2UtMToy IDQgNSAzIDUgNCA2IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6Q2FsaWJyaTsN CglwYW5vc2UtMToyIDE1IDUgMiAyIDIgNCAzIDIgNDt9DQovKiBTdHlsZSBEZWZpbml0aW9ucyAq Lw0KcC5Nc29Ob3JtYWwsIGxpLk1zb05vcm1hbCwgZGl2Lk1zb05vcm1hbA0KCXttYXJnaW46MGNt Ow0KCW1hcmdpbi1ib3R0b206LjAwMDFwdDsNCglmb250LXNpemU6MTEuMHB0Ow0KCWZvbnQtZmFt aWx5OiJDYWxpYnJpIixzYW5zLXNlcmlmO30NCmE6bGluaywgc3Bhbi5Nc29IeXBlcmxpbmsNCgl7 bXNvLXN0eWxlLXByaW9yaXR5Ojk5Ow0KCWNvbG9yOmJsdWU7DQoJdGV4dC1kZWNvcmF0aW9uOnVu ZGVybGluZTt9DQphOnZpc2l0ZWQsIHNwYW4uTXNvSHlwZXJsaW5rRm9sbG93ZWQNCgl7bXNvLXN0 eWxlLXByaW9yaXR5Ojk5Ow0KCWNvbG9yOnB1cnBsZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJs aW5lO30NCnAubXNvbm9ybWFsMCwgbGkubXNvbm9ybWFsMCwgZGl2Lm1zb25vcm1hbDANCgl7bXNv LXN0eWxlLW5hbWU6bXNvbm9ybWFsOw0KCW1zby1tYXJnaW4tdG9wLWFsdDphdXRvOw0KCW1hcmdp bi1yaWdodDowY207DQoJbXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG87DQoJbWFyZ2luLWxlZnQ6 MGNtOw0KCWZvbnQtc2l6ZToxMS4wcHQ7DQoJZm9udC1mYW1pbHk6IkNhbGlicmkiLHNhbnMtc2Vy aWY7fQ0Kc3Bhbi5FbWFpbFN0eWxlMTkNCgl7bXNvLXN0eWxlLXR5cGU6cGVyc29uYWwtcmVwbHk7 DQoJZm9udC1mYW1pbHk6IkNhbGlicmkiLHNhbnMtc2VyaWY7DQoJY29sb3I6d2luZG93dGV4dDt9 DQouTXNvQ2hwRGVmYXVsdA0KCXttc28tc3R5bGUtdHlwZTpleHBvcnQtb25seTsNCglmb250LWZh bWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjsNCgltc28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUzt9 DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6ZTo2MTIuMHB0IDc5Mi4wcHQ7DQoJbWFyZ2luOjcy LjBwdCA3Mi4wcHQgNzIuMHB0IDcyLjBwdDt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3BhZ2U6V29y ZFNlY3Rpb24xO30NCi0tPjwvc3R5bGU+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFw ZWRlZmF1bHRzIHY6ZXh0PSJlZGl0IiBzcGlkbWF4PSIxMDI2IiAvPg0KPC94bWw+PCFbZW5kaWZd LS0+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFwZWxheW91dCB2OmV4dD0iZWRpdCI+ DQo8bzppZG1hcCB2OmV4dD0iZWRpdCIgZGF0YT0iMSIgLz4NCjwvbzpzaGFwZWxheW91dD48L3ht bD48IVtlbmRpZl0tLT4NCjwvaGVhZD4NCjxib2R5IGxhbmc9IkVOLUdCIiBsaW5rPSJibHVlIiB2 bGluaz0icHVycGxlIj4NCjxkaXYgY2xhc3M9IldvcmRTZWN0aW9uMSI+DQo8cCBjbGFzcz0iTXNv Tm9ybWFsIj48c3BhbiBzdHlsZT0ibXNvLWZhcmVhc3QtbGFuZ3VhZ2U6RU4tVVMiPjxvOnA+Jm5i c3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJt c28tZmFyZWFzdC1sYW5ndWFnZTpFTi1VUyI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0K PHAgY2xhc3M9Ik1zb05vcm1hbCI+PGI+PHNwYW4gbGFuZz0iRU4tVVMiPkZyb206PC9zcGFuPjwv Yj48c3BhbiBsYW5nPSJFTi1VUyI+IFNlcnZpY2VAcGF5cGFJLmNvbSBbbWFpbHRvOmthaG5paWp1 bGVAamlhbnNrb2wuY29tXQ0KPGJyPg0KPGI+U2VudDo8L2I+IDI4IEp1bHkgMjAxNyAxMDoxNjxi cj4NCjxiPlRvOjwvYj4gdHJvamFrM2RAd2luZG93c2xpdmUuY29tPGJyPg0KPGI+U3ViamVjdDo8 L2I+IFtQYXlQYUkgbG5jXSBTdGF0ZW1lbnQgYWNjb3VudCB1bnVzdWFsIGFjdGl2aXR5IGxvZ2lu IHRvIHJlYWN0aXZhdGVkIDA3LzI4LzE3PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9 Ik1zb05vcm1hbCI+PG86cD4mbmJzcDs8L286cD48L3A+DQo8ZGl2IGFsaWduPSJjZW50ZXIiPg0K PHRhYmxlIGNsYXNzPSJNc29Ob3JtYWxUYWJsZSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIg Y2VsbHBhZGRpbmc9IjAiIHdpZHRoPSI1ODAiIHN0eWxlPSJ3aWR0aDo0MzUuMHB0Ij4NCjx0Ym9k eT4NCjx0cj4NCjx0ZCB3aWR0aD0iNTgwIiB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjQzNS4w cHQ7cGFkZGluZzowY20gMGNtIDBjbSAwY20iPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0YWJs ZSBjbGFzcz0iTXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxw YWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9IndpZHRoOjEwMC4wJSI+DQo8dGJvZHk+DQo8 dHI+DQo8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJiYWNrZ3JvdW5kOndoaXRlO3BhZGRpbmc6MGNt IDBjbSAxMi4wcHQgMGNtIj4NCjxkaXYgYWxpZ249ImNlbnRlciI+DQo8dGFibGUgY2xhc3M9Ik1z b05vcm1hbFRhYmxlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIg d2lkdGg9IjU4MCIgc3R5bGU9IndpZHRoOjQzNS4wcHQiPg0KPHRib2R5Pg0KPHRyPg0KPHRkIHdp ZHRoPSI1ODAiIHZhbGlnbj0idG9wIiBzdHlsZT0id2lkdGg6NDM1LjBwdDtwYWRkaW5nOjBjbSAw Y20gMGNtIDBjbSI+DQo8ZGl2IGFsaWduPSJjZW50ZXIiPg0KPHRhYmxlIGNsYXNzPSJNc29Ob3Jt YWxUYWJsZSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRo PSI1ODAiIHN0eWxlPSJ3aWR0aDo0MzUuMHB0Ij4NCjx0Ym9keT4NCjx0cj4NCjx0ZCB3aWR0aD0i NTgwIiB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjQzNS4wcHQ7cGFkZGluZzowY20gMGNtIDBj bSAwY20iPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0YWJsZSBjbGFzcz0iTXNvTm9ybWFsVGFi bGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAw JSIgc3R5bGU9IndpZHRoOjEwMC4wJSI+DQo8dGJvZHk+DQo8dHI+DQo8dGQgdmFsaWduPSJ0b3Ai IHN0eWxlPSJwYWRkaW5nOjEyLjBwdCAxMi4wcHQgMGNtIDEyLjBwdCI+DQo8cCBjbGFzcz0iTXNv Tm9ybWFsIj48Yj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjE1LjBwdDtmb250LWZhbWlseTomcXVv dDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZjtjb2xvcjp3aGl0ZSI+PHNwYW4gc3R5bGU9ImJv cmRlcjpzb2xpZCB3aW5kb3d0ZXh0IDEuMHB0O3BhZGRpbmc6MGNtIj48aW1nIHdpZHRoPSIxMjAi IGhlaWdodD0iMTIwIiBzdHlsZT0id2lkdGg6MS4yNWluO2hlaWdodDoxLjI1aW4iIGlkPSJfeDAw MDBfaTEwMjUiIHNyYz0iY2lkOmltYWdlMDAxLmpwZ0AwMUQzMDhCMi5DOTMxRUU5MCIgYWx0PSJJ bWFnZSByZW1vdmVkIGJ5IHNlbmRlci4gU2ltcGxlQXBwIj48L3NwYW4+PG86cD48L286cD48L3Nw YW4+PC9iPjwvcD4NCjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+DQo8L2Rpdj4NCjwv dGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+DQo8L2Rpdj4NCjwvdGQ+DQo8L3RyPg0KPC90 Ym9keT4NCjwvdGFibGU+DQo8L2Rpdj4NCjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+ DQo8L2Rpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0 LWFsaWduOmNlbnRlcjt2ZXJ0aWNhbC1hbGlnbjp0b3AiPg0KPG86cD4mbmJzcDs8L286cD48L3A+ DQo8ZGl2IGFsaWduPSJjZW50ZXIiPg0KPHRhYmxlIGNsYXNzPSJNc29Ob3JtYWxUYWJsZSIgYm9y ZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHls ZT0id2lkdGg6MTAwLjAlO0JPUkRFUi1TUEFDSU5HOiAwIj4NCjx0Ym9keT4NCjx0cj4NCjx0ZCB2 YWxpZ249InRvcCIgc3R5bGU9ImJhY2tncm91bmQ6I0YyRjJGNTtwYWRkaW5nOjBjbSAwY20gMGNt IDBjbSI+DQo8ZGl2IGFsaWduPSJjZW50ZXIiPg0KPHRhYmxlIGNsYXNzPSJNc29Ob3JtYWxUYWJs ZSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSI1ODAi IHN0eWxlPSJ3aWR0aDo0MzUuMHB0O0JPUkRFUi1TUEFDSU5HOiAwIj4NCjx0Ym9keT4NCjx0cj4N Cjx0ZCB3aWR0aD0iNTgwIiB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjQzNS4wcHQ7cGFkZGlu ZzowY20gMGNtIDBjbSAwY20iPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0YWJsZSBjbGFzcz0i TXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIw IiB3aWR0aD0iNTgwIiBzdHlsZT0id2lkdGg6NDM1LjBwdCI+DQo8dGJvZHk+DQo8dHI+DQo8dGQg d2lkdGg9IjU4MCIgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDo0MzUuMHB0O3BhZGRpbmc6MGNt IDBjbSAwY20gMGNtIj4NCjxkaXYgYWxpZ249ImNlbnRlciI+DQo8dGFibGUgY2xhc3M9Ik1zb05v cm1hbFRhYmxlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lk dGg9IjEwMCUiIHN0eWxlPSJ3aWR0aDoxMDAuMCUiPg0KPHRib2R5Pg0KPHRyPg0KPHRkIHN0eWxl PSJwYWRkaW5nOjBjbSAwY20gMGNtIDBjbSI+PC90ZD4NCjwvdHI+DQo8L3Rib2R5Pg0KPC90YWJs ZT4NCjwvZGl2Pg0KPC90ZD4NCjwvdHI+DQo8L3Rib2R5Pg0KPC90YWJsZT4NCjwvZGl2Pg0KPC90 ZD4NCjwvdHI+DQo8L3Rib2R5Pg0KPC90YWJsZT4NCjwvZGl2Pg0KPC90ZD4NCjwvdHI+DQo8L3Ri b2R5Pg0KPC90YWJsZT4NCjwvZGl2Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgYWxpZ249ImNlbnRl ciIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO3ZlcnRpY2FsLWFsaWduOnRvcCI+DQo8bzpwPiZu YnNwOzwvbzpwPjwvcD4NCjxkaXYgYWxpZ249ImNlbnRlciI+DQo8dGFibGUgY2xhc3M9Ik1zb05v cm1hbFRhYmxlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lk dGg9IjEwMCUiIHN0eWxlPSJ3aWR0aDoxMDAuMCU7Qk9SREVSLVNQQUNJTkc6IDAiPg0KPHRib2R5 Pg0KPHRyPg0KPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0iYmFja2dyb3VuZDp3aGl0ZTtwYWRkaW5n OjBjbSAwY20gMGNtIDBjbSI+DQo8ZGl2IGFsaWduPSJjZW50ZXIiPg0KPHRhYmxlIGNsYXNzPSJN c29Ob3JtYWxUYWJsZSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAi IHdpZHRoPSI1ODAiIHN0eWxlPSJ3aWR0aDo0MzUuMHB0O0JPUkRFUi1TUEFDSU5HOiAwIj4NCjx0 Ym9keT4NCjx0cj4NCjx0ZCB3aWR0aD0iNTgwIiB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjQz NS4wcHQ7cGFkZGluZzowY20gMGNtIDBjbSAwY20iPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0 YWJsZSBjbGFzcz0iTXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNl bGxwYWRkaW5nPSIwIiB3aWR0aD0iNTgwIiBzdHlsZT0id2lkdGg6NDM1LjBwdCI+DQo8dGJvZHk+ DQo8dHI+DQo8dGQgd2lkdGg9IjU4MCIgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDo0MzUuMHB0 O3BhZGRpbmc6MGNtIDBjbSAwY20gMGNtIj4NCjxkaXYgYWxpZ249ImNlbnRlciI+DQo8dGFibGUg Y2xhc3M9Ik1zb05vcm1hbFRhYmxlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFk ZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSJ3aWR0aDoxMDAuMCUiPg0KPHRib2R5Pg0KPHRy Pg0KPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0icGFkZGluZzoxMi4wcHQgMTIuMHB0IDEyLjBwdCAx Mi4wcHQiPg0KPHAgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDoxLjVwdDttYXJnaW4tcmlnaHQ6 MGNtO21hcmdpbi1ib3R0b206MTguMHB0O21hcmdpbi1sZWZ0OjBjbTttc28tbGluZS1oZWlnaHQt YWx0OjkuMHB0Ij4NCjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTYuNXB0O2ZvbnQtZmFtaWx5OiZx dW90O0hlbHZldGljYSZxdW90OyxzYW5zLXNlcmlmO2NvbG9yOiMwMDlDREUiPldlIG5lZWQgeW91 ciBoZWxwIHRvIHJlc29sdmUgdW5hdXRob3JpemVkIGFjdGl2aXRlczxvOnA+PC9vOnA+PC9zcGFu PjwvcD4NCjxwIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6MTAuNXB0O21hcmdpbi1yaWdodDow Y207bWFyZ2luLWJvdHRvbToxOC4wcHQ7bWFyZ2luLWxlZnQ6MGNtO2xpbmUtaGVpZ2h0OjkuMHB0 Ij4NCjxzcGFuIHN0eWxlPSJmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7SGVsdmV0 aWNhJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6Izg4ODg4OCI+RGVhciBDbGllbnQsPG86cD48L286 cD48L3NwYW4+PC9wPg0KPHAgc3R5bGU9Im1zby1tYXJnaW4tdG9wLWFsdDoxMC41cHQ7bWFyZ2lu LXJpZ2h0OjBjbTttYXJnaW4tYm90dG9tOjE1LjBwdDttYXJnaW4tbGVmdDowY207bGluZS1oZWln aHQ6MTMuNXB0Ij4NCjxzcGFuIHN0eWxlPSJmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6JnF1 b3Q7SGVsdmV0aWNhJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6Izg4ODg4OCI+V2UganVzdCB3YW50 ZWQgdG8gY29uZmlybSB0aGF0IHlvdSd2ZSBjaGFuZ2VkIHlvdXIgcGFzc3dvcmQuIElmIHlvdSBk aWRuJ3QgbWFrZSB0aGlzIGNoYW5nZSwgcGxlYXNlIGNoZWNrIGluZm9ybWF0aW9uIGluIGhlcmUu IEl0J3MgaW1wb3J0YW50IHRoYXQgeW91IGxldCB1cyBrbm93IGJlY2F1c2UgaXQgaGVscHMNCiB1 cyBwcmV2ZW50IHVuYXV0aG9yaXNlZCBwZXJzb25zIGZyb20gYWNjZXNzaW5nIHRoZSBQYXlQYWwg bmV0d29yayBhbmQgeW91ciBhY2NvdW50IGluZm9ybWF0aW9uLjxvOnA+PC9vOnA+PC9zcGFuPjwv cD4NCjxwIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6OS4wcHQ7bWFyZ2luLXJpZ2h0OjBjbTtt YXJnaW4tYm90dG9tOjE4LjBwdDttYXJnaW4tbGVmdDowY207bGluZS1oZWlnaHQ6MTMuNXB0Ij4N CjxzcGFuIHN0eWxlPSJmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7SGVsdmV0aWNh JnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6Izg4ODg4OCI+V2UndmUgbm90aWNlZCBzb21lIGNoYW5n ZXMgdG8geW91ciB1bnN1YWwgc2VsbGluZyBhY3Rpdml0aWVzIGFuZCB3aWxsIG5lZWQgc29tZSBt b3JlIGluZm9ybWF0aW9uIGFib3V0IHlvdXIgcmVjZW50IHNhbGVzLjxvOnA+PC9vOnA+PC9zcGFu PjwvcD4NCjxkaXYgYWxpZ249ImNlbnRlciI+DQo8dGFibGUgY2xhc3M9Ik1zb05vcm1hbFRhYmxl IiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgc3R5bGU9IkJPUkRF Ui1TUEFDSU5HOiAwIj4NCjx0Ym9keT4NCjx0cj4NCjx0ZCBzdHlsZT0iYmFja2dyb3VuZDojMDA5 Q0RFO3BhZGRpbmc6OS4wcHQgMTguMHB0IDkuMHB0IDE4LjBwdDstd2Via2l0LWJvcmRlci1yYWRp dXM6IDRweDtib3JkZXItcmFkaXVzOiA0cHgiPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgYWxpZ249 ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj48c3BhbiBzdHlsZT0iZm9udC1zaXpl OjEwLjBwdDtmb250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZiI+PGEg aHJlZj0iaHR0cDovL293Lmx5L3FlTDMzMGRZek8yIj48Yj48c3BhbiBzdHlsZT0iY29sb3I6d2hp dGU7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkNvbmZpcm0geW91ciBlbWFpbDwvc3Bhbj48L2I+PC9h PjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+ DQo8L2Rpdj4NCjxwIHN0eWxlPSJtc28tbWFyZ2luLXRvcC1hbHQ6MTIuMHB0O21hcmdpbi1yaWdo dDowY207bWFyZ2luLWJvdHRvbToxOC4wcHQ7bWFyZ2luLWxlZnQ6MGNtO2xpbmUtaGVpZ2h0OjEz LjVwdCI+DQo8c3BhbiBzdHlsZT0iZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0hl bHZldGljYSZxdW90OyxzYW5zLXNlcmlmO2NvbG9yOiM4ODg4ODgiPlRoYW5rIHlvdSBmb3IgeW91 ciB1bmRlcnN0YW5kaW5nIGFuZCBjb29wZXJhdGlvbi4gSWYgeW91IG5lZWQgZnVydGhlciBhc3Np c3RhbmNlLCBwbGVhc2UgY2xpY2sgQ29udGFjdCBhdCB0aGUgYm90dG9tIG9mIGFueSBQYXlQYWwg cGFnZS48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBzdHlsZT0ibXNvLW1hcmdpbi10b3AtYWx0 OjEyLjBwdDttYXJnaW4tcmlnaHQ6MGNtO21hcmdpbi1ib3R0b206OS4wcHQ7bWFyZ2luLWxlZnQ6 MGNtO2xpbmUtaGVpZ2h0OjE3LjI1cHQiPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo5LjBwdDtm b250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZjtjb2xvcjojODg4ODg4 Ij5TaW5jZXJlbHksPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgc3R5bGU9Im1zby1tYXJnaW4t dG9wLWFsdDo3LjVwdDttYXJnaW4tcmlnaHQ6MGNtO21hcmdpbi1ib3R0b206OS4wcHQ7bWFyZ2lu LWxlZnQ6MGNtO2xpbmUtaGVpZ2h0OjE3LjI1cHQiPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo5 LjBwdDtmb250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZjtjb2xvcjoj ODg4ODg4Ij5QYXlQYWw8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8L3RkPg0KPC90cj4NCjwvdGJv ZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L3RkPg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0K PC9kaXY+DQo8L3RkPg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L3RkPg0K PC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBh bGlnbj0iY2VudGVyIiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXI7dmVydGljYWwtYWxpZ246dG9w Ij4NCjxvOnA+Jm5ic3A7PC9vOnA+PC9wPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0YWJsZSBj bGFzcz0iTXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRk aW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9IndpZHRoOjEwMC4wJTtCT1JERVItU1BBQ0lORzog MCI+DQo8dGJvZHk+DQo8dHI+DQo8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJib3JkZXI6bm9uZTti b3JkZXItdG9wOnNvbGlkICNEOERERTQgMS4wcHQ7YmFja2dyb3VuZDojRjJGMkY1O3BhZGRpbmc6 MGNtIDBjbSAxMi4wcHQgMGNtOy13ZWJraXQtYm9yZGVyLXJhZGl1czogMCAwIDRweCA0cHg7Ym9y ZGVyLXJhZGl1czogMCAwIDRweCA0cHgiPg0KPGRpdiBhbGlnbj0iY2VudGVyIj4NCjx0YWJsZSBj bGFzcz0iTXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRk aW5nPSIwIiB3aWR0aD0iNTgwIiBzdHlsZT0id2lkdGg6NDM1LjBwdDstd2Via2l0LWJvcmRlci1y YWRpdXM6IDAgMCA0cHggNHB4O2JvcmRlci1yYWRpdXM6IDAgMCA0cHggNHB4Ij4NCjx0Ym9keT4N Cjx0cj4NCjx0ZCB3aWR0aD0iNTgwIiB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjQzNS4wcHQ7 cGFkZGluZzowY20gMGNtIDBjbSAwY207Qk9SREVSLVNQQUNJTkc6IDAiPg0KPGRpdiBhbGlnbj0i Y2VudGVyIj4NCjx0YWJsZSBjbGFzcz0iTXNvTm9ybWFsVGFibGUiIGJvcmRlcj0iMCIgY2VsbHNw YWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iNTgwIiBzdHlsZT0id2lkdGg6NDM1LjBw dCI+DQo8dGJvZHk+DQo8dHI+DQo8dGQgd2lkdGg9IjM5MCIgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3 aWR0aDoyOTIuNXB0O3BhZGRpbmc6MGNtIDBjbSAwY20gMGNtIj4NCjxkaXYgYWxpZ249ImNlbnRl ciI+DQo8dGFibGUgY2xhc3M9Ik1zb05vcm1hbFRhYmxlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5n PSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSJ3aWR0aDoxMDAuMCUiPg0K PHRib2R5Pg0KPHRyPg0KPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0icGFkZGluZzo5LjBwdCAxMi4w cHQgMGNtIDEyLjBwdCI+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1z aXplOjcuNXB0O2ZvbnQtZmFtaWx5OiZxdW90O0hlbHZldGljYSZxdW90OyxzYW5zLXNlcmlmIj48 YSBocmVmPSJodHRwOi8vcGF5cGFsLmNvbSI+PHNwYW4gc3R5bGU9ImNvbG9yOiMwMDlDREUiPkhl bHANCjwvc3Bhbj48L2E+fCA8YSBocmVmPSJodHRwOi8vcGF5cGFsLmNvbSI+PHNwYW4gc3R5bGU9 ImNvbG9yOiMwMDlDREUiPlJlc29sdXRpb24gPC9zcGFuPg0KPC9hPnwgPGEgaHJlZj0iaHR0cDov L3BheXBhbC5jb20iPjxzcGFuIHN0eWxlPSJjb2xvcjojMDA5Q0RFIj5TZWN1cml0eSBDZW50cmU8 L3NwYW4+PC9hPg0KPG86cD48L286cD48L3NwYW4+PC9wPg0KPHA+PHNwYW4gc3R5bGU9ImZvbnQt c2l6ZTo3LjVwdDtmb250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZiI+ UGxlYXNlIGRvIG5vdCByZXBseSB0byB0aGlzIGVtYWlsLiBUbyBnZXQgaW4gdG91Y2ggd2l0aCB1 cywgY2xpY2sNCjxhIGhyZWY9Imh0dHA6Ly9wYXlwYWwuY29tIj48c3BhbiBzdHlsZT0iY29sb3I6 IzAwOUNERSI+SGVscCAmYW1wOyBDb250YWN0Ljwvc3Bhbj48L2E+PG86cD48L286cD48L3NwYW4+ PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo3LjVwdDtm b250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssc2Fucy1zZXJpZiI+PGJyPg0KQ29weXJp Z2h0IMKpIDE5OTkg4oCTIDIwMTcgUGF5UGFsLiBBbGwgcmlnaHRzIHJlc2VydmVkLiA8YnI+DQo8 YnI+DQpDb25zdW1lciBhZHZpc29yeSAtIFBheVBhbCBQdGUuIEx0ZC4gdGhlIGhvbGRlciBvZiBQ YXlQYWwncyBzdG9yZWQgdmFsdWUgZmFjaWxpdHksIGRvZXMgbm90IHJlcXVpcmUgdGhlIGFwcHJv dmFsIG9mIHRoZSBNb25ldGFyeSBBdXRob3JpdHkgb2YgU2luZ2Fwb3JlLiBVc2VycyBhcmUgYWR2 aXNlZCB0byByZWFkIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBjYXJlZnVsbHkuPGJyPg0KPGJy Pg0KUGF5UGFsIFBQWDAwMTg4OToyMTNlZTFiZjYxODdlIDxvOnA+PC9vOnA+PC9zcGFuPjwvcD4N CjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+DQo8L2Rpdj4NCjwvdGQ+DQo8dGQgd2lk dGg9IjE5MCIgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDoxNDIuNXB0O3BhZGRpbmc6MGNtIDBj bSAwY20gMGNtIj48L3RkPg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L3Rk Pg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L3RkPg0KPC90cj4NCjwvdGJv ZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L3RkPg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0K PC9kaXY+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZuYnNwOzwvbzpwPjwvcD4NCjwvZGl2 Pg0KPC9ib2R5Pg0KPC9odG1sPg0K --_000_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_-- --_004_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_ Content-Type: image/jpeg; name="image001.jpg" Content-Description: image001.jpg Content-Disposition: inline; filename="image001.jpg"; size=500; creation-date="Sat, 29 Jul 2017 20:36:56 GMT"; modification-date="Sat, 29 Jul 2017 20:36:56 GMT" Content-ID: Content-Transfer-Encoding: base64 X-Microsoft-Exchange-Diagnostics: 1;DB6P192MB0231;27:wPFlVOQ8iMAXT+N6591mBRfClfXdhMLmsxh/Y7d1LVbWrHPkVIxvj9+3g1ttW81Vi7Xh16wwzAIakEj5LqQ7s3r7Kr3/lVOL94eT9Ky+Tm+IqokcaiD5Q9lLzBrvUIz0CJDh27WR+m3qUDN87HH0jA== X-Microsoft-Antispam-Mailbox-Delivery: abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ex:0;auth:1;dest:I;WIMS-SenderIP:40.92.69.49;WIMS-SPF:windowslive%2ecom;WIMS-DKIM:windowslive%2ecom;WIMS-822:trojak3d%40windowslive%2ecom;WIMS-PRA:trojak3d%40windowslive%2ecom;WIMS-AUTH:PASS;ENG:(400001000128)(400125000095)(5062000261)(5061607266)(5061608174)(4900095)(4921089)(4950112)(4990090)(102400140)(400001001223)(400125100095)(61617095)(400001002128)(400125200095); /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIf IiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/wAALCAB4AHgBAREA/8QAHwAAAQUBAQEB AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APZqKKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK/9k= --_004_AM4PR0901MB1219E3152878394D9F48EFB982BC0AM4PR0901MB1219_--";
preg_match($regex_html,$email,$return);
print_r($return);
and heres my function:
function multipart_msg_body($inbox, $email_number){
$structure = imap_fetchstructure($inbox, $email_number);
$encoding_type = array("base64","quoted-printable","8bit","7bit","binary");
$message_body_parts = array();
if (array_key_exists(1,$structure->parameters)){
$type = $structure->parameters[1]->value;
if ($type == "multipart/alternative"){
$message = imap_body($inbox, $email_number);
foreach($encoding_type as $type){
$regex_html = '/(?<=Content-Type: text\/html;).*?(Content-Transfer-Encoding:).*?('.$type.').*?(\);).(.*?)(?= --_)/';
$regex_plain = '/(?<=Content-Type: text\/plain;).*?(Content-Transfer-Encoding:).*?('.$type.').*?(\);).(.*?)(?= --_)/';
$body_html = preg_match($regex_html,$message,$html_match);
$body_plain = preg_match($regex_plain,$message,$plain_match);
print_r($html_match);
if ($body_html){
$message_body_parts["html_".$type] = $html_match;
}
if ($body_plain){
$message_body_parts["plain_".$type] = $body_plain;
}
}
print_r($message_body_parts);
}
}
}
Solved:
Different regex was required as imap_body() and print_r(imap_body()) seem to generate a different string to work with.
function multipart_msg_body($inbox, $email_number){
$structure = imap_fetchstructure($inbox, $email_number);
$encoding_type = array("base64","quoted-printable","8bit","7bit","binary");
$message_body_parts = array();
if (array_key_exists(1,$structure->parameters)){
$type = $structure->parameters[1]->value;
if ($type == "multipart/alternative"){
$message = imap_body($inbox, $email_number, FT_INTERNAL);
foreach($encoding_type as $type){
$regex_html = "/(?<=Content-Type: text\/html;).*?(Content-Transfer-Encoding:).*?(".$type.").*?(\);)(.*?)(--_)/s";
$regex_plain = "/(?<=Content-Type: text\/plain;).*?(Content-Transfer-Encoding:).*?(".$type.").*?(\);)(.*?)(--_)/s";
$body_html = preg_match($regex_html,$message,$html_match);
$body_plain = preg_match($regex_plain,$message,$plain_match);
if ($body_html){
$message_body_parts["html_".$type] = $html_match[4];
}
if ($body_plain){
$message_body_parts["plain_".$type] = $plain_match[4];
}
}
return($message_body_parts);
}
}
}
Right, as I suspected, imap_body() is formed slightly different as a variable on its own to what the result of print_r(imap_body()), I've saved the variable into a file and ammended my regex to work with that, all works sweet now.
New regex:
$regex_html = "/(?<=Content-Type: text\/html;).*?(Content-Transfer-Encoding:).*?(".$type.").*?(\);)(.*?)(--_)/s";
hope this helps, a lot easier and possibly quicker way of finding the plain and html body of a multipart imap message. Thanks for all contributions.
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;
}
}
}
}
#!/usr/bin/php -q
<?php
$savefile = "savehere.txt";
$sf = fopen($savefile, 'a') or die("can't open file");
ob_start();
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
// handle email
$lines = explode("\n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i < count($lines); $i++) {
if ($splittingheaders) {
// this is a header
$headers .= $lines[$i]."\n";
// look out for special headers
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
/*$headers is ONLY included in the result at the last section of my question here*/
fwrite($sf,"$message");
ob_end_clean();
fclose($sf);
?>
That is an example of my attempt. The problem is I am getting too much in the file.
Here is what is being written to the file: (I just sent a bunch of garbage to it as you can see)
From xxxxxxxxxxxxx Tue Sep 07 16:26:51 2010
Received: from xxxxxxxxxxxxxxx ([xxxxxxxxxxx]:3184 helo=xxxxxxxxxxx)
by xxxxxxxxxxxxx with esmtpa (Exim 4.69)
(envelope-from <xxxxxxxxxxxxxxxx>)
id 1Ot4kj-000115-SP
for xxxxxxxxxxxxxxxxxxx; Tue, 07 Sep 2010 16:26:50 -0400
Message-ID: <EE3B7E26298140BE8700D9AE77CB339D#xxxxxxxxxxx>
From: "xxxxxxxxxxxxx" <xxxxxxxxxxxxxx>
To: <xxxxxxxxxxxxxxxxxxxxx>
Subject: stackoverflow is helping me
Date: Tue, 7 Sep 2010 16:26:46 -0400
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_NextPart_000_0169_01CB4EA9.773DF5E0"
X-Priority: 3
X-MSMail-Priority: Normal
Importance: Normal
X-Mailer: Microsoft Windows Live Mail 14.0.8089.726
X-MIMEOLE: Produced By Microsoft MimeOLE V14.0.8089.726
This is a multi-part message in MIME format.
------=_NextPart_000_0169_01CB4EA9.773DF5E0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
111
222
333
444
------=_NextPart_000_0169_01CB4EA9.773DF5E0
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content=3Dtext/html;charset=3Diso-8859-1 =
http-equiv=3DContent-Type>
<META name=3DGENERATOR content=3D"MSHTML 8.00.6001.18939"></HEAD>
<BODY style=3D"PADDING-LEFT: 10px; PADDING-RIGHT: 10px; PADDING-TOP: =
15px"=20
id=3DMailContainerBody leftMargin=3D0 topMargin=3D0 =
CanvasTabStop=3D"true"=20
name=3D"Compose message area">
<DIV><FONT face=3DCalibri>111</FONT></DIV>
<DIV><FONT face=3DCalibri>222</FONT></DIV>
<DIV><FONT face=3DCalibri>333</FONT></DIV>
<DIV><FONT face=3DCalibri>444</FONT></DIV></BODY></HTML>
------=_NextPart_000_0169_01CB4EA9.773DF5E0--
I found this while searching around but have no idea how to implement or where to insert in my code or if it would work.
preg_match("/boundary=\".*?\"/i", $headers, $boundary);
$boundaryfulltext = $boundary[0];
if ($boundaryfulltext!="")
{
$find = array("/boundary=\"/i", "/\"/i");
$boundarytext = preg_replace($find, "", $boundaryfulltext);
$splitmessage = explode("--" . $boundarytext, $message);
$fullmessage = ltrim($splitmessage[1]);
preg_match('/\n\n(.*)/is', $fullmessage, $splitmore);
if (substr(ltrim($splitmore[0]), 0, 2)=="--")
{
$actualmessage = $splitmore[0];
}
else
{
$actualmessage = ltrim($splitmore[0]);
}
}
else
{
$actualmessage = ltrim($message);
}
$clean = array("/\n--.*/is", "/=3D\n.*/s");
$cleanmessage = trim(preg_replace($clean, "", $actualmessage));
So, how can I get just the plain text area of the email into my file or script for furthr handling??
Thanks in advance. stackoverflow is great!
There are four steps that you will have to take in order to isolate the plain text part of your email body:
1. Get the MIME boundary string
We can use a regular expression to search your headers (let's assume they're in a separate variable, $headers):
$matches = array();
preg_match('#Content-Type: multipart\/[^;]+;\s*boundary="([^"]+)"#i', $headers, $matches);
list(, $boundary) = $matches;
The regular expression will search for the Content-Type header that contains the boundary string, and then capture it into the first capture group. We then copy that capture group into variable $boundary.
2. Split the email body into segments
Once we have the boundary, we can split the body into its various parts (in your message body, the body will be prefaced by -- each time it appears). According to the MIME spec, everything before the first boundary should be ignored.
$email_segments = explode('--' . $boundary, $message);
array_shift($email_segments); // drop everything before the first boundary
This will leave us with an array containing all the segments, with everything before the first boundary ignored.
3. Determine which segment is plain text.
The segment that is plain text will have a Content-Type header with the MIME-type text/plain. We can now search each segment for the first segment with that header:
foreach ($email_segments as $segment)
{
if (stristr($segment, "Content-Type: text/plain") !== false)
{
// We found the segment we're looking for!
}
}
Since what we're looking for is a constant, we can use stristr (which finds the first instance of a substring in a string, case insensitively) instead of a regular expression. If the Content-Type header is found, we've got our segment.
4. Remove any headers from the segment
Now we need to remove any headers from the segment we found, as we only want the actual message content. There are four MIME headers that can appear here: Content-Type as we saw before, Content-ID, Content-Disposition and Content-Transfer-Encoding. Headers are terminated by \r\n so we can use that to determine the end of the headers:
$text = preg_replace('/Content-(Type|ID|Disposition|Transfer-Encoding):.*?\r\n/is', "", $segment);
The s modifier at the end of the regular expression makes the dot match any newlines. .*? will collect as few characters as possible (ie. everything up to \r\n); the ? is a lazy modifier on .*.
And after this point, $text will contain your email message content.
So to put it all together with your code:
<?php
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd))
{
$email .= fread($fd, 1024);
}
fclose($fd);
$matches = array();
preg_match('#Content-Type: multipart\/[^;]+;\s*boundary="([^"]+)"#i', $email, $matches);
list(, $boundary) = $matches;
$text = "";
if (isset($boundary) && !empty($boundary)) // did we find a boundary?
{
$email_segments = explode('--' . $boundary, $email);
foreach ($email_segments as $segment)
{
if (stristr($segment, "Content-Type: text/plain") !== false)
{
$text = trim(preg_replace('/Content-(Type|ID|Disposition|Transfer-Encoding):.*?\r\n/is', "", $segment));
break;
}
}
}
// At this point, $text will either contain your plain text body,
// or be an empty string if a plain text body couldn't be found.
$savefile = "savehere.txt";
$sf = fopen($savefile, 'a') or die("can't open file");
fwrite($sf, $text);
fclose($sf);
?>
There is one answer here:
You need only to change these 2 lines:
require_once('/path/to/class/rfc822_addresses.php');
require_once('/path/to/class/mime_parser.php');
Is there a way I can add a soap attachment to a request using PHP's built-in SoapClient classes? It doesn't look like it's supported, but maybe I can manually build the mime boundaries? I know the PEAR SOAP library supports them, but in order to use that I have to rewrite my entire library to use it.
Why don't you just send files using Data URI scheme rather than implement SoapAttachment ? Here is an example :
Client
$client = new SoapClient(null, array(
'location' => "http://localhost/lab/stackoverflow/a.php?h=none",
'uri' => "http://localhost/",
'trace' => 1
));
// Method 1 Array
// File to upload
$file = "golf3.png";
// First Example
$data = array();
$data['name'] = $file;
$data['data'] = getDataURI($file, "image/png");
echo "Example 1: ";
echo ($return = $client->upload($data)) ? "File Uploaded : $return bytes" : "Error Uploading Files";
// Method 2 Objects
// File to upload
$file = "original.png";
// Second Example
$attachment = new ImageObj($file);
$param = new SoapVar($attachment, SOAP_ENC_OBJECT, "ImageObj");
$param = new SoapParam($param, "param");
echo "Example 2: ";
echo ($return = $client->uploadObj($attachment)) ? "File Uploaded : $return bytes" : "Error Uploading Files";
Output
Example 1: File Uploaded : 976182 bytes
Example 2: File Uploaded : 233821 bytes
Server
class UploadService {
public function upload($args) {
$file = __DIR__ . "/test/" . $args['name'];
return file_put_contents($file, file_get_contents($args['data']));
}
public function uploadObj($args) {
$file = __DIR__ . "/test/" . $args->name;
$data = sprintf("data://%s;%s,%s", $args->mime, $args->encoding, $args->data);
return file_put_contents($file, file_get_contents($data));
}
}
try {
$server = new SOAPServer(NULL, array(
'uri' => 'http://localhost/'
));
$server->setClass('UploadService');
$server->handle();
} catch (SOAPFault $f) {
print $f->faultstring;
}
Client Util
// Function Used
function getDataURI($image, $mime = '') {
return 'data: ' . (function_exists('mime_content_type') ?
mime_content_type($image) : $mime) . ';base64,' .
base64_encode(file_get_contents($image));
}
// Simple Image Object
class ImageObj{
function __construct($file, $mime = "") {
$this->file = $file;
$this->name = basename($file);
if (function_exists('mime_content_type')) {
$this->mime = mime_content_type($file);
} elseif (function_exists('finfo_open')) {
$this->mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file);
} else {
$this->mime = $mime;
}
$this->encoding = "base64";
$this->data = base64_encode(file_get_contents($file));
}
}
Yes, you can build the MIME component of the message using something like imap_mail_compose.
You'll need to construct a multipart message as they do in the first example, putting the XML from the $request parameter, from an overridden SoapClient::__doRequest method, into the first part of the MIME message.
Then you can do as others have shown in the first imap_mail_compose example to add one or more messages parts with attachments. These attachements can, but do not have to be base64 encoded, they can just as well be binary. The encoding for each part is specified by part-specific headers.
You'll also need to cook up an appropriate set of HTTP headers, per the SwA Document #Baba linked to earlier.
Once it's all said and done, you should have something looking like the examples from that document:
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
start="<claim061400a.xml#claiming-it.com>"
Content-Description: This is the optional message description.
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <claim061400a.xml#claiming-it.com>
<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
..
<theSignedForm href="cid:claim061400a.tiff#claiming-it.com"/>
..
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-ID: <claim061400a.tiff#claiming-it.com>
...binary TIFF image...
--MIME_boundary--
And you can send that across the wire with the aforementioned overridden SoapClient::__doRequest method. Things I have noticed in trying to implement it myself thus far:
You may need to create an href URI reference from each SOAP node to the corresponding attachment, something like href="cid:claim061400a.tiff#claiming-it.com" above
You will need to extract the boundary component from the MIME content returned by imap_mail_compose for use in an HTTP Content-Type header
Don't forget the start component of the Content-Type header either, it should look something like this:
imap_mail_compose appears fairly minimal (but low hanging fruit), if it proves insufficient, consider Mail_Mime instead
Content-Type: Multipart/Related; boundary=MIME_boundary;
type=text/xml; start=""
Lastly, I'm not sure how evenly the various implementations of SwA are out there on the Internet... Suffice it to say, I've not been able to get an upload to a remote service with a crude implementation of what I've described above yet. It does seem like SwA is the typical SOAP attachment paradigm of choice though, from what I gather reading around on the net.