Wednesday, August 20, 2008

PHP Source Code for Manually Registering Global Variables

Methodology and Implementation


If you read up on the originial USENET thread, you know that there were a few suggestions made about going about this as well as posts pointing out why those solutions didn't quite fit. In order to get around some of the fallbacks and keep the original idea in tact, functions needed to be created.

By making use of PHP's superglobal arrays ($GLOBALS, $_SESSION, $_GET, $_POST, $_COOKIE, $_REQUEST, $_SERVER, $_FILES, $_ENV) and referencing variables, the solution became rather simple to accommodate the OP's idea.

You can read the thread to find out what brough on this interest if you are curious. What it comes down to is that the OP didn't want to trust register_globals, gpc_order and variables_order server settings to get it right. Therefore, the OP wanted a way to manually register the variables needed by pulling them from the appropriate place. This was to help the OP in creating more secure and stable PHP applications.

How this works is really quite simple. Say you have a variable named "var1" in a session. This variable would normally be accessed by $_SESSION['var1'] if register_globals is not turned on. That syntax creates a few extra keystrokes as well as more extra strokes when using heredoc syntax or quoted string output. However, if you were to be able to simply access that variable through $var1, that saves a lot of keystrokes when you start to use the variable over and over (as is likely the case with sessions and user input variables). For this to work correctly, however, if you were to set a value to the variable either through $var1 or $_SESSION['var1'], the compliment also needed to be changed. This is where variable references come in. (References are similar to pointers in the C programming language.)

The implementation is bery easy to use. In order to "register" or global $var1 variable, we'd simply call the correct function from below.

global_session('var1');

In doing so, we now are able to access the same value in memory by the following 3 methods:

  • $var1
  • $_SESSION['var1']
  • $GLOBALS['var1']

By setting a new value to any one of the above 3 variables will change the value for all of them.

Difference From register_globals = On

One difference I have spotted in the way these functions act from having register_globals enabled is in the case of session variables. If you had altered $var1 in a script (with PHP's register_globals = "On"), you'd have to manually add the new value back into the session. In most cases, these functions would make a more convenient method; however, there may be instances where you do not want to have the $_SESSION variable automatically updated.

Additional tests with other superglobal arrays reveal that the same behavior exists as above for all the superglobal arrays except $GLOBALS. Therefore, if you truly want to set global variable values globally, you would need to use the methods described on this page.

function global_get($var){
if(!
array_key_exists($var,$_GET))
$_GET[$var]='';
$GLOBALS[$var]=&$_GET[$var];
}

function
global_post($var){
if(!
array_key_exists($var,$_POST))
$_POST[$var]='';
$GLOBALS[$var]=&$_POST[$var];
}

function
global_session($var){
if(!
array_key_exists($var,$_SESSION))
$_SESSION[$var]='';
$GLOBALS[$var]=&$_SESSION[$var];
}

function
global_cookie($var){
if(!
array_key_exists($var,$_COOKIE))
$_COOKIE[$var]='';
$GLOBALS[$var]=&$_COOKIE[$var];
}

function
global_server($var){
if(!
array_key_exists($var,$_SERVER))
$_SERVER[$var]='';
$GLOBALS[$var]=&$_SERVER[$var];
}

function
global_files($var){
if(!
array_key_exists($var,$_FILES))
$_FILES[$var]='';
$GLOBALS[$var]=&$_FILES[$var];
}

function
global_env($var){
if(!
array_key_exists($var,$_ENV))
$_ENV[$var]='';
$GLOBALS[$var]=&$_ENV[$var];
}

function
global_request($var){
if(!
array_key_exists($var,$_REQUEST))
$_REQUEST[$var]='';
$GLOBALS[$var]=&$_REQUEST[$var];
}
?>

Creating a chat script with PHP and Ajax

Introduction

In this multi-part tutorial series I will show you how to create your own chat script with PHP and Ajax. You've probably heard of Ajax before, and what it exactly is, but in case you haven't, read the following two tutorials to learn more about Ajax: "Mastering Ajax, Part 1: Introduction to Ajax" and "Getting started with Ajax".


Another JavaScript library we'll be using is the Prototype library, which includes many useful JavaScript functions and comes with inbuilt Ajax support. If you want to know more about this library, have a look at the following tutorial: "Using prototype.js v1.3.1".


In this first part of the series I will show you how to create a really basic chat script, and nothing more. In the next parts we'll be adding more features, eventually creating a really robust and powerful chat script.


How it works


Our chat script will consist of two parts: a server and a client.


The client is used by your visitors, and doesn't contain any PHP at all. The client must do all the data sending. Every time the user wants to send a new message, the client must send this data (using Ajax) to the server. The client must also check for new messages on the server, again using an Ajax request.


The server only has to add a new message or send a list of messages to the client, and it doesn't have to use any HTML or JavaScript at all. It's strictly PHP. I've added a simple diagram below to show what I've just







Creating the server


Let's start by creating the server, but first, create a new datebase to hold the messages of your chat script, with the following database scheme:



CREATE TABLE `message` (

`messageid` int(5) NOT NULL AUTO_INCREMENT,

`user` varchar(255) NOT NULL DEFAULT '',

`message` text NOT NULL,

`datetimestamp` int(11) NOT NULL DEFAULT '0',

PRIMARY KEY (`messageid`)

) TYPE=MyISAM AUTO_INCREMENT=1 ;



The first thing the server must do is check what the client wants: adding a new message or requesting latest messages? The following code does what we want:



if (!isset($_GET['action'])) {

die('This chat server can only be used by the chat client.');

}

$action = $_GET['action'];

if ($action != 'get' AND $action != 'add') { $action = 'get'; }


// Do we want to get chat messages or add a new message?

if ($action == 'get') {

// Get messages

send_messages();

} else {

// Add a new message

add_message();

}



As you can see we're going to use two different functions: send_messages() to return all the latest messages and add_message() to add a new message.


Adding a new message is quite simple, and it only requires some standard database code, like this:


function add_message() {

global $db;

// Everything there?

if (!isset($_GET['user'])) {

die('error:no-user');

}



if (!isset($_GET['message'])) {

die('error:no-message');

}


$user = ss(htmlentities(strip_tags($_GET['user'])));

$message = ss(htmlentities(strip_tags($_GET['message'])));

$datetimestamp = time();


// Insert message

$db->query ("INSERT INTO message (user, message, datetimestamp) VALUES ('$user', '$message', $datetimestamp)");


// Return any new message

send_messages();

}



The function first checks if both variables are there, and if they're not, it returns an error. The errors look a bit weird, but this format actually makes it easier for our client (you'll see why later). When everything is okay, the message is inserted into the database.


The send_messages() function has to send the messages that have NOT yet been received by the client. To do this, the client sends the timestamp of the last received message, from which the server can automatically select the messages that haven't been received yet, like so:


function send_messages() {

global $db;

// Is there a latest timestamp?

if (!isset($_GET['latest'])) {

$latest = false;

} else {

$latest = intval($_GET['latest']);

}


// If there isn't a latest, get the five newest messages, and return them

if ($latest == false) {

$messages = $db->sql_query ("SELECT user, message, datetimestamp FROM message ORDER BY datetimestamp DESC LIMIT 0,4");

} else {

$messages = $db->sql_query ("SELECT user, message, datetimestamp FROM message WHERE datetimestamp > $latest ORDER BY datetimestamp DESC LIMIT 0,9");

}


// Any messages?

if ($messages == false) {

die('no-messages');

}


// Get newest timestamp

$newest = $messages['0']['datetimestamp'];


// Reverse array for correct order

$messages = array_reverse($messages);


// Return response

$response = $newest;


foreach ($messages as $message) {

$response .= $message['user'] . '>' . $message['message'] . "\n";

}


$response = trim($response);


die($response);

}



This code first selects the right messages, and after that returns it in the right format (each message is separated by a newline, and the user and message are separated by >).


Creating the client




You can close your PHP editor now, and switch to your HTML/JS editor, as we'll only be using HTML and JavaScript from now on.


First of all, the client page itself. It's nothing advanced, and very simple:


<html>

<head>

<title>Ajax Chat Client</title>

<script type="text/javascript" src="../prototype.js"></script>

<script type="text/javascript" src="script.js"></script>


<link REL="stylesheet" HREF="../style.css" TYPE="text/css" media="all">


</head>


<body><div id="container">

<h1>Ajax Chat Client</h1>


<div id="login">

<p>Please enter an username: </p>

<input type="text" name="user" id="user" />

<input type="button" onclick="login();" value="Enter Chatroom" />

</div>


<div id="chatelements" style="display:none;">

<textarea id="chat" rows="20"></textarea>

<input type="text" id="message"><input type="button" onclick="send_message();" value="Send" />

</div>



<div id="debug">

</div>


<div id="copyright">

This is a demo of an article series on <a href="http://www.phpit.net">PHPit</a>.

Copyright &copy; 2006 Dennis Pallett.

</div>

</div></body>

</html>



It has three important elements: the login div, which shows a login box when first viewing the page, a textarea, which is used to show all the chat messages, and a text field which is used to enter new messages.


If you have a close look at the HTML above, you'll notice two different JS functions: login() and send_message(). These are defined in the script.js file, and are the most important of our chat script.


The login() function is used to set a user's username, and getting the initial messages. It looks like this:


var server = 'http://projects/phpit/content/creating%20an%20ajax-based%20chat/demos/1/chatserver.php';

var username = '';

var latest = '';

function login() {

// Get username

var user = $F('user');


if (user == '') {

alert('Please enter a username before entering the chat room');

return false;

}


username = user;


// Show chat

Element.hide('login');

Element.show('chatelements');


$('chat').value = '';

$('message').value = '';


// Begin getting messages

get_messages();

checker = new PeriodicalExecuter(get_messages, 2);

}



The first part of the function checks the username. If everything is okay, the chat elements are shown, and the latest messages are retrieved using the get_messages() function. The function also creates a new object, called the PeriodicalExecuter, which is used to check for new messages every 2 seconds.


The get_messages() function is used to retrieve new functions using an Ajax request, like so:


function get_messages() {

var args = 'action=get&latest=' + latest;

var do_ajax = new Ajax.Request(server, {method: 'get', parameters: args, onComplete: handle_response});

}

The above code uses the Ajax object (included with the Prototype library) to send a new GET request to the server with two arguments: action and the timestamp of the latest message received. As you can see, the onComplete parameter has been set to handle_response, which means that when the Ajax request is done, the response will be sent to a function called handle_response().


The handle_response() function actually checks the response, and decides what to do. Remember the responses that we gave in the server? We're going to use that now, like so:


function handle_response(request) {

var response = request.responseText;

// Error?

if (response == 'error:no-user') {

// No username, show login again

alert('It appears you aren\'t logged in any longer. Please login again');

Element.show('login');

Element.hide('chatelements');

return false;

}

if (response == 'error:no-message') {

// No username, show login again

alert('You didn\'t send any message. Please try again');

return false;

}

if (response == 'no-messages'){

// There are no new messages

return false;

}


// We're getting a valid response, first get the latest timestamp

latest = response.substring(0, 10);


// Now get the messages

messages = response.substring(10, response.length);


// Split messages

messages = messages.split('\n');


// Add each message

var chat = $('chat');

for (var i=0; i < messages.length; i++) {

var message = messages[i].split(">");



chat.value = chat.value + '\n';

chat.value = chat.value + message[0] + ': ' + message[1];

}

}



This function first checks whether any errors have been returned. This only happens when a message has been sent (and not when receiving messages). After that it checks whether there are any messages.


If there are new messages, it parses the new messages (using some standard string functions), and then adds the new messages to the chat area.


And that's all there is to it. We've now got an almost working chat script. All that's left is to write the send_message() function.





PHP & Security: 3 Example Exploits

Introduction

One of the most common aspects of programming and scripting is security. Every program or script has to think about security, and each language has certain weak points. Actually, it isn't the language that has weak points - it's the programmer who creates weak points. PHP is no exception to this, and security should be at the top when you're creating a new script, no matter how simple or small the script may be.

I'm sure you've all read many basic PHP security articles, which include things like filtering user input, beware of XSS attacks, etc. That's why I'm not going to discuss them in this article. If you haven't heard about these things, have a look on Google. Heck, maybe I'll do a basic PHP security article in the near future.

In this article we're going to look a three different security cases. In each case I will try to explain the exploit, provide a working example, and then suggest possible fixes to prevent you from making the same mistake. Let's get cracking, shall we?

Security Case #1 - E-mail Injection

This is one of the neatest PHP exploits I've ever seen, and really requires some knowledge of how e-mail works. This exploit is often used by spammers to use contact forms on your websites to send out massive amounts of spam, without you even knowing. I used to be a victim of this as well, because I didn't even have a clue this existed. There was one thing I noticed though: really weird messages coming through my contact forms, for example:

Example

aciov@yourdomain.com
Content-Type: multipart/mixed; boundary=\"===============2145621685==\"
MIME-Version: 1.0
Subject: 9afb7555
To: aciov@yourdomain.com
bcc: mhkoch321@aol.com
From: aciov@yourdomain.com

This is a multi-part message in MIME format.

--===============2145621685==
Content-Type: text/plain; charset=\"us-ascii\"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

wpbtizuum
--===============2145621685==--


As you can see this doesn't make much sense at all. But what it does mean is that spammers are trying to see if your contact form is open to e-mail injection.

This exploit works quite like SQL injection - untrusted users are able to inject data, because of poor input validation. When you use the mail() function you might think each argument is a separate thing, and they can't influence each other. But that's not the case, and the e-mail is actually one big long text message. For example, mail('me@example.com', 'My Subject', 'My Message', "From: contact@example.com\r\n";) is actually changed into:

To: me@example.com
Subject: My Subject
From: contact@example.com

My Message

The exploit happens when spammers are able to insert data into the e-mail, therefore being able to change the complete e-mail. For example, if your mail() function looks like this:


$email = $_POST['email'];
mail ('me@example.com', 'My Subject', 'My Message', "From: $email\\r\\n");
?>

As you can see an attacker can inject raw data into the e-mail. This means it's now possible to send a complete different e-mail with a new subject, message, and to header. Your contact form is used as an open relay!

How do you protect against this exploit?
Easy - validate ALL input, and insert as little as possible into the e-mail. If you make sure you only get valid data from the user, the chance of e-mail injection has already been reduced hugely, and it probably won't be possibly any longer. Also see the above link for different solutions.

This is one of the sneakiest exploits around, but it is also very simple (and easy to forget about it as a developer!). The View Source exploit was the one that caused APNIPHP to be "hacked" recently.


It only works when you use a script to highlight or show the source of other PHP files, using the highlight_file() function or the fopen() function. These functions allow your visitors to view the source of other files, which is the whole point of this script. But you must also implement some security measures to prevent users from viewing files that they shouldn't see (such as database files, password files, etc). The best way of doing this is using a white-list array of filenames, and only allowing these files to be opened. This method is bullet-proof and will never fail.

But perhaps you want to restrict the script to only allow files from a certain directory, e.g. the 'demos' directory. To enforce this restriction, you'd probably use code like this:

if (strpos($file, 'demos') === false) {
echo 'Security alert. Not a demo!';
} else {
highlight_file ($file);
}

This checks whether the filename contains 'demos', and if so, displays the source. Seems fairly fail-proof, but that's where the exploit strikes. An attacker could include '..' in the filename, which means "go a directory up". So C:\program files\demos\..\ means the same as C:\program files\. This basically means that an attacker has unlimited access to everything on the server. Big whoops!

How do you protect against this exploit?
The easiest way is to check if the filename contains the two dots and display an error. So the above code becomes:

if (strpos($file, 'demos') === false OR strpos($file, '..') !== false) {
echo 'Security alert. Not a demo!';
} else {
highlight_file ($file);
}

UPDATE:
The above way isn't completely secury, and any file that contains 'demos' in the filename can still be viewed. If you really want to secure your view source script, don't allow a full path, and instead only allow a name. For example, instead of using '/home/phpit/public_html/demo/demo.php' simply use 'demo.php', and in your script add the full path. The only thing you have to worry about then is to filter out the two dots, and that's easy.

$file = '/home/phpit/public_html/demo/' . $_GET['filename'];

if (strpos($file, '..') !== false) {
echo 'Security alert. Not a demo!';
} else {
highlight_file ($file);
}

This would probably be enough to protect your view source script, and stop this exploit from working. You can also use dedicated source-viewing scripts, like phpViewSource.

How do you protect against this exploit?
Protecting your scripts against CSRF attacks is extremely hard to do, and a really dedicated attacker will likely succeed anyway. But there are still steps you can take to make it harder.

First of all, make sure that any forms that change data (add/edit/delete) are POST only. GET requests should not be able to change anything.

Secondly, include a secret token with your forms, which also expire after a certain period of time. This will prevent almost any kind of CSRF attack, and is extremely different to counter.

Finally, don't worry too much about CSRF attacks. Although they are out there, it's likely you won't ever have to deal with it, and even so, it's an easy fix. If you're interested have a look on http://www.squarefree.com/securitytips/web-developers.html#CSRF for more information about CSRF attacks.


PHP Global Variables

Introduction

Whenever you're developing a new large-scale PHP script, you're bound to use global variables, since some data needs to be used by multiple parts of your script. Good examples of global data are script settings, database connections, user credentials and more. There are many ways of making this data global, but the most commonly used way is to use the global keyword, which we will explore later on in this article.

The only problem with the global keyword, and any global data for that matter, is that's it's actually a very bad way of programming, and usually tends to lead to bigger problems later on. The reason for this is that global data ties all the separate parts of your script together, and often if you make a change in one part, something else will break in another part. If you have more than a few global variables, you're whole script will eventually become a big kludge of unmaintainable code.

That's why this article will show you how to prevent this by using various techniques and design patterns. But first, let's have a look at the global keyword and how it works.

Using globals and the global keyword

By default PHP defines a few variables called Superglobals which are automatically global, and can be accessed anywhere, like the $_GET or $_REQUEST variables. These are mainly used to retrieve form data or other outside data, and there's no real harm in using these variables, since they should never be written to anyway. But you can also use your own global variables, with the global keyword which is used to import variables from the global scope into the local scope of a function.

The following example demonstrates use of the global keyword:

$my_var = 'Hello World';

test_global();

function test_global() {
// Now in local scope
// the $my_var variable doesn't exist

// Produces error: "Undefined variable: my_var"
echo $my_var;

// Now let's important the variable
global $my_var;

// Works:
echo $my_var;
}

?>


As you can see in the above example, the global keyword is used to important variables from the global scope. Seems to work fine, and it's nice and simple, so why should you worry about using the global keyword?

There are three good reasons:

1. Reusing parts of the script is impossible
If a certain function relies on global variables, it becomes almost impossible to use that function in a different context. Another problem is that you can't take that function, and use it in another script.

2. Solving bugs is much harder
Tracking a global variable is much harder than a non-global variable. A global variable could be declared in some obscure include file, which could take hours to find, although a good text editor / IDE could help with this.

3. Understanding the code in a year will be much more difficult
Globals make it difficult to see where a variable is coming from and what it does. You might know about every global during development, but after a year or so you'll probably have forgotten at least half of them, and then you'll be kicking yourself for using so many globals.

Google tips and tricks- Google don'ts

Google tips:

Bellow are some techniques which may reduce your Google ranking or even ban you from its index. You should avoid them if possible.

Bad navigation

Your website must have clean and simple navigation. This way you ensure that Googlebot will be able to crawl your entire site. Navigation links should be located near the top of the pages since this makes it easy for your visitors and Googlebot to navigate through your site.
Best bet for navigation is use of text links, as this increases word count and keyword density, as well as giving description of destination page to Googlebot. Googlebot is also able to follow image links and from recently Flash navigation links. If you use image links make sure you add some description in “alt” attribute of image tag to describe your link.

JavaScript links

Googlebot is not able (currently) to follow JavaScript links. People often use these type of links for fancy navigation. If you use them just make sure you have alternative navigation using HTML links.

Hidden text

Googlebot and other robots learned to recognize this method several years ago. So if you don’t want to be identified as spammer and banned from SERP’s, don’t use this method.

Hidden links

Number of incoming links to certain page has direct effect to Google PageRank (PR). However, if those are hidden that may produce similar results as with hidden text.

Cloaking

Cloaking is a search engine optimization method where you serve highly optimized page version to robots and a regular page to your visitors. Official Google policy is that cloaked pages will not be allowed in their index. However, there are many websites that use cloaking with great success. So if you like to risk getting banned from SERP’s you may use this method, just make sure you do it properlyJ

Guest book spamming and FFA pages

Adding your link to hundreds of guest books will not help you with your PR, since it appears that Google is able to detect them and ignores outgoing links completely. This way you’ll save yourself many hours of useless work.
When PR was initially introduced, many SEO companies were offering to “submit your site to zillion FFA pages for free” and hopefully increase your PR. I don’t remember that this used to work at time and it certainly doesn’t work now. If you find any of these, avoid them.

Sessions

Google is not able to accept session cookies and will try avoiding URL based sessions. Also, you should use fewer parameters in you dynamic URLs and avoid use “id” parameter as Googlebot may think that is session ID.