50 PHP Programming Tips

Great tips - a must read.
http://www.hm2k.com/posts/50-php-optimisation-tips-revisited.

50 Useful PHP Tools

Set Focus on First Input Field

$(':input:first').focus();
or
$('input[tabindex="0"]').focus();

Make sure to add tabindex="0" to the first input field.< p/>

Find Current Directory

echo getcwd();
echo dirname($_SERVER['SCRIPT_FILENAME']);
echo realpath(".");

Return An Array as a List

$array = array();
//create an array
$str = implode(", ",$array);
echo "text $str";

Rename and Move a File

if (file_exists("/home/john/newsletters")) {
rename("/home/john/newsletters","/home/john/mail/lists") or die ("could not move file");
} 

Parse URL

$myDomain = parse_url("http://www.microsoft.com/?search-something#bottom");
echo "Domain ".$myDomain['host'];
echo "Query string ".$myDomain['query'];
echo "Anchor ".$myDomain['fragment'];

Converting Smart Quotes

source: Chris Shiflett
function convert_smart_quotes($string) 
{ 
    $search = array(chr(145), 
                    chr(146), 
                    chr(147), 
                    chr(148), 
                    chr(151)); 
 
    $replace = array("'", 
                     "'", 
                     '"', 
                     '"', 
                     '-'); 
 
    return str_replace($search, $replace, $string); 
} 

Check for File Extension

$ext = pathinfo($file, PATHINFO_EXTENSION);

Control Prefixes for Variables

  • cbo ComboBox
  • chk CheckBox
  • dag DataGrid
  • dat DataSet
  • fra Frame
  • frm Form
  • grd Grid
  • hsb Horizontal scroll bar
  • lbl Label
  • lst ListBox
  • mnu Menu
  • nud NumericUpDown
  • pgb ProgressBar
  • pic PictureBox
  • pnl Panel
  • rdb RadioButton
  • rtb RichTextBox
  • spn Spin control
  • tmr Time
  • txt TextBox
  • vsb Vertical scroll bar

If you can't upload a php file to make phpinfo(), or if PHP information is hidde

 If you can't upload a php file to make phpinfo(), or if PHP information is hidden from headers by ServerTokens directive, there's still one way to get PHP version. Add ?=PHPE9568F36-D428-11d2-A769-00AA001ACF42 to any .php url. For example index.php?=PHPE9568F36-D428-11d2-A769-00AA001ACF42. It still could be hidden, but sometimes administrators forget to hide it

If you see a guy with breadsticks - it's PHP 4.0.0 - 4.2.3
If you see a brown dog - it's PHP 4.3.0 - 4.3.10
If you see a black dog - it's PHP 4.3.11 - 4.4.6; or 5.0.4 - 5.1.2
If you see a rabbot - it's PHP 5.0.0 - 5.0.3
If you see a PHP logo - it's PHP 5.1.3 - 5.2.13
If you see a PHP elephant - it's 5.3.0 or newer 

Clean Text

function cleanup_text ($value='', $preserve='', $allowed_tags='') {
if (empty($preserve)) {
     $value = strip_tags($value, $allowed_tags);
}
$value = htmlspecialchars($value);
return $value;
}

Create a Random Password

function createRandomPassword() {
    $chars = "abcdefghijkmnopqrstuvwxyz23456789";
    srand((double)microtime()*1000000);
    $i = 0;
    $pass = '' ;
    while ($i         $num = rand() % 33;
        $tmp = substr($chars, $num, 1);
        $pass = $pass . $tmp;
        $i++;
    }
    return $pass;
}

Debugging with IP Restriction

Here is a great tip for how to safely debug your code.

function CanDebug() {
global $DEBUG;
$allowed = array ('127.0.0.1', '81.1.1.1');
if (in_array ($_SERVER['REMOTE_ADDR'], $allowed)) return $DEBUG;
else return 0; }

function Debug ($message) {
if (!CanDebug()) return;
if (is_string ($message)) echo $message; else var_dump ($message); ';}


Outputting debugging statements.

Place at the top of a page or configuration file to ensure that all PHP notices, warnings and errors will be shown you only. If the condition is not met, the errors will be logged instead.

if (CanDebug()) { ini_set ('display_errors', 1); error_reporting (E_ALL); }else { ini_set ('display_errors', 0); error_reporting (E_ALL & ~E_NOTICE);} 

 

Define your PHP error handling function

function error_handler($level, $message, $file, $line, $context) {
    //Handle user errors, warnings, and notices ourself
    if($level === E_USER_ERROR || $level === E_USER_WARNING || $level === E_USER_NOTICE) {
        echo 'Error: '.$message;
        return(true); //And prevent the PHP error handler from continuing
    }
    return(false); //Otherwise, use PHP's error handler
}

Environmental Variables

IP Address $_SERVER['REMOTE_ADDR']
Path of file $_SERVER['DOCUMENT_ROOT']
Path with query string $_SERVER{'REQUEST_URI']
Domain of Host $_SERVER['HTTP_HOST']
Browser detection $_SERVER['HTTP_USER_AGENT']

Error Log Class

Class log {
  //
  const USER_ERROR_DIR = '/home/site/error_log/Site_User_errors.log';
  const GENERAL_ERROR_DIR = '/home/site/error_log/Site_General_errors.log';

  /*
   User Errors...
  */
    public function user($msg,$username)
    {
    $date = date('d.m.Y h:i:s');
    $log = $msg."   |  Date:  ".$date."  |  User:  ".$username."\n";
    error_log($log, 3, self::USER_ERROR_DIR);
    }
    /*
   General Errors...
  */
    public function general($msg)
    {
    $date = date('d.m.Y h:i:s');
    $log = $msg."   |  Date:  ".$date."\n";
    error_log($msg."   |  Tarih:  ".$date, 3, self::GENERAL_ERROR_DIR);
    }

}

$log = new log();
$log->user($msg,$username); //use for user errors
//$log->general($msg); //use for general errors

Extend a Class

To extend a class,you simply include the original class definition and define the subclass using the extends keyword.
require("Frogs.php");
class Tree_Frogs extends Frogs {
}
This creates a new subclass or child class called Tree_Frogs from the original or parent class, Frogs. The child inherits all the features of the parent but can adapt some of them and acquire new ones.
To refer to the parent version, you prefix it with the parent keyword followed by two colons:
parent::originalMethod();

File Modification and Permission

File Modified Dates

$modified = date("D d Mg:i:s", filemtime($file));
$accessed = date("D d Mg:i:s", fileatime($file));

File Permissions

$perms = fileperms("/var/www/masctest-ssl/category/");
                
echo "File permssions are ".substr(sprintf("%o",$perms), -4);

Filter Posted Variables (includes arrays)

function filterParameters($array) {    
    // Check if the parameter is an array
    if(is_array($array)) {
        // Loop through the initial dimension
        foreach($array as $key => $value) {
        // Check if any nodes are arrays themselves
        if(is_array($array[$key]))
            // If they are, let the function call itself over that particular node
            $array[$key] = $this->filterParameters($array[$key]);
        
        // Check if the nodes are strings
        if(is_string($array[$key]))
            // If they are, perform the real escape function over the selected node
            $array[$key] = mysql_real_escape_string($array[$key]);
        }            
    }
    // Check if the parameter is a string
    if(is_string($array))
        // If it is, perform a  mysql_real_escape_string on the parameter
        $array = mysql_real_escape_string($array);
    return $array;        
}

 

if (!is_string($_POST['frogs']) || strlen($_POST['frogs'])) {
echo 'frogs is invalid';
}

File Uploads

Since PHP 4.2.0, PHP returns an appropriate error code along with the file array. The error code can be found in the ['error'] segment of the file array that is created during the file upload by PHP. In other words, the error might be found in $_FILES['userfile']['error'].

  • UPLOAD_ERR_OK Value: 0; There is no error, the file uploaded with success.
  • UPLOAD_ERR_INI_SIZE Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
  • UPLOAD_ERR_FORM_SIZE Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
  • UPLOAD_ERR_PARTIAL Value: 3; The uploaded file was only partially uploaded.
  • UPLOAD_ERR_NO_FILE Value: 4; No file was uploaded.

Note: These became PHP constants in PHP 4.3.0.

----

For security purposes, the uploaded file should be renamed to something random and unpredictable. Use the sha1() function to create a 40 character hash from some data (like the original file name and a unique identifier).

$tmp_name = sha1($fiel['name'].uniqid('',true));
$destination = DIR.$tmp_name.'_tmp';

Get File Contents

$file = file_get_contents('demo/open.html');
$file = strip_tags($file);
Then create a textarea and put in it htmlspecialchars($file);

PHP 500 Errors

A PHP file must have permissions set to 644. Any folder containing PHP files and PHP access (to upload files, for example) must have permissions set to 755. PHP will run a 500 error when dealing with any file or folder that has permissions set to 777!

PHP Error Messages

error_log("You messed up!", 3, "/var/tmp/my-errors.log");
0    message is sent to PHP's system logger, using the Operating System's system logging mechanism or a file, depending on what the error_log configuration directive is set to. This is the default option.
1    message is sent by email to the address in the destination parameter. This is the only message type where the fourth parameter, extra_headers is used.
2     No longer an option.
3    message is appended to the file destination. A newline is not automatically added to the end of the message string.
4    message is sent directly to the SAPI logging handler.

The extra headers. It's used when the message_type parameter is set to 1. This message type uses the same internal function as mail() does.

PHP Posting Forms

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
check to see if the page was loaded in the correct manner

Prefixes for Variable Names

  • arr Array
  • bln Boolean
  • dat Date and Time
  • dbl Double
  • dec Decimal
  • err Error
  • int Integer
  • lng Lon
  • obj Object
  • sng Single
  • str String

Random Password Generator

function generatePassword($length=9, $strength=0) {
    $vowels = 'aeuy';
    $consonants = 'bdghjmnpqrstvz';
    if ($strength & 1) {
        $consonants .= 'BDGHJLMNPQRSTVWXZ';
    }
    if ($strength & 2) {
        $vowels .= "AEUY";
    }
    if ($strength & 4) {
        $consonants .= '23456789';
    }
    if ($strength & 8) {
        $consonants .= '@#$%';
    }
 
    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) {
            $password .= $consonants[(rand() % strlen($consonants))];
            $alt = 0;
        } else {
            $password .= $vowels[(rand() % strlen($vowels))];
            $alt = 1;
        }
    }
    return $password;
}

Recommended php.ini Settings

display_errors = Off //do not display errors
display_startup_errors = Off
log_errors = On //log errors
This extra effort goes to waste if the log files can be found and read. So make sure that the log is written outside of the document root.
error_log = "/somewhere/outside/web/root/"
track_errors = Off //keeps track of last error inside global $php_errormsg. We do not want this.
html_errors = Off //inserts links to documentation about errors
expose_php = Off; //does not let the server add PHP to its header,
//thus letting on that PHP is used on the server
As previously discussed, register_globals can be a big security hole especially if variables are not
initialized.
register_globals = Off //would register form data as global variables
// DEPRECATED as of PHP 5.3.0
Magic quotes attempts to automatically escape quotes. However, this leads to inconsistencies. It is
best to use database functions for this explicitly.
magic_quotes_gpc = Off //deprecated in 5.3.0 Use database escaping instead
As previously mentioned, we should disable setting the SID in cookies or the URL.
session.use_cookies = 1
session.use_only_cookies = 1
session.use_trans_sid = 0
We can disable higher risk PHP functions, enabling some if need be.
disable_functions = curl_exec, curl_multi_exec, exec, highlight_file, parse_ini_file,passthru, phpinfo, proc_open, popen, shell_exec, show_source, system
There is the equivalent directive for PHP classes, where we can disable any that we do not want PHP to be able to use.
disable_classes =
We can harden how PHP handles file access and remote files:
allow_url_fopen = Off //whether to allow remote files to be opened
allow_url_include = Off //whether to allow includes to come from remote files
file_uploads = Off //disable only if your scripts do not need file uploads
The directive open_basedir limits the files that can be opened by PHP to the specified directory and
subtree.
open_basedir = /the/base/directory/

enable_dl = Off //can allow bypassing of open_basedir settings

For shared hosting, safe_mode restricts PHP to be executed by the appropriate user id only.
However, it does not restrict other scripting languages such as Bash or Perl from doing the same. This
limits the actual amount of safety we can expect from this directive.

safe_mode = On

Regular Expression Syntax

[:digit:] Only the digits 0 to 9
[:alnum:] Any alphanumeric character 0 to 9 OR A to Z or a to z.
[:alpha:] Any alpha character A to Z or a to z.
[:blank:] Space and TAB characters only.
[:xdigit:] Hexidecimal digits
[:punct:] Punctuation symbols . , " ' ? ! ; :
[:print:] Any printable character.
[:space:] Any space characters.
[:upper:] Any alpha character A to Z.
[:lower:] Any alpha character a to z.
[:cntrl:] Control characters

Safer Numbers

Typecast your values to numeric to force them to be numbers
$id = (int)$_GET['id'];
If anything extra is added to the id variable, it will make the value a 0.

Site Under Maintenance

function maintenance($mode = FALSE){    
     if($mode){        
     if(basename($_SERVER['SCRIPT_FILENAME']) != 'maintenance.php'){            
          header("Location: http://example.com/maintenance.php");            
          exit;        
     }    
     }else{        
     if(basename($_SERVER['SCRIPT_FILENAME']) == 'maintenance.php'){            
     header("Location: http://example.com/");            
     exit;        
     }    
     }
}
Source: http://www.phpsnippets.info/easy-maintenance-mode-with-php

Standardize email address in mail() function

Use _____@$_SERVER['SERVER_NAME'] to standardize the email addresses used.

Ten tips for bug tracking

A good tester always tries to reduce the repro steps to the minimal steps to reproduce; this is extremely helpful for the programmer who has to find the bug.

Remember that the only person who should close a bug is the person who opened it in the first place. Anyone can resolve it, but only the person who saw the bug can really be sure that what they saw is fixed.

Not Reproducible means that the programmer couldn't reproduce the bug. Programmers often use this to send a bug back to the tester when the report is missing critical steps. Good testers see this is a challenge, not an excuse to close the case.

Keep careful track of versions. When a programmer fixes the bug, they should indicate what version the fix will appear in, so that the poor tester doesn't have to retest the bug on a version of the software where it wasn't even supposed to be fixed.

Get into the habit of writing all your bug reports with three sections: steps to repro, the bug itself, and what was expected.

(Free bonus) Don't take bugs personally! If a bug is assigned to you, it's not a personal criticism, it's just a way to make the software better. After you get your first three thousand bugs or so, you'll stop feeling dejected and start feeling like a fun puzzle has appeared for you to solve. Some people pay cash money for these fun puzzles, printed up in books, which they solve at the beach or on a hammock. You get to solve them at workand get paid for it!What can be more fun than that?

Source: http://www.fogcreek.com/FogBugz/docs/60/topics/basics/Tentipsforbugtracking.html

Time Calculation

function calculate_time_past($start_time, $end_time, $format = "s") {
$time_span = strtotime($end_time) - strtotime($start_time);
if ($format == "s") { // is default format so dynamically calculate date format
if ($time_span > 60) { $format = "i:s"; }
if ($time_span > 3600) { $format = "H:i:s"; }
}
return gmdate($format, $time_span);
}
$start_time = "2007-03-28 00:50:14"; // 00:50:14 will work on its own
$end_time = "2007-03-28 00:52:59"; // 00:52:59 will also work instead
echo calculate_time_past($start_time, $end_time) . "
"; // will output 02:45
echo calculate_time_past($start_time, $end_time, "H:i:s"); // will output 00:02:45 when format is overridden

Validate Data

        if (!is_array($validation)) {
            if ($validation == "letters") {
                if (!eregi("^[a-zA-Z]*$", $value)) {
                    $valid_message = "You may only enter letters in this field.";
                }
            } elseif ($validation == "numbers") {
                if (!eregi("^[0-9\.]*$", $value)) {
                    $valid_message = "You may only enter numbers in this field.";
                }
            } elseif ($validation == "alphanum") {
                if (!eregi("^[0-9a-zA-Z]*$", $value)) {
                    $valid_message = "You may only enter letters and numbers in this field.";
                }
            } elseif ($validation == "email") {  
                if (!ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$', $value)) {
                    $valid_message = "Please enter a valid e-mail address.";
                }
            } elseif ($validation == "no_blank") {
                if ($value == "") {
                    $valid_message = "Please provide this information.";
                } else {
                    $valid_message = FALSE;
                }
            } else {
                $valid_message = FALSE;
            }
        } else {
            $validation_options = explode(",",$validation);
            for ($v=0; $v                if ($validation_options[$v] == "letters") {
                    if (!eregi("^[a-zA-Z]*$", $value)) {
                        $valid_message = "You may only enter letters in this field.";
                    }
                } elseif ($validation_options[$v] == "numbers") {
                    if (!eregi("^[0-9\.]*$", $value)) {
                        $valid_message = "You may only enter numbers in this field.";
                    }
                } elseif ($validation_options[$v] == "alphanum") {
                    if (!eregi("^[0-9a-zA-Z]*$", $value)) {
                        $valid_message = "You may only enter letters and numbers in this field.";
                    }
                } elseif ($validation_options[$v] == "email") {  
                    if (!ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$', $value)) {
                        $valid_message = "Please enter a valid e-mail address.";
                    }
                } elseif ($validation_options[$v] == "no_blank") {
                    if ($value == "") {
                        $valid_message = "Please provide this information.";
                    }
                } else {
                    $valid_message = FALSE;
                }
            }
        }        

Get Path Info

$info = pathinfo($_SERVER['PHP_SELF']);
print_r($info);
?>
Array (
[dirname]=> /dev/php
[basename]=>fs.php
[extension] =>php
)

Read and display information as an XML document

echo "echo "";
$filename = "users.txt";
$fh = fopen($filename, "r") or die("Could not open file");
while (!feof($fh)) {
echo "";
$fields = fgetcsv($fh, 1000);
echo "".$fields[0]."";
echo "".$fields[2]."";
echo "";
}
fclose($fh);
echo "";
?>

Header Redirects

Another type of redirect is the refresh type of redirect. This is easily done in HTML as a meta refresh redirect. In PHP, you can
do this as follows:

header("refresh:5;url=http://www.example.org/targeturl.php");
echo 'You\'ll be redirected in about 10 secs. If not, click <a
href="http://www.example.org/anotherurl.php">here.';

This is not a search engine friendly redirect and along with 302 redirection, it should not be used for SEO purposes. The only
thing that is acceptable to most search engines including Google is the 301 redirect.


301 redirect all non-www URLs to www URLs using PHP (assuming your protocol is http:// all throughout your website and
not using https):

//Get current page URL
$currentpageurl= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
//Check if the URL is non-www version
if (!(preg_match("/www/i",$currentpageurl))) {
//URL is a non-www version, append www to the URL
$wwwversion="http://www.".$currentpageurl;
//301 redirect to the www version
header("Location: $wwwversion",TRUE,301);
exit();
}

3.) 301 redirect all http to https (non-secure to secure 301 redirection):

$currenturl= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
//Check if it is not using the secure port which is 443
if ($_SERVER["SERVER_PORT"] != "443") {
//not connecting through secure https port, this URL is using http protocol
//append https
$secureversion="https://".$currenturl;
//Redirect to the secure version
header("Location: $secureversion",TRUE,301);
exit();
}
echo "Hi, this will redirect any non-secure page to equivalent secure page";



Conditional 301 redirect (redirect when the URL matches to a given URL)

//Function to get the current URL of the website
function currentpageurl() {
$currentpageurl = 'http';
if ($_SERVER["HTTPS"] == "on") {$currentpageurl .= "s";}
$currentpageurl .= "://";
if ($_SERVER["SERVER_PORT"] != "80") {
$currentpageurlL .=
$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
} else {
$currentpageurl .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
}
return $currentpageurl;
}
//Equate the current URL with $currentpageurl variable
$currentpageurl=currentpageurl();
//Conditional check to redirect
if ($currentpageurl=="http://www.example.org/301redirecttest.php") {
//URL match, do 301 redirect
header('Location: http://www.example.org/',TRUE,301);
exit();
}

The above example will only do a 301 redirect to the homepage URL http://www.example.org if the URL is
http://www.example.org/301redirecttest.php

ImageType

If an image is uploaded through a form, its size, type, etc are provided as part of the $_FILE associative array. To check the type of image across a local machine or nextwork, use the exif_imagetype function.
if (function_exists("exif_imagetype"))
echo exif_imagetype("/path/image.gif");
else
echo "You do not have the GD image library installed.";

PDF Hacks from PDF Hacks book