Saturday, June 27, 2009

Debugging techniques with free tools [updated 30 June]


  • Netbeans PHP 6.* + Xdebug + Firefox (with netbeans extension to server debug with javascript) !
    howto configure with
    Wamp 2.0h:
    - download
    php_xdebug-2.0.4-5.2.8.dll into the Wamp folder
    - open port 9000 in the firewall
    - edit php.ini adding

    [xdebug]
    zend_extension_ts="c:/wamp/bin/php/php5.2.9-2/ext/php_xdebug-2.0.4-5.2.8.dll"
    xdebug.remote_enable=on
    xdebug.remote_handler=dbgp
    xdebug.remote_host=localhost
    xdebug.remote_port=9000
    xdebug.remote_mode=req

    - now, let's debug the script with Netbeans choosing "Server side PHP with client side Javascript". Netbeans will install an extension for firefox which will allows to launch the script in the server (localhost). The extension will "pause" (thanks to extension and javascript) the server execution and it will be possibile to debug with netbeans when the breakpoints (put them in valid lines) will be reached.

    See the screenshot: array debug



    Note: obviously it's possible to debug the script directly in the php command line (no browsers is needed).

    Tested with Netbeans 6.7, Wamp 2.0h

    see official wiki

  • Eclipse PDT + Xdebug ! both are free. In Eclipse you can set breakpoints, then run the application; when breakpoints are reached, Eclipse will show variable values (tree explorer for multi-level arrays )
  • debug with php code
    function debugAll(var_dump($GLOBALS));
    print
    "[pre]"; debugAll(); print "[/pre]";
  • zend debugger [...]
  • [...]

Tuesday, June 23, 2009

Symfony: password hashing and login

It's a good practice not to keep the clear values of the passwords in the db, but to store only their hash values.
You can do login operations comparing the hash value of the inserted password with the stored hash value.

How to do it with Symfony 1.2, propel ORM, MD5 hashing:
  • db schema: Use a VARCHAR, length must be at least 32
  • validator:
    - require a minimum length (ex: 3 chars) or (better) regexp validation
    - use a widget Schema password
    $this->widgetSchema['password'] = new sfWidgetFormInputPassword (array(
    'always_render_empty' => false, //IMPORTANT !!
    ));
  • model: modify the method setPassword($v) assigning the md5 value:
    public function setPassword($v)
    //set md5 password if there is a new inserted password
    if (strlen($v)!=32) //if is not a md5 value, convert into it (*)
    $v = md5($v);
    return
    parent::setPassword($v); }
  • To check the login data, use the md5 value in the post action :
    $criteria->add(UsersPeer::USER,$request->getParameter('user'))
    ->
    add(UsersPeer::PASSWORD,md5($request->getParameter('passwordlogin')));
From now, only the hash value of the passwords will be stored.
The CRUD operations will work.

(*) Note: it won't work if the clear password is 32 chars length.

Monday, June 22, 2009

LAMP documentation links

PHP
SYMFONY v1.2

MYSQL
LINUX

Sunday, June 14, 2009

JSON generation with PHP and parsing with jQuery

JSON [official site][wiki] is a data interchange format (similar to XML, but simpler), often used for WEB 2.0 applications to load structured data with AJAX HTTP calls.
- PHP offers functions to encode and decode JSON from/to a PHP value.
- jQuery includes a function (getJSON) to parse HTTP resource with JSON data.

JSON pseudo grammar
#json block: comma separated couple key: value
JSON_BLOCK = { KEY1: VALUE1, KEY2: VALUE2, ..., KEY_N: VALUE_N }
#key must be a string (example: "abc123")
KEY_N = string
# value must be a native type, or array of values or json_block (recursive)
VALUE_N = string | number | true | false | null |
| [
VALUE_N,..., VALUE_N] |JSON_BLOCK

Minimal example:
//note: "less/greater than" symbols are replaced with square brackets because of blogspot limitation

/* json.php - json generation */
print json_encode( array(
"title" => "products",
"items"=> array(
array(
"id"=>"1","title"=>"1st"),
array(
"id"=>"2","title"=>"2nd")
)));
/*
result ("items" key contains an array with two values, each one is a block).
{
"title":"products",
"items": [ {"id":"1","title":"1st"}, {"id":"2","title":"2nd"} ]
}
*/


/* page.html - call JSON resource (ajax with jQuery) and write into the DOM*/
[script src="jquery-1.3.2.min.js" ][/script]
[
script]
$(
document).ready(function(){
$.
getJSON("json.php",
function(
data){
$.
each(data.items, function(i,item){
$(
"[h1]").text(item.id).appendTo("#main");
$(
"[h4]").text(item.title).appendTo("#main");
});
});
});
[/
script]
[
body]
[
div id="main" ][/div]
[/
body]

//output:
[body]
[
div id="main"
[h1]1[h1] [h4]1st[h4]
[
h1]2[h1] [h4]2nd[h4]
[/
div]
[/
body]

Wednesday, June 10, 2009

MySQL : version differences notes (draft)

Relevant features added in Mysql 4.0
  • FULLTEXT search
  • INNODB tables (and on [delete|update features]
  • UNION statement
  • TRUNCATE TABLE statement
  • multiple table delete and update
Relevant features added in Mysql 4.1
  • Subquery (nested query) supported
  • "CREATE table LIKE table 2" syntax supported
  • added storages:
    - EXAMPLE (for developers)
    - NBCLUSTER (table partitioned over many computers)
    - CSV (comma separated values storage)
    - BLACKHOLE (it doesn't store data)
  • added command "HELP"
  • API improved (multiple statement in a single call)
  • "INSERT ... ON DUPLICATE KEY UPDATE" syntax added
  • GROUP_CONCAT() added
Relevant features added in Mysql 5.0
  • BIT data type
  • Math precision improved
  • SQLSTATE error message
  • TRIGGERS (limited support)
  • VARCHAR max length increased to 2^16 byte (64 Kb)
  • "greedy" optimizer, "merge index" to improve join performance
  • Improvement of "NOT IN"
  • VARCHAR more efficient
  • INNODB less disk space usage (-20%)
  • Added storages ARCHIVE and FEDERATED
Relevant features added in Mysql 5.1
  • Partitioning (tables in different locations)
  • plugin API to load/unload components at runtime
  • event scheduler (like cronotab)
  • customizable MySQL logs (to file or tables)
  • XML and XPath functions
Relevant features added in Mysql 6.0
  • UTF8 (4 bytes), UTF16 and UTF32
  • BACKUP_DATABASE and RESTORE statements (to backup)
  • performance optimization for subqueries and joins
  • transactional locks
  • LOAD_XML statement

Monday, June 8, 2009

INNODB storage engine: notes

Advantages
  • transactions
  • row-level locking
  • foreign key constraints ! and behaviour
    ON [DELETE|UPDATE] [RESTRICT|CASCADE|SET NULL|NO ACTION|SET DEFAULT]

Disadvantages
  • INNODB does NOT support FULLTEXT index (MyISAM does)
  • not initial value for auto_increment keys

array_walk example

bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] )

/* example !!
* transform array with other arrays as elements into an array with simple elements
* array trasform !
*/

$ar = array( array(1,2), array(10,20), array(100,200) );
function
sum(&$ar) //NOTE: Argument By reference
{
$ar = $ar[0]+$ar[1];
}

array_walk($ar, "sum");
print_r($ar);
/*
Array
(
[0] => 3
[1] => 30
[2] => 300
)
*/

PHP security: input validation and XSS

for lots of reasons, security included, it's very important to validate all user input and protect our application from intentional or accidental wrong inputs.

First of all, here are some advices
  • don't use register_globals ! A malicious user may change value of script variables simply modifying the query string
  • don't use $_REQUEST: possibile loss of data. Use $_GET and $_POST

Number validation
use cast operator to validate numbers. If the malicious input is "'); drop table users", the casted (int) value will be zero.

When you use casting, remember the maximum size of int to prevent overflow. you may use (float) instead of (int).

Remember: the decimal separator is the point, not the period !
A numeric value with period (,) is not numeric, and a float casting will be delete the decimal part.

String validation
First of all, the input may contain stressed letters (French and Italian languages do, for example à,è,ì,ò and ù).
Use
set_local(LC_CTYPE,"french")
The stressed characters will be converted into the corresponding non-stressed characters (à->a, è->e, etc...).

To validate string inputs, use regular expressions !
ereg($patter, $string) // or eregi: same arguments but case insensitive
example:

if (ereg("^[0-9]{5}$", $_POST['postcode'])!==false) { /*postcode valid*/ }

"^[0-9]{5}$" means: string that contain 5 characters, each must be a number
don't forget "^" and "$" , or "a12345b" will be considered valid.

Use regular expression to validate various type of input: e-mails, URLs. For further details, php.net examples and google !

File uploads
as second argument of
move_uploaded_file ( string $filename , string $destination )
use basename($_FILE["fieldName"]["name"]) to increase security
$filename must be $_FILE["fieldName"]["tmp_name"]

Don't trust $_FILE["fieldName"]["type"]
If you expect a image, use getimagesize(). If isn't an image, the return value will be FALSE

If the size of the $destination file is different form the size of the temp file ($filename), delete it !!

Do not use magic quotes !
Magic quotes doesn't escape correctly all the special characters !
it's better to use specific db functions, such as
mysql_real_escape_string()

Pay attention to the current PHP configuration, you may do a stripslashes to $_GET data if the magic quotes are enabled. Use the get_magic_quotes_gpc()

Do not allow the user to modify serialized data !
A malicious user may be change and array with 100 elements a:100:{} to an array with millions of elements (it requires lots of memory).

If you need to pass serialized data, you should use a two-way cipher algorithm with key.

XSS
Cross site scripting allows users to insert malicious code in frontend via form submit. When the result page with the user data will be displayed (examples: weblog comments or site guestbook), the code will be executed or shown.
Examples of malicious inputs:
  • [? passthru("rm -rf *"); ?]
  • [iframe src="http://mysite.com/banner.php" ... /]
Some tips:
  • Convert characters to html entities. the "less and greater than" will be converted in HTML entities preventing not-expected HTML formatting or PHP code execution
    pho function: htmlspecialchars() //converts "ampersand", "double and single quote", "less and greater than" into HTML entities
  • Pay attention to quotes or double quotes if you compose tag attributes with user's data:
    print "[a href='{$_GET['link']}']text[/a]";
    if $_GET['link'] is: #' onclick='alert('malicous js code')' title='
    the result of the link will be execute a user-defined javascript
  • If the HTML tags are not allowed, you can use strip_tags() and remove all the tags from the user data. Note: strip_tags() does not convert special chars !
  • To only remove attributes to user submitted tags, use preg_replace()
  • If the user data is a URL, remember to check that it will not start with "javascript:" to prevent javascript code, or (better), parse with eregi()
  • to obtain a IP-based accesscontrol, you should also consider the proxy. If the user uses it, the real IP is contained in the variabile HTTP_X_FORWARDED_FOR, and validate it by using ip2long(), then long2ip() and check if the IP remain the same
  • HTTP_REFERER is not reliable, some browsers don't send it

Design Pattern: Strategy

Strategy is a way to encapsulate, manage and interchange (also at runtime) algorithms.
In the following example, we have three classes (A,B and C) that implement an interface with the method f().
The class AlgoContainer must be initiated by passing the object (external instantiation) or the class name (internal instantation).


Interface StrategyInt
{
public function f();
}

class A implements StrategyInt {
public function f() { print "A:f()"; }
}

class B implements StrategyInt {
public function f() { print "B:f()"; }
}

class C implements StrategyInt {
public function f() { print "C:f()"; }
}

class AlgoContainer {
private $strategy;
private $name;
public function __construct($s){
if (is_object($s))
$this->strategy = $s;
else
$this->strategy = new $s();
}
public function doF() {
$this->strategy->f();
}
}

//Usage 1 (external instantiation):
$ac = new AlgoContainer(new A);
$ac-> doF();

//Usage 2 (internal instantiation):
$ac = new AlgoContainer("A");
$ac-> doF();

Design Pattern: Decorator

Decorator is similar to Proxy.
Basically, decorator is an extension (or wrapper) of the original class (component) and adds features.
A decorator contains a pointer to the component class (initialized by the constructor), and the methods of the component overridden.

Example:


class ImgComponent {
private $src;
private $alt;
public function __construct($name, $src) { /* assign to properties*/ };
public function getHTML() {
return "[ img src="{$this->src}\" alt=\"{$this->alt}\" /]";
}
}

Let's write a decorator:


class ImgWithCaption extends imgComponent
{
private $caption;
private $imgComponent;
public function __construct(&$img, $caption) {
$caption->imgComponent = $caption;
$this->imgComponent = &$img;
};

public function getHTML() {
return "<div><div>{parent::getHTML()}</div>
<div> $caption</div></div>";
}
}

Design Pattern: Adapter

The Adapter design pattern is basically a wrapper, that is a class which provides methods to access to another class.
It's commonly used to normalize incompatibile interfaces.
It's similar to Proxy pattern, but it's a little different. Proxy includes an object and controls accesses to it; Adapter provides an interface to the object, usually by inheritance.



class A {
public static function sort(array $ar) { ... }
}

class B {
private $ar;
public function __construct() {}
public function sortElements() { ... };
public function returnArray() { return $ar;}
}

Now we can extend B and provide the same interface as A



class BAdapter extends B {
public static function sort(array $ar) {
$b = new B($ar);
$b->sortElements();
return $b->returnArray();
}
}

now we can use A and B2 in the same way:



print_r( A::sort(array(3,2,4)) );
print_r( BAdapter ::sort(array(3,2,4)) );

Sunday, June 7, 2009

Design Pattern: Observer

The behavioural design pattern Observer allows to automatically update one-to-many dependences.

Structure: an object (Hence: $subject) contains a list of observer references, and provides a method notify() that invoke update() of every observer. Also observers have a reference to $subject, used inside update().

Commonly used to event handling (listeners) and login issues.

Implementation in PHP5:

Define a class Subject:
  • private $observersArray // array of Observer objects
  • attach(Observer $ob) and detach(Observer $ob)
    // add/remove observer $ob to/from $observersArray
  • notify() // call the method update() of every observer attached (in $observersArray)
Define one (or more) class Observer that contain(s):
  • reference (private properties) to Subject
  • __construct($subject) // assign the object to the private properties
  • update() // do sth. on referenced Subject. Automatically invoked from subjects that have this observer attached
Usage:



//instantiate subject
$s = new Subject();

//create 2 observers
$obs1 = new Observer($s, ...);
$obs2 = new Observer($s, ...);

//attach N observers to the subject
$s->attach($obs1);
$s->attach($obs2);
...
$s->attach($obsN);

//change something in $s
$s->changeSth(...);

// to update all the observers attached: only call notify()
// All the N observers will be updated.
$s->notify();

Design Pattern: Proxy

It provides a filtered controlled access to an object, without exposing it directly.

How to implement in PHP5:
Declare a class:
  • constructor: instantiates the object (only the first time) and keeps the instance into a private properties
  • - implement the methods that provide a controlled access to the internal object
    or
    - use the magic method __call($name, $value), then checks/filters the name and arguments, and may call call_user_func_array($func, $params). The $func parameter ($func) must be an array that contains the object (private property) and the function name ($name passed to __call).
For security obvious reasons, implement also the other magic methods, such as __clone(), __se()t, __get(), __toString()


Design Pattern: Factory

Factory is a creational design pattern which handles object creation.
A factory class provides the methods to create object (whit a superclass in common), but let subclasses to decide which class will be instantiated.
Basically, it contains a static method ("connect" in the example below) that accept one parameter and makes a switch on it. Depending on the parameter, a new object of different type is returned. Typical use is when we have a super class A and subclasses A1, A2, An, and we add a static method getAx($name) { ... switching on $name and return a instance o A1 or A2... or An } .

Advantages: if we create a new type/subclass, we will not rewrite the code that create objects.

example:
Following, a class (factory) "DB" with a static method that returns an instance (object MySQL or postgreeSQL, that implements the same interface), in according to the argument (connection string).



class DB
{
public static connect($connString)
{
ereg("([a-z]*)://([a-z]*):([a-z]*)@([a-z]*)/([a-z]*)",$connString, $reg);
list($tmp, $driver, $user, $pass, $host, $db) = $reg;
switch($driver)
{
case "mysql": return new MySQL($host, $user, $pass, $db); break;
case "postgre": return new postgreSQL($user, $pass, $db, $host); break;
default: new Exception("connection string not valid !");
}
}


Example of use:
Now, let's use the factory, regardless the class type



$conn1 = DB:: connect("mysql://user:pass@localhost/db");
$conn2 = DB:: connect("postgre://user:pass@localhost/db");

//$conn1 and $conn will only use method of the common superclass/interface, ex: query()

Design Pattern: Value

Consider a class Val which contains a value, and a method add() which add another value with the same type.

class Val {
private
$value;
public function
__construct($value=0) {$this->value = $value; }

public function
get() { return $this->value; }

public function
add($newVal) {
//(1) WRONG:
//$this->addV += $value; //WRONG !!

// (2) RIGHT !!
return new Val($this->value + $newVal->get());
}
}

Add directly the value to the internal properties (1) is wrong!!
Suppose to have a class ValContainer, with a properties that is a reference to object Val.

Two or more instances of ValContainer should be contains references to the same instance of Val (e.g. via another class which contains a Val instance and returns it).

If one instance calls the method add() of Val, the other instances will have the new value modified !! This is not in according to OOP principles !

The second method (2) is right, it instantiates another Val object in case of add() !!

Design Pattern Singleton

Singleton is a creational pattern which ensures a class has only one instance, and provide a global pointer to access it.
The most common example is a database connection.

The idea: the class doesn't provide a constructor, but a method to return an instance. That instance is assigned to a static properties and is instantiated only at the 1st access.

class Example
{
// Hold an instance of the class
private static $instance;

// A private constructor; prevents direct creation of object
private function __construct() { }

// The singleton method
public static function singleton()
{
if (!isset(
self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return
self::$instance;
}

// Prevent users to clone the instance
public function __clone() { trigger_error('Clone is not allowed.', E_USER_ERROR); }

}

XMLWriter

the PHP5 XMLWriter class allows to easily create XML well-formed documents.

The most useful methods:
  • openURI($output) // use 'php://output' as argument to stream directly
  • startDocument('1.0') // add the initial tag. 1st argument : xml version
  • writeElement('hr') // write the empty node [hr/]
  • writeAttribute('src','img.gif') //write the attribute (inside the last node) and value
    e.g: [img src="http://www.blogger.com/img.gif" /]
  • writeElement('b','content') // write node with content "[b]content[/b]"
  • startElement('body') //add the start node [body]
  • endElement() //close the last element started. e.g: [/body]
  • How to create nodes with attributes and text:
    startElement('textarea')
    writeAttribute('name','area1')
    text('default text')
    endElement()

    output:
    [textarea name="area"]default text[/textarea]
  • endDocument()
  • flush()
  • there are other methods to write comments, DTD, CData etc... view the official documentation.
Note: I used square brackets instead of "minor or greater than" because of blogspot editor limitation.

Complete Example: RSS Feed !!

@date_default_timezone_set("GMT");
$xml = new XMLWriter();
// Output directly to the user
$xml->openURI('php://output');
$xml->startDocument('1.0');
$xml->setIndent(2);
//rss
$xml->startElement('rss');
$xml->writeAttribute('version', '2.0');
$xml->writeAttribute('xmlns:atom', 'http://www.w3.org/2005/Atom');

//channel
$xml->startElement("channel");

//title, desc, link, date
$xml->writeElement('title', 'PHP news');
$xml->writeElement('description', 'description....');
$xml->writeElement('link', 'http://www.example.com/rss.hml');
$xml->writeElement('pubDate', date("D, d M Y H:i:s e"));

//item !
$xml->startElement("item");
$xml->writeElement('title', 'news 1');
$xml->writeElement('link', 'http://www.example.com/1.html');
$xml->writeElement('description', 'descr 1');
$xml->writeElement('pubDate', date("D, d M Y H:i:s e"));
//cat
$xml->startElement('category');
$xml->writeAttribute('domain', 'http://www.example.com/cat1.htm');
$xml->text('News');
$xml->endElement();
//end item
$xml->endElement();
//end channel
$xml->endElement();
// end rss
$xml->endElement();
//end doc
$xml->endDocument();
//flush
$xml->flush();


output:




SPL: DirectoryIterator

foreach (new DirectoryIterator('.') as $fileInfo) {
//if($fileInfo->isDot()) continue;

echo "Name: ".$fileInfo->getFilename() . "\n";
echo
"Last : ".date("d/m/Y H:i", $fileInfo->getCTime()) . "\n";
echo
"Size: ".$fileInfo->getSize() . " byte\n";
echo
"Type: ".$fileInfo->getType() . "\n"; //dir or file
echo "Executable: ".($fileInfo->isExecutable()?"yes":"no") . "\n";
echo
"Readable: ".($fileInfo->isReadable()?"yes":"no") . "\n";
echo
"Writable: ".($fileInfo->isWritable()?"yes":"no") . "\n";
}

Saturday, June 6, 2009

ArrayAccess: use object as an array, file manager example

ArrayAccess (PHP5) allows to treat objects as an array.
View below the interface scheme, with explanatory comments

ArrayAccess { //PHP5 built-in Interface
// returns true/false if the element in the position $offset exists/doesn't exist
abstract public boolean offsetExists ( string $offset )
// returns the element at the position $offset
abstract public mixed offsetGet ( string $offset )
// set the element at the position $offset to the value $value
abstract public void offsetSet ( string $offset , string $value )
//delete the element at the position $offset
abstract public void offsetUnset ( string $offset )
}

minimal implementation (to copy to quickly use).

class ... implements ArrayAccess
{
public function
offsetExists( $offset ){}
public function
offsetGet( $offset ){}
public function
offsetSet( $offset , $value ){}
public function
offsetUnset( $offset ){}
}


An useful example !
Let's write a class which allows to easily manage files content, like an array.

$obj["file.txt"] = "content"; //write "content" into file.txt
$obj["file.txt"] .= "content"; //append "content" into file.txt
print $obj["file.txt"] ; //print the content of file.txt
unset($obj["file.txt"]); //delete file.txt
if (isset($obj["file.txt"])) {} ; // equivalent to file_exists("file.txt")


/* class to easy manage files content like an array */
class filesManager implements ArrayAccess
{
private $basePath;
private
$prefix;
private
$suffix;

public function
__construct($basePath="", $prefix="", $suffix=""){
$this->basePath = $basePath;
$this->prefix = $prefix;
$this->suffix = $suffix;
}

//get files basepath + prefix
private function path($file){
return
$this->basePath.$this->prefix.$file.$this->suffix;
}

//file exists ?
public function offsetExists( $file ){
return
file_exists($this->path($file));
}

//read file
public function offsetGet( $file ){
if (!
$this->offsetExists($file)) return "";
$handle = fopen($this->path($file), "r");
$contents = fread($handle, filesize($this->path($file)));
fclose($handle);
return
$contents;
}

//write new content into a file
public function offsetSet( $file , $value ){
$handle = fopen($this->path($file), "w");
fwrite($handle, $value);
fclose($handle);
}

//delete file
public function offsetUnset( $file ){
unlink($this->path($file));
}

}




//example of use

/* the files will be read and created in
* the folder "data", with prefix "_" and
* suffix ".txt" */
$f = new filesManager("data/","_",".txt");

//create the file "data/_notes.txt" and write "file start" inside !
if (!isset($f['notes']))
$f['notes'] = "file start !";

//append
$f['notes'] .= "\nanother line";

//print all the content
print $f['notes'];

//delete
unset($f['notes']);

 

PHP and tips|PHP