Categories
PHP Tips & Tutorials

How to link external code source folder in Eclipse PDT projects & Array initializer indentation size?

Code folders may be distributed across different locations and paths but you want to manage them in one Eclipse project. It’s easy to achieve this by linking code source in your Eclipse project.

  1. Right click on project
  2. Click “Properties”
  3. Select “PHP” > “Build Path”
  4. Click “Link Source…”
  5. Click “Browse”
  6. Select the code folder to link and click “OK”

Change array initializer indentation size

https://stackoverflow.com/q/13108241/49318

Twig syntax highlighting

http://twig.dubture.com/installation/

Categories
Anti Spam Tips & Tricks Domains Google Hacks, Cheats & Tips PHP Tips & Tutorials

Remove Gmail via Field and Add mailed-by & signed-by with PHP mail()

PHP mail() is a great function to easily send emails from your website server. If you have ever used it before in action, or are currently using mail() to send out emails from your website or application, chances are you would find Gmail to be very persistent in attaching a ‘via’ field to the from address of your messages to the recipient. If you are on a shared host or have multiple websites on a VPS, the ‘via’ field would be the domain of a whole different website from that of the sending domain, which makes you very uncomfortable.

So how to make the ‘via’ field disappear in Gmail messages sent from your PHP mail() function? How to make the ‘mailed-by‘ field and the ‘signed-by‘ field to be the email-sending domain rather than the server hostname?

How to make Gmail trust your messages sent from the mail() function?

Get rid of Gmail ‘via’ field for PHP mail() messages and make your domain show up in ‘mailed-by’ and ‘signed-by’

Here are what you need to do to make Gmail completely trusts your domain and your PHP mail() messages sent from it.

1. SPF and DKIM

Firstly, you would need to set an SPF record for the domain you are sending emails from and enable DKIM as well. These are primarily for identifying your messages against spam.

2. "From: [email protected]"

Secondly, make sure you are setting the “From: ” header to be an email address on the domain you are sending messages from. Don’t pretend to be someone else. Use “From: [email protected]” if you are sending the messages from abc.com, rather than anything else, such as [email protected], or [email protected], or whatever. If you want the recipient to reply to your Gmail email instead of your domain email, use the “Reply-To: ” header. “From: ” must always be the domain email that you are sending the email from.

3. "Return-Path: [email protected]"

Thirdly and most importantly, set the “Return-Path: ” header to be the same domain as that of the “From: ” header. Use the 5th parameter of the mail() function for this:

mail('[email protected]', 'Subject', "Message Body", $headers, '[email protected]')

So the Return-Path of this message would be “[email protected]yourdomain.com” (the email address immediately following the -f switch). The $headers parameter should contain all the necessary message headers. Make sure “From: ” is [email protected]yourdomain.com.

Now Gmail trusts all emails from yourdomain.com

After these steps and measures, Gmail should now completely trust your messages from yourdomain.com. The ‘via‘ field of your messages should be gone and the ‘mailed-by‘ field as well as the ‘signed-by‘ field should be correctly showing up as yourdomain.com.

Uploaded below is the screenshot of a message sent to my Gmail email from one of my websites (*ses.com) using the mail() function:

make Gmail trust your email

Both ‘mailed-by‘ and ‘signed-by‘ fields are correctly populated with the sending domain even though it is not the primary site nor hostname of the server that sends the email. The ‘via‘ field is also gone.

This site doesn’t have any SSL certificates installed.

Gmail is by far the best spam catcher of all email services so if they trust you, your emails sent by PHP mail() from yourdomain.com should look good in all other email inboxes. Our forum has also got a thread to cover this.

Thanks to Michael Gorven and Laura for the help.

Categories
PHP Tips & Tutorials Programming Tips & Insights

PHP: Round to the Nearest 0.5 (1.0, 1.5, 2.0, 2.5, etc.)

The common practice of rounding, namely the round() function in PHP, is to round to the nearest decimal point, that is, 1.0, 2.0, 3.0, etc. or, 10, 20, 30, etc. For example,

echo round(4.25, 0);		// 4
echo round(3.1415926, 2);	// 3.14
echo round(299792, -3);		// 300000

When I’m trying to aggregate all the customer ratings for a specific provider in one of my web hosting reviews community, I want to round the average rating to the nearest 0.5 (half the decimal) so that a half star would be correctly displayed.

This is more of a mathematical problem than a PHP one. After some thinking and testing, I came up with a slightly more sophisticated solution than but the round() function:

echo round(1.7 * 2) / 2;		// 1.5
echo round(2.74 * 2) / 2;		// 2.5
echo round(2.75 * 2) / 2;		// 3.0
echo round(3.1 * 2) / 2;		// 3.0

Just as easy as that.

Categories
Information Security Linux Server Administration Tips PHP Tips & Tutorials

500 Internet Server Error for Incorrect Permissions after Installing suPHP and Uploading PHP Script

Many’s the time after you have uploaded some PHP script to your server and point the web browser to the address it gives 500 Internet Server Error. If you have suPHP installed this is very likely because the uploaded PHP script (files and directories) have wrong permissions set to them.

With regards to Linux permissions, suPHP requires all directories to be at least 755 and all files to be at least 644 for any PHP script to run. If the directory or the PHP script has the wrong permissions set to them, suPHP would give out 500 Internet Server Error until you have corrected them. In addition, the directory and the PHP script must be owned by the current user and group or they wouldn’t run either.

To fix this is very easy, just perform the following command after you have uploaded the PHP script:

chown -R youruser /home/youruser/public_html/*
chgrp -R youruser /home/youruser/public_html/*
find /home/youruser/public_html/* -type f -exec chmod 644 {} \;
find /home/youruser/public_html/* -type d -exec chmod 755 {} \;

The 1st line sets everything (files and directories) under /home/youruser/public_html/ to be owned by user youruser.

The 2nd line sets everything (files and directories) under /home/youruser/public_html/ to be owned by group youruser.

The 3rd line sets all files under /home/youruser/public_html/ to be 644 in permissions.

The 4th line sets all directories under /home/youruser/public_html/ to be 755 in permissions.

Categories
Free PHP Classes & Library PHP Tips & Tutorials

Convert Object to Array in PHP

There are quite a few ways to do this and each of them has its strengths and weaknesses. Find out if one suits your needs by trying one of the approaches below.

Casting with (array)

$array = (array) $obj;

Problem is this doesn’t convert complex / multi-dimensional objects well.

get_object_vars()

$array = get_object_vars( $obj );

$array would then be an array of properties and values from $obj that are accessible in the current scope.

Custom function for complex objects

function objectToArray( $object )
    {
        if( !is_object( $object ) && !is_array( $object ) )
        {
            return $object;
        }
        if( is_object( $object ) )
        {
            $object = get_object_vars( $object );
        }
        return array_map( 'objectToArray', $object );
    }

$array = objectToArray( $obj );

This function is conjured by PHPRO.ORG.

JSON – json_encode(), json_decode()

$json  = json_encode($object);
$array = json_decode($json, true);

This is probably the coolest approach delivered by Andy.

Categories
PHP Tips & Tutorials Regular Expression Tips & Tutorials WordPress How To

PHP preg_match() First Letter of a WordPress Post for Drop Cap Styling

Drop Cap ExampleWhile CSS3 can target the first letter of text inside an element, it’s still not universally supported across major browsers AND it doesn’t work well for elements that have child elements inside. The bullet proof way to target the first letter of a WordPress post would be to capture the content of the post in WordPress theme and match it by regular expression functions in PHP, such as preg_match().

And here’s the code I’ve come up for this job:

ob_start();
the_content();
$content = ob_get_clean();
$content = preg_replace('@<p>\s*((?:<[^<>]+>\s*)*)([^<>\s])@'
, '<p>$1<span class="drop_cap">$2</span>'
, $content
, 1);

echo $content;

Obviously, this code should reside in single.php of your WordPress theme where the content of the posts is being output. Just replace any “the_content()” function in the post area with this snippet.

The key is the regular expressions:

@<p>\s*((?:<[^<>]+>\s*)*)([^<>\s])@

And:

<p>$1<span class="drop_cap">$2</span>

That finds the 1st non-whitespace, printable character (a letter, a numeral, etc.) of a post and adds a surrounding <span> tag with class “drop_cap” to it.

Now you will add some drop cap styles to style.css as class .drop_cap, and the first letter of your posts will have a nice drop cap style. See this blog Mosso Reviews for example.

Categories
PHP Tips & Tutorials

PHP Getting the last xx bytes of a large text file

Sometimes the text files are very large and you don’t want to load it in memory before searching through it because it’s inefficient. You just want to get the last few bytes of the file because the latest additions / updates are there.

This would help you:

$fp = fopen('somefile.txt', 'r');
fseek($fp, -50, SEEK_END); // It needs to be negative
$data = fgets($fp, 51);

Which gets the last 50 bytes of the file somefile.txt in $data. Thanks to niels for the solution.

Make sure the 2nd parameter for fgets() is 1 more than the absolute value of the 2nd parameter for fseek().

Categories
.htaccess Tutorials & Tips Free PHP Classes & Library Information Security PHP Tips & Tutorials

PHP Class for Handling .htpasswd and .htgroup (Member Login & User Management)

Apache is a marvelous web server that offers .htpasswd and .htgroup for controlling restricted access to your website. By help of .htaccess, they work as a member login & user management system that is so simple and easy to deploy. You can even define user groups / roles with it.

Basically,

  • .htpasswd defines pairs of username & password that are user accounts.
  • .htgroup defines groups / roles of user accounts that can be access-controlled as a whole.
  • .htaccess then applies .htpasswd and .htgroup to the current directory, and specifies which groups in .htgroup has access to the current directory.

For example, we have

/home/myuser/.htpasswd

user1:{SHA}kGPaD671VNU0OU5lqLiN/h6Q6ac=
user2:{SHA}npMqPEX3kPQTo+x/+ZckHDrIcQI=
user3:{SHA}q1Fh2LTUjjkncp11m0M9WUH5Zrw=

/home/myuser/.htgroup

admin: user2
editor: user1 user3
writer: user3

/home/myuser/public_html/example.com/member/.htaccess

AuthName "Members Area"
AuthType Basic
AuthUserFile /home/myuser/.htpasswd
AuthGroupFile /home/myuser/.htgroup
<Limit GET POST>
require group admin
require group writer
</Limit>

What they do is only let users in the admin and writer group, that is user2 and user3, to access example.com/member. When someone tries to access example.com/member, Apache would prompt him or her for user name and password, and he or she must be either user2 or user3 to access it – they must enter the correct password set out in .htpasswd for user2 or user3.

user1 isn’t allowed to access example.com/member even if the password is correct. You get the idea.

You can place .htaccess anywhere in your website, and it will control access to the directory it’s in by the defined rules (which groups / roles are allowed to access). Just make sure it is pointing to the right .htpasswd and .htgroup by AuthUserFile and AuthGroupFile.

And you can have multiple .htaccess in different directories of your website, using the same .htpasswd and .htgroup.

This is so simple yet so very handy in creating & managing different users and user roles (.htpasswd, .htgroup) and giving them permissions (.htaccess) in accessing different website assets.

PHP Class

Now that you are familiar with the basic authentication and native user management system in Apache, you can use this two simple PHP classes to automate tasks such as user creation, user deletion, adding user to group, and removing user from group.

class Htpasswd

class Htpasswd {
	
	private $file = '';
	private $salt = 'AynlJ2H.74VEfI^BZElc-Vb6G0ezE9a55-Wj';
	
	private function write($pairs = array()) {
		$str = '';
		foreach ($pairs as $username => $password) {
			$str .= "$username:{SHA}$password\n";
		}
		file_put_contents($this -> file, $str);
	}
	
	private function read() {
		$pairs = array();
		$fh = fopen($this -> file, 'r');
		while (!feof($fh)) {
			$pair_str = str_replace("\n", '', fgets($fh));
			$pair_array = explode(':{SHA}', $pair_str);
			if (count($pair_array) == 2) {
				$pairs[$pair_array[0]] = $pair_array[1];
			}
		}
		return $pairs;
	}
	
	private function getHash($clear_password = '') {
		if (!empty($clear_password)) {
			return base64_encode(sha1($clear_password, true));
		} else {
			return false;
		}
	}
	
	public function __construct($file) {
		if (file_exists($file)) {
			$this -> file = $file;
		} else {
			die($file." doesn't exist.");
			return false;
		}
	}

	public function getUsers() {
		return $this -> read();
	}
	
	public function addUser($username = '', $clear_password = '') {
		if (!empty($username) && !empty($clear_password)) {
			$all = $this -> read();
			if (!array_key_exists($username, $all)) {
				$all[$username] = $this -> getHash($clear_password);
				$this -> write($all);
			}
		} else {
			return false;
		}
	}
	
	public function deleteUser($username = '') {
		$all = $this -> read();
		if (array_key_exists($username, $all)) {
			unset($all[$username]);
			$this -> write($all);
		} else {
			return false;
		}
	}
	
	public function doesUserExist($username = '') {
		$all = $this -> read();
		if (array_key_exists($username, $all)) {
			return true;
		} else {
			return false;
		}
	}
	
	public function getClearPassword($username) {
		return strtolower(substr(sha1($username.$this -> salt), 4, 12));
	}
	
}

class Htgroup

class Htgroup {
	
	private $file = '';
	
	private function write($groups = array()) {
		$str = '';
		foreach ($groups as $group => $users) {
			$users_str = '';
			foreach ($users as $user) {
				if (!empty($users_str)) {
					$users_str .= ' ';
				}
				$users_str .= $user;
			}
			$str .= "$group: $users_str\n";
		}
		file_put_contents($this -> file, $str);
	}
	
	private function read() {
		$groups = array();
		$groups_str = file($this -> file, FILE_IGNORE_NEW_LINES);
		foreach ($groups_str as $group_str) {
			if (!empty($group_str)) {
				$group_str_array = explode(': ', $group_str);
				if (count($group_str_array) == 2) {
					$users_array = explode(' ', $group_str_array[1]);
					$groups[$group_str_array[0]] = $users_array;
				}
			}
		}
		return $groups;
	}
	
	public function __construct($file) {
		if (file_exists($file)) {
			$this -> file = $file;
		} else {
			die($file." doesn't exist.");
			return false;
		}
	}

	public function getGroups() {
		return $this -> read();
	}
	
	public function addUserToGroup($username = '', $group = '') {
		if (!empty($username) && !empty($group)) {
			$all = $this -> read();
			if (isset($all[$group])) {
				if (!in_array($username, $all[$group])) {
					$all[$group][] = $username;
				}
			} else {
				$all[$group][] = $username;
			}
			$this -> write($all);
		} else {
			return false;
		}
	}
	
	public function deleteUserFromGroup($username = '', $group = '') {
		$all = $this -> read();
		if (array_key_exists($group, $all)) {
			$user_index = array_search($username, $all[$group]);
			if ($user_index !== false) {
				unset($all[$group][$user_index]);
				if (count($all[$group]) == 0) {
					unset($all[$group]);
				}
				$this -> write($all);
			}
		} else {
			return false;
		}
	}

	public function getGroupsByUser($username = '') {
		$all = $this -> read();
		$user_groups = array();
		foreach ($all as $group => $users) {
			if (in_array($username, $users)) {
				$user_groups[] = $group;
			}
		}
		return $user_groups;
	}

}

Usage

First, you should use your own $salt. Change the value of $salt in the Htpasswd class to something else for your own application.

To instantiate the classes:

$passwdHandler = new Htpasswd('/home/myuser/.htpasswd');
$groupHandler = new Htgroup('/home/myuser/.htgroup');

To create and delete a user:

// Add a user with name 'user1' and password 'I prefer to use passphrase rather than password.' if it doesn't exist in .htpasswd.
$passwdHandler -> addUser('user1', 'I prefer to use passphrase rather than password.');
// Delete the user 'user1' if it exists in .htpasswd.
$passwdHandler -> deleteUser('user1');

To check if a particular user exists in .htpasswd:

// Check if user 'user1' exists in .htpasswd.
if ($passwdHandler -> doesUserExist('user1')) {
	// User 'user1' exists.
}

To get the clear text password for a particular user (Apache stores passwords in .htpasswd as encoded strings):

// Get the clear password for user 'user1'.
echo $passwdHandler -> getClearPassword('user1');

To add a user to a group:

// Add user 'user1' to group 'admin' in .htgroup. Group will be automatically created if it doesn't exist.
$groupHandler -> addUserToGroup('user1', 'admin');

To delete a user from a group (user still exists in .htpasswd, just not associated with the group any more):

// Delete user 'user1' from group 'admin' in .htgroup. Group will be automatically removed if it doesn't contain any users.
$groupHandler -> deleteUserFromGroup('user1', 'admin');

To get a list of groups a particular user is assigned to:

/* Get an array of groups that 'user1' is a member of. */
$user_groups = $groupHandler -> getGroupsByUser('user1');

Conclusion

This ain’t concluded. It’s just an END notice. Feel free to let me know your thoughts and how my classes work for you.

Categories
PHP Tips & Tutorials

PHP: Strip or Trim Extra Whitespaces Inside a String

There are raw strings that contain extraly unwanted whitespaces (tabs, spaces, new lines) that you want to get rid of so as to form a normalized string that has only a single spaces between words and sentences. For instance, you may want to transform this string:

Morning   is here,   sunshine
   is here.    Morning is    here.

Into this:

Morning is here, sunshine is here. Morning is here.

How to achieve this in PHP?

Just use this function:

function purge_inside_whitespaces($text) {
	while (preg_match('/\s{2}/', $text)) {
		$text = preg_replace('/\s{2}/', ' ', $text);
	}
	return $text;
}

Basically, it keeps scouring through the $text string passed to it and removes any continuous whitespaces and replace them with single spaces, until it can’t find any more continuous whitespaces.

Note you would need to apply trim() to get rid of any whitespaces in the beginning or at the end of the string, because if there are any there, a single space would still remain after applying purge_inside_whitespaces().

Categories
PHP Tips & Tutorials

PHP: Check if A String Contain Only Uppercase / Capital Letters

Sometimes you would want to check if a string is an acronym or an abbreviation by testing if it only contains capitalized letters from A to Z and nothing else. There are 2 ways to accomplish this simple task in PHP.

ctype_upper()

Use the native ctype_upper() function and you will know if the provided string contains only uppercase letters:

if (ctype_upper($string)) {
	echo $string.' is all uppercase letters.';
} else {
	echo $string.' is not all uppercase letters.';
}

The Ctype functions would turn out to be very handy when you want to test a string against different character types – digits, alphabetic, alpha-numeric, lowercase letters, uppercase letter, and even punctuations, etc. See the full list here: http://www.php.net/manual/en/ref.ctype.php

strtoupper()

Use the strtoupper() function to transform the string into all uppercase characters that’s capitalized letters, and then compare the transformed string against the original one to see if they are identical. If they are, then you are pretty sure the original string was also a string consisting of ONLY capital letters.

if (strtoupper($string) == $string) {
	echo $string.' is all uppercase letters.';
}

Check if A String Consists of Only Lowercase Letters

The same goes true if you want to do the test other way around. Just use ctype_lower() and strtolower() instead.