Reading an email's subject in Unicode out of an IMAP server - php

I'm using Zend Framework 1's IMAP server connector and I'm trying to fetch an email from server with Unicode characters in its subject. Here's how I do it:
$message = $imapServer->getMessage($message_number);
echo $message->getHeader('subject');
The problem is that it comes out encoded:
=?UTF-8?B?2KjYp9uM?=
I can find the encoding function within Zend_Mail class named _encodeHeader but I can not find the decoding pair! Does anyone know how to decode this string?
And here's the encoder function:
protected function _encodeHeader($value)
{
if (Zend_Mime::isPrintable($value) === false) {
if ($this->getHeaderEncoding() === Zend_Mime::ENCODING_QUOTEDPRINTABLE) {
$value = Zend_Mime::encodeQuotedPrintableHeader($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
} else {
$value = Zend_Mime::encodeBase64Header($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
}
}
return $value;
}

Search for a "RFC2047 decoder" and pick one of the existing libraries which does just that. If nothing is usable, roll your own.

Here's how I solved it:
switch (strtolower($encoding)) {
case \Zend_Mime::ENCODING_QUOTEDPRINTABLE:
if (preg_match('/^\s?=\?([^\?]+)\?Q\?/', $str, $matches) === 1) {
$str = preg_replace('/\s?=\?'.preg_quote($matches[1]).'\?Q\?/', ' ', $str);
$str = strtr($str, array('?=' => ''));
$str = trim($str);
}
return \Zend_Mime_Decode::decodeQuotedPrintable($str);
case \Zend_Mime::ENCODING_BASE64:
return base64_decode($encodedText);
case \Zend_Mime::ENCODING_7BIT:
case \Zend_Mime::ENCODING_8BIT:
default:
return $encodedText;
}

Related

How to search for strings of webpage without saving content?

I know of one method where you can do this:
$url = "http://www.google.com/search?q=test";
$str = file_get_contents($url);
preg_match("title/tt\d{7}?/", $str, $matches);
print $matches[0];
But this reads the whole file and then scans for the match.Is there anyway I can reduce the time time taken for doing the above process of matching?
If you know where inside the webpage you need to look (i.e only the first 3000 characters or so), you can use the maxlen parameter in file_get_contents to limit the reading:
file_get_contents($url, false, NULL, -1, 3000);
UPDATE
If you don't know where to look in the webpage and you want to minimize http request length, I worked up a nice solution for you :))
$url = "www.google.com";
$step = 3000;
$found = false;
$addr = gethostbyname($url);
$client = stream_socket_client("tcp://$addr:80", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
fwrite($client, "GET /search?q=test HTTP/1.0\r\nHost: $url\r\nAccept: */*\r\n\r\n");
$str = "";
while(!feof($client)){
$str .= stream_get_contents($client, $step, -1);
if(preg_match("/tt\d{7}?/", $str, $matches)){
$found = true;
break;
}
}
fclose($client);
if($found){
echo $matches[0];
} else {
echo "not found";
}
EXPLANATION:
set the $step variable to be the number of bytes to read each iteration, and change the "search?q=test" to your desired query (IMDB titles, judging by your regex? :) ). It will do the job wonderfully.
You can also do echo $str after the while loop to see exactly how much it has read until it found the requested string.
I believe this was what you were looking for.

Why this error is showing?

I'm facing a strange error sometimes on my php wap site! Its not persistent, just occurs somwtimes & If I refresh page, error is went out and normal page appears. I'm attaching errors screenshot-
172 line of fun.inc.php is-
return mysql_real_escape_string($str);
I'm pasting line 164 to 212 for better understanding
function clean($str)
{
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
$str = str_replace("<",'',$str);
$str = str_replace(">",'',$str);
}
return mysql_real_escape_string($str);
}
function regchars($word){
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
for($i=0;$i<strlen($word);$i++){
$ch = substr($word,$i,1);
$nol = substr_count($chars,$ch);
if($nol==0){
return true;
}
}
return false;
}
function nospace($word){
$pos = strpos($word," ");
if($pos === false){
return false;
}else{
return true;
}
}
function checknumber($word){
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$ch = substr($word,0,1);
$sres = ereg("[0-9]",$ch);
$ch = substr($word,0,1);
$nol = substr_count($chars,$ch);
if($nol==0){
return true;
}
return false;
}
function registerform($ef)
{
$errl = "";
switch($ef)
{
Is its a problem of my code or problem from hosting server? How can I prevent users from showing such code??
The function mysql_real_escape_string requires a database connection, so that it can detect what character set is in use and escape correctly.
However, you should not be using that library at all - it is now deprecated. Use either PDO or mysqli, and switch to parameterisation rather than escaping values prior to inserting them yourself.
It seems also that PHP is attempting to connect to the current database as root. Where you do establish a connection, bear in mind that connecting with root is a bad idea. Connect with a user having the least permissions possible for your application to work.
You are not connected to MySQL. You can remove this function if you do not want to do something SQL queries with that.

Case-insensitive PSpell spell checking?

I'd like to use PHP's PSpell check function in my program. Is there an option somewhere for case-insensitive checking in pspell_check()?
I've found a way around the lack of an option for case insensitivity. PSpell's suggestion function seems to always return the correct capitalization of a mis-capitalized word as its first suggestion, so we can check for this if the initial spell check fails:
<?php
function pspell_icheck($dictionary_link, $word) {
return ( pspell_check($dictionary_link, $word) ||
strtolower(reset(pspell_suggest($dictionary_link, $word))) == strtolower($word) );
}
$dict = pspell_new('en');
$word = 'foo';
echo pspell_icheck($dict, $word);
?>
Works on PHP 5.3.2. Happy coding :)
Try this patch http://code.google.com/p/patched-pspell/ . It enables you to set any options.
pspell_config_set($pspell_config, 'ignore-case', 'true');
There is an easy solution. Just do this:
$word = ucfirst($word); //Always capitalize to avoid case sensitive error
if (!pspell_check($dict, $word)) {
$suggestions = pspell_suggest($dictionary, $word);
}

IP Address Validation Help

I am using this IP Validation Function that I came across while browsing, it has been working well until today i ran into a problem.
For some reason the function won't validate this IP as valid: 203.81.192.26
I'm not too great with regular expressions, so would appreciate any help on what could be wrong.
If you have another function, I would appreciate if you could post that for me.
The code for the function is below:
public static function validateIpAddress($ip_addr)
{
global $errors;
$preg = '#^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}' .
'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$#';
if(preg_match($preg, $ip_addr))
{
//now all the intger values are separated
$parts = explode(".", $ip_addr);
//now we need to check each part can range from 0-255
foreach($parts as $ip_parts)
{
if(intval($ip_parts) > 255 || intval($ip_parts) < 0)
{
$errors[] = "ip address is not valid.";
return false;
}
return true;
}
return true;
} else {
$errors[] = "please double check the ip address.";
return false;
}
}
I prefer a simplistic approach described here. This should be considered valid for security purposes. Although make sure you get it from $_SERVER['REMOTE_ADDR'], any other http header can be spoofed.
function validateIpAddress($ip){
return long2ip(ip2long($ip)))==$ip;
}
There is already something built-in to do this : http://fr.php.net/manual/en/filter.examples.validation.php See example 2
<?php
if (filter_var($ip, FILTER_VALIDATE_IP)) {
// Valid
} else {
// Invalid
}
Have you tried using built-in functions to try and validate the address? For example, you can use ip2long and long2ip to convert the human-readable dotted IP address into the number it represents, then back. If the strings are identical, the IP is valid.
There's also the filter extension, which has an IP validation option. filter is included by default in PHP 5.2 and better.
Well, why are you doing both regex and int comparisons? You are "double" checking the address. Also, your second check is not valid, as it will always return true if the first octet is valid (you have a return true inside of the foreach loop).
You could do:
$parts = explode('.', $ip_addr);
if (count($parts) == 4) {
foreach ($parts as $part) {
if ($part > 255 || $part < 0) {
//error
}
}
return true;
} else {
return false;
}
But as others have suggested, ip2long/long2ip may suit your needs better...

Detect base64 encoding in PHP?

Is there some way to detect if a string has been base64_encoded() in PHP?
We're converting some storage from plain text to base64 and part of it lives in a cookie that needs to be updated. I'd like to reset their cookie if the text has not yet been encoded, otherwise leave it alone.
Apologies for a late response to an already-answered question, but I don't think base64_decode($x,true) is a good enough solution for this problem. In fact, there may not be a very good solution that works against any given input. For example, I can put lots of bad values into $x and not get a false return value.
var_dump(base64_decode('wtf mate',true));
string(5) "���j�"
var_dump(base64_decode('This is definitely not base64 encoded',true));
string(24) "N���^~)��r��[jǺ��ܡם"
I think that in addition to the strict return value check, you'd also need to do post-decode validation. The most reliable way is if you could decode and then check against a known set of possible values.
A more general solution with less than 100% accuracy (closer with longer strings, inaccurate for short strings) is if you check your output to see if many are outside of a normal range of utf-8 (or whatever encoding you use) characters.
See this example:
<?php
$english = array();
foreach (str_split('az019AZ~~~!##$%^*()_+|}?><": Iñtërnâtiônàlizætiøn') as $char) {
echo ord($char) . "\n";
$english[] = ord($char);
}
echo "Max value english = " . max($english) . "\n";
$nonsense = array();
echo "\n\nbase64:\n";
foreach (str_split(base64_decode('Not base64 encoded',true)) as $char) {
echo ord($char) . "\n";
$nonsense[] = ord($char);
}
echo "Max nonsense = " . max($nonsense) . "\n";
?>
Results:
Max value english = 195
Max nonsense = 233
So you may do something like this:
if ( $maxDecodedValue > 200 ) {} //decoded string is Garbage - original string not base64 encoded
else {} //decoded string is useful - it was base64 encoded
You should probably use the mean() of the decoded values instead of the max(), I just used max() in this example because there is sadly no built-in mean() in PHP. What measure you use (mean,max, etc) against what threshold (eg 200) depends on your estimated usage profile.
In conclusion, the only winning move is not to play. I'd try to avoid having to discern base64 in the first place.
function is_base64_encoded($data)
{
if (preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $data)) {
return TRUE;
} else {
return FALSE;
}
};
is_base64_encoded("iash21iawhdj98UH3"); // true
is_base64_encoded("#iu3498r"); // false
is_base64_encoded("asiudfh9w=8uihf"); // false
is_base64_encoded("a398UIhnj43f/1!+sadfh3w84hduihhjw=="); // false
http://php.net/manual/en/function.base64-decode.php#81425
I had the same problem, I ended up with this solution:
if ( base64_encode(base64_decode($data)) === $data){
echo '$data is valid';
} else {
echo '$data is NOT valid';
}
Better late than never: You could maybe use mb_detect_encoding() to find out whether the encoded string appears to have been some kind of text:
function is_base64_string($s) {
// first check if we're dealing with an actual valid base64 encoded string
if (($b = base64_decode($s, TRUE)) === FALSE) {
return FALSE;
}
// now check whether the decoded data could be actual text
$e = mb_detect_encoding($b);
if (in_array($e, array('UTF-8', 'ASCII'))) { // YMMV
return TRUE;
} else {
return FALSE;
}
}
UPDATE For those who like it short
function is_base64_string_s($str, $enc=array('UTF-8', 'ASCII')) {
return !(($b = base64_decode($str, TRUE)) === FALSE) && in_array(mb_detect_encoding($b), $enc);
}
We can combine three things into one function to check if given string is a valid base 64 encoded or not.
function validBase64($string)
{
$decoded = base64_decode($string, true);
$result = false;
// Check if there is no invalid character in string
if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {$result = false;}
// Decode the string in strict mode and send the response
if (!$decoded) {$result = false;}
// Encode and compare it to original one
if (base64_encode($decoded) != $string) {$result = false;}
return $result;
}
I was about to build a base64 toggle in php, this is what I did:
function base64Toggle($str) {
if (!preg_match('~[^0-9a-zA-Z+/=]~', $str)) {
$check = str_split(base64_decode($str));
$x = 0;
foreach ($check as $char) if (ord($char) > 126) $x++;
if ($x/count($check)*100 < 30) return base64_decode($str);
}
return base64_encode($str);
}
It works perfectly for me.
Here are my complete thoughts on it: http://www.albertmartin.de/blog/code.php/19/base64-detection
And here you can try it: http://www.albertmartin.de/tools
base64_decode() will not return FALSE if the input is not valid base64 encoded data. Use imap_base64() instead, it returns FALSE if $text contains characters outside the Base64 alphabet
imap_base64() Reference
Here's my solution:
if(empty(htmlspecialchars(base64_decode($string, true)))) {
return false;
}
It will return false if the decoded $string is invalid, for example: "node", "123", " ", etc.
$is_base64 = function(string $string) : bool {
$zero_one = ['MA==', 'MQ=='];
if (in_array($string, $zero_one)) return TRUE;
if (empty(htmlspecialchars(base64_decode($string, TRUE))))
return FALSE;
return TRUE;
};
var_dump('*** These yell false ***');
var_dump($is_base64(''));
var_dump($is_base64('This is definitely not base64 encoded'));
var_dump($is_base64('node'));
var_dump($is_base64('node '));
var_dump($is_base64('123'));
var_dump($is_base64(0));
var_dump($is_base64(1));
var_dump($is_base64(123));
var_dump($is_base64(1.23));
var_dump('*** These yell true ***');
var_dump($is_base64(base64_encode('This is definitely base64 encoded')));
var_dump($is_base64(base64_encode('node')));
var_dump($is_base64(base64_encode('123')));
var_dump($is_base64(base64_encode(0)));
var_dump($is_base64(base64_encode(1)));
var_dump($is_base64(base64_encode(123)));
var_dump($is_base64(base64_encode(1.23)));
var_dump($is_base64(base64_encode(TRUE)));
var_dump('*** Should these yell true? Might be edge cases ***');
var_dump($is_base64(base64_encode('')));
var_dump($is_base64(base64_encode(FALSE)));
var_dump($is_base64(base64_encode(NULL)));
May be it's not exactly what you've asked for. But hope it'll be usefull for somebody.
In my case the solution was to encode all data with json_encode and then base64_encode.
$encoded=base64_encode(json_encode($data));
this value could be stored or used whatever you need.
Then to check if this value isn't just a text string but your data encoded you simply use
function isData($test_string){
if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string))){
return true;
}else{
return false;
}
or alternatively
function isNotData($test_string){
if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string))){
return false;
}else{
return true;
}
Thanks to all previous answers authors in this thread:)
Usually a text in base64 has no spaces.
I used this function which worked fine for me. It tests if the number of spaces in the string is less than 1 in 20.
e.g: at least 1 space for each 20 chars --- ( spaces / strlen ) < 0.05
function normalizaBase64($data){
$spaces = substr_count ( $data ," ");
if (($spaces/strlen($data))<0.05)
{
return base64_decode($data);
}
return $data;
}
Your best option is:
$base64_test = mb_substr(trim($some_base64_data), 0, 76);
return (base64_decode($base64_test, true) === FALSE ? FALSE : TRUE);

Categories