hypertext preprocessor demystified

236
PHP Course Material Introduction of PHP What Is PHP? PHP stands for PHP: Hypertext Preprocessor, a recursive acronym. It is mainly a Web server side scripting language. But it can also be used for other purposes. PHP was originally created by Rasmus Lerdorf in 1995 as a simple Web page generation tool named as PHP/FI (Personal Home Page/Forms Interpreter). Today it becomes the number one of server side scripting languages. Here is a comparison of number of matches on Google for key words: "PHP script", "Perl script", and "ASP script": Main features of PHP: Cookies - PHP transparently supports HTTP cookies. Sessions - PHP supports sessions to allow you to preserve certain data across subsequent accesses. Connection handling - PHP maintains a connection in 3 possible states: NORMAL, ABORTED, and TIMEOUT. Using remote files - PHP allows you to open remote files with Internet protocols like HTTP or FTP. Persistent Database Connections - PHP supports persistent connections to database servers. File uploads - PHP allows Web users to upload single or multiple files. Safe mode - PHP supports a safe mode with many built-in functions restricted or disabled. Command line - PHP supports many command line options. PHP Variables Variable => Value 1 Naresh i Technologies

Upload: balajisap

Post on 10-Jul-2016

47 views

Category:

Documents


0 download

DESCRIPTION

Hypertext Preprocessor

TRANSCRIPT

Page 1: Hypertext Preprocessor Demystified

PHP Course Material

Introduction of PHP

What Is PHP?

PHP stands for PHP: Hypertext Preprocessor, a recursive acronym. It is mainly a Web server side scripting language. But it can also be used for other purposes.

PHP was originally created by Rasmus Lerdorf in 1995 as a simple Web page generation tool named as PHP/FI (Personal Home Page/Forms Interpreter). Today it becomes the number one of server side scripting languages. Here is a comparison of number of matches on Google for key words: "PHP script", "Perl script", and "ASP script":

Main features of PHP:

Cookies - PHP transparently supports HTTP cookies. Sessions - PHP supports sessions to allow you to preserve certain data across subsequent

accesses.

Connection handling - PHP maintains a connection in 3 possible states: NORMAL, ABORTED, and TIMEOUT.

Using remote files - PHP allows you to open remote files with Internet protocols like HTTP or FTP.

Persistent Database Connections - PHP supports persistent connections to database servers.

File uploads - PHP allows Web users to upload single or multiple files.

Safe mode - PHP supports a safe mode with many built-in functions restricted or disabled.

Command line - PHP supports many command line options.

PHP Variables

Variable => Value_SERVER["CLIENTNAME"] => Console_SERVER["CommonProgramFiles"] => C:\Program Files\Common Files_SERVER["ComSpec"] => C:\WINDOWS\system32\cmd.exe_SERVER["HOMEDRIVE"] => C:_SERVER["NUMBER_OF_PROCESSORS"] => 2_SERVER["OS"] => Windows_NT_SERVER["SESSIONNAME"] => Console...

_ENV["CLIENTNAME"] => Console_ENV["CommonProgramFiles"] => C:\Program Files\Common Files_ENV["ComSpec"] => C:\WINDOWS\system32\cmd.exe

1 Naresh i Technologies

Page 2: Hypertext Preprocessor Demystified

PHP Course Material_ENV["HOMEDRIVE"] => C:_ENV["NUMBER_OF_PROCESSORS"] => 2_ENV["OS"] => Windows_NT..Hello.php - My First PHP Script

Use any text editor like notepad, and enter the first PHP script, Hello.php:

Hello <?php echo "world!"; ?>

Adding PHP to IIS as CGI

If you want to add PHP scripts to your IIS server to serve as Web pages, you need to add the PHP engine to the IIS server as a CGI interface.

1. Add \php to the PATH environment variable. I assume you know how to do this.

2. Set up PHP configuration file. First copy \php\php.ini-recommended to \php\php.ini. Then edit \php\php.ini to set the following values:

cgi.force_redirect = 0doc_root = "c:\inetpub\wwwroot"cgi.redirect_status_env = ENV_VAR_NAME

3. Create a new environment variable PHPRC with \php. This is needed to access php.ini.

4. Now we need to change IIS configuration to run PHP scripts as CGI scripts. Click Control Panel, Internet Information Service (IIS), Default Web Site, and Properties. On the Directory tab, first set Execute Permissions to "Scripts only". Then click Configuration to add a new Application Mapping with Executable=\php\php-cgi.exe, Extension=.php, and Script engine checked.

5. Stop and start Default Web Site in IIS.

6. Copy Hello.php to \inetpub\wwwroot.

7. Run Internet Explorer (IE) with http://localhost/Hello.php. You should see:

Hello world!

2 Naresh i Technologies

Page 3: Hypertext Preprocessor Demystified

PHP Course Material

PHP Script File Syntax

This chapter provides tutorial notes and example codes on PHP script file syntax. Topics include what tags to use to include a PHP code segment in a script file; script file processing rules; how to split 1 statement in multiple lines, how to enter comments into PHP scripts.

PHP Script Source Code File Format

PHP Script Processing Rules

PHP Statement Delimiter and Comments

PHP Script Source Code File Format This section describes the PHP script source code file format - A text file with PHP code segments mixed into non-PHP text. The most common way to mix PHP codes is to use the PHP processing tag '?php'.

Since multiple PHP code segments can be mixed with non-PHP text, a PHP script source code will look like this:

text PHP_code text PHP_code text PHP_code ...

When you ask the PHP to process a PHP script source code, it will separate PHP code segments from the non-PHP text using following 3 default rules:

1. PHP processing tag: <?php PHP_code ?> - Everything included in the "php" tag will be processed as PHP code. For example:

Hello <?php $name = "Herong"; echo $name;?>, Nice to meet you!

2. PHP processing tag shorthand: <? PHP_code ?> - Everything included in the "php" tag will be processed as PHP code. For example:

Hello <? $name = "Herong"; echo $name;?>, Nice to meet you!

3. HTML "script" tag: <script language="php">PHP_code</script> - Everything between the "script" starting tag and the "script" ending tag will be processed as PHP code. For example:

3 Naresh i Technologies

Page 4: Hypertext Preprocessor Demystified

PHP Course MaterialHello <script language="php"> $name = "Herong"; echo $name;</script>, Nice to meet you!

The PHP processing tag is the most commonly used way to mixed PHP codes into non-PHP text to create a PHP script source code file. Since most PHP scripts are designed to generate Web pages, non-PHP text in a PHP script source code is made of mostly HTML tags. Here is an example of a PHP script source code that generates a simple Web page:

<html><head><title>Welcome Page</title></head><body><p>Hello <?php $name = "Herong"; echo $name;?>, Nice to meet you!</p></body></html>PHP Script Processing Rules This section describes the PHP script source code processing rules - all non-PHP text segments are converted into print statements and merged with PHP code segments to form a single code block.

As I mentioned in the previous section, a PHP script source code is a sequence non-PHP text segments and PHP code segments. The PHP engine will process the source code in 3 logical steps:

Converting each non-PHP text segment into a PHP code segment with a print statement. Joining all PHP code segments into a single final PHP code block.

Executing the final PHP code block.

In anothe word, a PHP script source code can be viewed as a single PHP code block. All non-PHP text segments are just PHP print statements written in a special way.

PHP's processing rules are very similar to Active Server Page (ASP)'s processing rules.

Now let's see an example PHP script source code file:

<?php /* HeadOrTail.php* Copyright (c) Nareshit.com*/ ?>I am tossing a coin now. Guess what the result will be? <?php $coin = rand(0,1); ?><?php if ($coin==1) { ?> Head<?php } else { ?>

4 Naresh i Technologies

Page 5: Hypertext Preprocessor Demystified

PHP Course Material Tail<?php } ?>

If you process this script with the PHP engine, you will get:

I am tossing a coin now. Guess what the result will be? Tail

Based on the PHP engine processing rules, the above script is identical to this script from the PHP engine process point of view:

<?php /* HeadOrTailModified.php

*/ print "I am tossing a coin now. Guess what the result will be?\n";$coin = rand(0,1); if ($coin==1) { print " Head\n";} else { print " Tail\n";} ?>PHP Statement Delimiter and Comments: This section provides a tutorial example on how to write PHP statements and comment in PHP source code files. PHP uses semicolon ';' as the statement delimiter. Comments can be entered in Perl, Java, or C styles.

PHP uses semicolon ";" as the statement delimiter. PHP statements can be written in the source code file in different ways:

The most common way is to write one statement per one code line. But you can split one statement into multiple code lines if you have a long statement.

You can also write multiple statements in one code line, if you want to.

If you want to enter comments into the PHP source code, you can do it in 3 ways:

Perl style: Using "#" Java style: Using "//"

C style: Using "/*" and "*/"

Here is a tutorial example on how to write PHP statements and comments:

<?php /* StatementSamples .php*/

# The next 1 statement is written in 2 code lines.print "I am tossing a coin now. "

5 Naresh i Technologies

Page 6: Hypertext Preprocessor Demystified

PHP Course Material . "Guess what the result will be?\n";

/* I am using the rand() function to simulate the randomness of tossing a coin. The rand(min,max) function returns a random integerbetween the specified minimum number and maximum number.-- This is a sample of C style comment*/

# The next 1 statement is written in 1 code line.$count = 0;while ($count < 7) { # Next 2 statements are written in 1 code line. $count++; print "Round # $count:\n";

$coin = rand(0,1); if ($coin==1) { print " Head\n"; // Java style comment } else { print " Tail\n"; # Perl style comment }}?>

There is no surprises in the output:

I am tossing a coin now. Guess what the result will be?Round # 1: TailRound # 2: TailRound # 3: HeadRound # 4: TailRound # 5: TailRound # 6: HeadRound # 7: TailPHP Data Types and Data Literals

This chapter provides tutorial notes and example codes on PHP data types and data literals. Topics include 8 data types supported in PHP; data literals to provide data values in PHP code for different data types; integer and float value overflow conditions.

Data Types Supported in PHP

Data Literals Supported in PHP

Data Literals Examples for Integer, String and Other Data Types

Overflow of Integer and Float Values

6 Naresh i Technologies

Page 7: Hypertext Preprocessor Demystified

PHP Course Material

Conclusion:

PHP supports 8 data types: boolean, integer, float, string, array, object, resource, null. PHP integer data type uses the 32-bit signed integer storage format.

PHP float data type uses the 64-bit floating-point number storage format, the IEEE 754 double-precision standard.

PHP sting data type uses the 8-bit byte storage format.

PHP array data type uses key-value pairs to manage array elements. PHP arrays are really associate arrays, maps or hash tables in other programming languages.

PHP handles integer value overflow conditions by automatically converting results to float data type.

PHP handles float value overflow conditions by automatically converting results to "infinite" or 0.

Variables, References, and Constants

This chapter provides tutorial notes and example codes on PHP variables, references, and constants. Topics include how to name variables; assigning data values to variables; creating the reference of a variable; using variable variable names; using string expressions as variable names; defining constant names to values; retrieving the value from a constant.

Variables and Assignment Operations

References and Variables

Variable Variable Name - Name Variables with Expressions

Constant and define() Function

Conclusion:

PHP variables are typeless. Values of different data types can be assigned to the same variable.

PHP variable names starts with $ sign.

& operator returns the reference of a variable.

The reference of a variable can be assigned to a new variable to make an alias to the original variable.

A variable name can represented as a string expression. This is called variable variable name.

Functions define() defines a constant with the constant name and the constant value.

Only scalar data type values can be used as constant values.

7 Naresh i Technologies

Page 8: Hypertext Preprocessor Demystified

PHP Course Material

Variables and Assignment OperationsThis section describes what is a variable, variable names prefixed with $, 'set' and 'unset' states of a variable, assigning data to variables, var_dump($var) to print variable information.

What is a variable? A variable is an identifier for a piece of data stored in memory during the program execution. In PHP, variables are used under these basic rules:

1. A variable name in PHP must be prefixed with a "$" sign. Perl has a similar rule for scale variables.

2. Variable names are case sensitive. So $address and $Address refer to two different variables.

3. Variables in PHP are typeless. Therefor there is no variable type declaration statements in PHP. Any variable can be used as the identifier for any data type.

4. A variable has 2 states: "set" and "unset". A variable is in the "set" state, if a piece of data has been assigned to it. A variable is in the "unset" state, if there is no data assigned to it.

5. Assignment operations (coded by the assignment operator, =) can be used to assign data to variables.

6. The unset($var) function can be used to remove the assigned data from the given variable.

7. Variables can used in any operations like data literals in PHP source code. If a variable with data assigned is used in an operation, the assigned data value will be used for the operation. If a variable with no data assigned is used in an operation, NULL will be used for the operation.

8. There are some special characters that you should not use them as part of a variable name, ' ', '$', '[', ']', '{', '}', ...

PHP has a nice built-in function, var_dump($var), that prints out detailed information about the specified variable.

To show you some of variable rules mentioned above, I wrote the following PHP script, VariableTest.php:

<?php # VariableTest.php# print "\nVariable assignments:\n"; $u; # Not assigning to any data print "\n \$u: "; var_dump($u);

$b = TRUE; # Assigning a boolean print "\n \$b: "; var_dump($b);

$i = 777; # Assigning an integer print "\n \$i: "; var_dump($i); $f = 3.14; # Assigning a float

8 Naresh i Technologies

Page 9: Hypertext Preprocessor Demystified

PHP Course Material print "\n \$f: "; var_dump($f);

$s = "Hello Herong"; # Assigning a string print "\n \$s: "; var_dump($s);

$a = array("Jan"=>31,"Feb"=>28); # Assigning an array print "\n \$a: "; var_dump($a);

$o = new DateTime(); # Assigning an object print "\n \$o: "; var_dump($o);

$r = opendir("."); # Assigning a resource print "\n \$r: "; var_dump($r);

$n = NULL; # Assigning NULL print "\n \$n: "; var_dump($n);?>

If you run this sample script, you should get:

Variable assignments:

$u: NULL

$b: bool(true)

$i: int(777)

$f: float(3.14)

$s: string(12) "Hello Herong"

$a: array(3) { ["Jan"]=> int(31) ["Feb"]=> int(28) ["Mar"]=> int(31)}

$o: object(DateTime)#1 (0) {}

$r: resource(4) of type (stream)

$n: NULLReferences and VariablesThis section describes what is a reference, creating references with & operator, assigning references to variables, removing reference links with unset($var) function.

What is a reference? A reference is an alias of a variable. PHP supports references in a very similar way as the Perl language. Here are some basic rules about using references in PHP:

1. To create a reference of a given variable, you need to use the reference operator: &. For example, &$title creates a reference of variable $title.

9 Naresh i Technologies

Page 10: Hypertext Preprocessor Demystified

PHP Course Material

2. Reference can be assigned to another variable using the assignment operator: =. For example, $subject = &$title assigns the reference of variable $title to variable $subject.

3. The variable holding the reference is an alias of the original variable and behaves the same way as the original variable. For example, $subject = &$title; var_dump($subject); prints information of the data assigned to variable $title.

4. If the original variable is assigned to a new data, the reference variable is automatically assigned to that new data. For example, $subject = &$title; $title = "New String"; assigns "New String" to both $subject and $title.

5. If the reference variable is assigned to a new data, the original variable is automatically assigned to that new data. For example, $subject = &$title; $subject = "New Text"; assigns "New Text" to both $subject and $title.

6. Multiple reference variables can be created by assigning the reference to multiple variables. For example, $subject = &$title; $topic = &$title; assigns the reference of $title to both $subject and $topic.

7. Actually, original variable and its reference variables can all be viewed as references to the assigned data shared by all of them. For example, $subject = &$title; $topic = &$title; $topic = "New Message"; creates 3 variables referring to the same data "New Message".

8. To remove the reference link between a variable and its assigned data, you need to use the unset($var) function. For example; $title = "New String"; unset($title); removes the reference link between $title and "New String". $title is in the "unset" states now.

9. If multiple variables are referencing the same data, removing the reference link on one variable does not affect other variables. For example, $subject = &$title; $topic = &$title; $topic = "New Message"; unset($topic); removes the reference link on $topic, but $subject and $title are still referring to "New Message".

10. If multiple variables are referencing the same data, assigning a new reference to a new data to one variable does not affect other variables. For example, $subject = &$title; $topic = &$title; $topic = "New Message"; $topic = &$name; assigns the reference of $name to $topic, but $subject and $title are still referring to "New Message".

To show you some of reference rules mentioned above, I wrote the following PHP script, ReferenceTest.php:

<?php # ReferenceTest.php# $title; print "\n \$title is not assigned to anything:\n"; print " \$title: "; var_dump($title);

$subject = &$title; print "\n \$subject is an alias of $title:\n"; print " \$subject: "; var_dump($subject); print " \$title: "; var_dump($title);

10 Naresh i Technologies

Page 11: Hypertext Preprocessor Demystified

PHP Course Material

$subject = "Herong's PHP Book"; print "\n \$subject is assigned with a string:\n"; print " \$title: "; var_dump($title); print " \$subject: "; var_dump($subject);

$title = "Herong's Programming Book"; print "\n \$title is reassigned with a new string:\n"; print " \$title: "; var_dump($title); print " \$subject: "; var_dump($subject);

$topic = &$subject; print "\n \$topic is added as the third reference variable:\n"; print " \$title: "; var_dump($title); print " \$subject: "; var_dump($subject); print " \$topic: "; var_dump($topic);

unset($subject); print "\n \$subject's reference link is removed:\n"; print " \$title: "; var_dump($title); print " \$subject: "; var_dump($subject); print " \$topic: "; var_dump($topic);

$name = "Herong's Tutorial Book"; $title = &$name; print "\n \$title is assigned to a new reference:\n"; print " \$title: "; var_dump($title); print " \$subject: "; var_dump($subject); print " \$topic: "; var_dump($topic); print " \$name: "; var_dump($name);?>

If you run this sample script, you should get:

$title is not assigned to anything: $title: NULL

$subject is an alias of : $subject: NULL $title: NULL

$subject is assigned with a string: $title: string(17) "Herong's PHP Book" $subject: string(17) "Herong's PHP Book"

$title is reassigned with a new string: $title: string(25) "Herong's Programming Book" $subject: string(25) "Herong's Programming Book"

$topic is added as the third reference variable: $title: string(25) "Herong's Programming Book" $subject: string(25) "Herong's Programming Book" $topic: string(25) "Herong's Programming Book"

$subject's reference link is removed: $title: string(25) "Herong's Programming Book" $subject: NULL

11 Naresh i Technologies

Page 12: Hypertext Preprocessor Demystified

PHP Course Material $topic: string(25) "Herong's Programming Book"

$title is assigned to a new reference: $title: string(22) "Herong's Tutorial Book" $subject: NULL $topic: string(25) "Herong's Programming Book" $name: string(22) "Herong's Tutorial Book"Variable Variable Name - Name Variables with ExpressionsThis section describes what is a variable variable name, storing the variable name in another variable, naming variables with expressions, using any expressions as variable names.

What is a Variable Variable Name: A variable variable name is a variable name that is stored inside another variable. Normally, a variable name is a static string. But sometimes, you want to store a variable name inside another variable to be able to participate in operations. PHP supports variable variable names with following basic rules:

1. If the name of the original variable is stored in a different variable, you can use the $$var notation to identify the original variable in your PHP source code. For example, $variableName = "title"; $$variableName represents the variable $title.

2. If the name of the original variable can be calculated by an expression, you can use the ${exp} notation to identify the original variable in your PHP source code. For example, $variableName = "title"; ${$variableName."_1"} represents the variable $title_1.

3. Variables with variable names can be assigned with new data like normal variables. For example, $variableName = "title"; $$variableName = "Herong's PHP Book"; assigns "Herong's PHP Book" to $title.

4. Variables with variable names can be used in any operations like normal variables. $variableName = "title"; $$variableName = "Herong's PHP Book"; print($$variableName." is free"); prints "Herong's PHP Book is free".

5. If you use an expression as the variable name, the result of the expression will be automatically converted to a string, which will be used as the variable name. With this automatic conversion, anything can be used as a variable name. Even an empty string can be used as a variable name, ${""} is a perfect variable expression.

Now let's look at my tutorial example below to confirm some rules mentioned above:

<?php # VariableVariableName.php# $variableName = "title"; $$variableName = "Herong's PHP Book"; print "\n \$\$variableName is assigned to a message:\n"; print " \$variableName: "; var_dump($variableName); print " \$\$variableName: "; var_dump($$variableName); print " \$title: "; var_dump($title);

$variableName = ""; $$variableName = "Herong's Programming Book"; print "\n \$variableName contains an empty string:\n";

12 Naresh i Technologies

Page 13: Hypertext Preprocessor Demystified

PHP Course Material print " \$variableName: "; var_dump($variableName); print " \$\$variableName: "; var_dump($$variableName); print " \${''}: "; var_dump(${''});

$variableName = NULL; $$variableName = "Herong's Tutorial Book"; print "\n \$variableName contains the NULL:\n"; print " \$variableName: "; var_dump($variableName); print " \$\$variableName: "; var_dump($$variableName); print " \${NULL}: "; var_dump(${NULL});

$variableName = 1.0/3.3; $$variableName = "Herong's Free Book"; print "\n \$variableName contains a float number:\n"; print " \$variableName: "; var_dump($variableName); print " \$\$variableName: "; var_dump($$variableName); print " \${1.0/3.3}: "; var_dump(${1.0/3.3});?>

If you run this sample script, you should get:

$$variableName is assigned to a message: $variableName: string(5) "title" $$variableName: string(17) "Herong's PHP Book" $title: string(17) "Herong's PHP Book"

$variableName contains an empty string: $variableName: string(0) "" $$variableName: string(25) "Herong's Programming Book" ${''}: string(25) "Herong's Programming Book"

$variableName contains the NULL: $variableName: NULL $$variableName: string(22) "Herong's Tutorial Book" ${NULL}: string(22) "Herong's Tutorial Book"

$variableName contains a float number: $variableName: float(0.30303030303) $$variableName: string(18) "Herong's Free Book" ${1.0/3.3}: string(18) "Herong's Free Book"Constant and define() FunctionThis section describes what is a constant, define() function defines a constant name to a value, constant value can retrieved by the name directly or by the constant() function, any string can be used as constant name.

What Is a Constant? A constant is an identifier for a data value. Once defined, the data value identified by a constant can not be changed. PHP supports constants with following basic rules:

1. A constant must be defined with the define(name, value). For example, define("PI", 3.14159); defines a constant named as PI to a value of 3.14159.

2. To retrieve the value defined in a constant, you can use the constant name directly in any expression. For example, define("PI", 3.14159); $area = PI * $radius * $radius; uses the value define in PI to calculate the area.

13 Naresh i Technologies

Page 14: Hypertext Preprocessor Demystified

PHP Course Material

3. You are allowed to use any string for the constant name. For example, define("LONG PI", 3.14159265359); defines a constant named as 'LONG PI' to a value of 3.14159265359. But using special characters in constant names are not recommended.

4. If a constant name contains special characters, you need to use the constant(name) function to retrieve the value defined in the constant. For example, define("LONG PI", 3.14159265359); $area = constant("LONG PI") * $radius * $radius; uses the value defined in "LONG PI" to calculate the area.

5. If you want to know if there is a constant defined for a given constant name, you can use the define(name) function. For example, define("LONG PI", 3.14159265359); defined("LONG PI"); returns TRUE. And defined("LONG RI") returns FALSE.

6. Constants can be defined with only value of scalar data types: boolean, integer, float, and string.

7. The PHP engine provides a number of prefined (built-in) constants. For example, __FILE__, __LINE__, PHP_OS, PHP_VERSION, PHP_INT_MAX, DIRECTORY_SEPARATOR, ...

Now let's look at my tutorial example below to confirm some rules mentioned above:

<?php # ConstantTest.php# print "\n PI is not defined as a constant:\n"; print " PI: "; var_dump(PI);

define("PI", 3.14159); print "\n PI is defined to a constant now:\n"; print " PI: "; var_dump(PI);

define("LONG PI", 3.14159265359); print "\n LONG PI is defined to a constant now:\n"; print " LONG PI: "; var_dump(constant("LONG PI"));

print "\n LONG RI is not defined as a constant:\n"; print " LONG PI: "; var_dump(defined("LONG PI")); print " LONG RI: "; var_dump(defined("LONG RI"));

print "\n Trying to define DAYS to an array:\n"; define("DAYS", array("Jan"=>31,"Feb"=>28)); print " DAYS: "; var_dump(DAYS);

print "\n PHP built-in constants:\n"; print " __FILE__: "; var_dump(__FILE__); print " __LINE__: "; var_dump(__LINE__); print " PHP_OS: "; var_dump(PHP_OS); print " PHP_VERSION: "; var_dump(PHP_VERSION); print " PHP_INT_MAX: "; var_dump(PHP_INT_MAX); print " DIRECTORY_SEPARATOR: "; var_dump(DIRECTORY_SEPARATOR);?>

If you run this sample script, you should get:

14 Naresh i Technologies

Page 15: Hypertext Preprocessor Demystified

PHP Course Material PI is not defined as a constant: PI: string(2) "PI"

PI is defined to a constant now: PI: float(3.14159)

LONG PI is defined to a constant now: LONG PI: float(3.14159265359)

LONG RI is not defined as a constant: LONG PI: bool(true) LONG RI: bool(false)

Trying to define DAYS to an array:

Warning: Constants may only evaluate to scalar values in C:\herong\php_book\ConstantTest.php on line 20 DAYS: string(4) "DAYS"

PHP built-in constants: __FILE__: string(43) "C:\herong\php_book\ConstantTest.php" __LINE__: int(25) PHP_OS: string(5) "WINNT" PHP_VERSION: string(5) "5.0.4" PHP_INT_MAX: int(2147483647) DIRECTORY_SEPARATOR: string(1) "\"Expressions, Operations and Type Conversions

This chapter provides tutorial notes and example codes on PHP expressions and operations. Topics include writing expressions with data literals, variables, and operations; bitwise, arithmetic, comparison, logical, string, and assignment operations; precedence of operations; data type automatic conversions.

What Is an Expression?

What Is an Operation?

Precedence of Operations

Data Type Automatic Conversion

Conclusion:

PHP supports 6 basic types of operations: bitwise, arithmetic, comparison, logical, string, and assignment operations.

PHP performs automatic type conversion, if an operand has a data type that does match the operator.

Write your expressions properly with operand data types match operators to avoid automatic type conversion.

What Is an Expression?

15 Naresh i Technologies

Page 16: Hypertext Preprocessor Demystified

PHP Course Material

This section provides an introduction of what is an expression. A data literal or a variable is a simple expression. A single operation or a group of multiple operations is a complex express.

What Is an Expression? Giving a precise single definition of an expression is not an easy task. So I will try to define it in a recursive way:

1. A simple expression is a presentation of a data value like, a literal, a variable, an element of an array, or a function call.

2. A complex expression is a presentation of a data value returned from an operation represented by an operator, and one or two expressions as operands. The operation will result a new data value.

If you apply rule #2 recursively, an expression may contain multiple operations in a sequence. When this happens, operations must be carried out in an order defined by the following rules:

A. The operation enclosed in a pair of parentheses must be carried out before an operation outside the parentheses.

B. The operation with a higher precedence must be carried out before an operation with lower precedence.

C. The operation on the left must be carried out before the operation on the right.

D. Rule A must be applied before Rule B, which must be applied before Rule C.

Examples of expressions:

"Hello world!" # Simple expression - a String literal 777 # Simple expression - an Integer literal $author # Simple expression - a variable getdate() # Simple expression - a function call

7*9.99 # Complex expression - an arithmetic operation "Hello ".$author # Complex expression - a string concatenation (7+2)*9.99 > 50 # Complex expression - multiple operationsWhat Is an Operation? This section describes what is an operation - a process that takes one or two operands and returns a result based on certain processing rule represented by the operator.

What Is an Operation? An operation is a process that takes one or two operands and returns a result based on certain processing rule represented by the operator. PHP supports most types of operations used in other programming languages:

1. Bitwise Operations: and ($a & $b), or ($a | $b), xor ($a ^ $b), not (~ $a), shift left ($a << $s), and shift right ($a >> $s).

2. Incrementing/Decrementing Operations: pre-increment (++$a), post-increment ($a++), pre-decrement (--$a), and post-decrement ($a--).

16 Naresh i Technologies

Page 17: Hypertext Preprocessor Demystified

PHP Course Material

3. Arithmetic Operations: negation (-$a), addition ($a + $b), subtraction ($a - $b), multiplication ($a * $b), division ($a / $b), and modulus ($a % $b).

4. Comparison Operations: equal ($a == $b), identical ($a === $b), not equal ($a != $b, $a <> $b), not identical ($a !== $b), less than ($a < $b), greater than ($a > $b), less than or equal ($a <= $b), and greater than or equal ($a >= $b).

5. Logical Operations: and ($a and $b, $a && $b), or ($a or $b, $a || $b), xor ($a xor $b), and not (!$a).

6. String Operation: concatenation ($a . %b).

7. Assignment Operations: assignment ($a = %b), addition with assignment ($a += $b), subtraction with assignment ($a -= $b), multiplication with assignment ($a *= $b), division with assignment ($a /= $b), modulus with assignment ($a %= $b), and concatenation with assignment ($a .= %b).

To help us understand different types of operations, I wrote the following PHP script, OperationTest.php:

<?php # OperationTest.php# print "\n Bitwise Operations:\n"; print " 0x00FF & 0x3210: " . (0x00FF & 0x3210) . "\n"; print " 0x0001 | 0x0010: " . (0x0001 | 0x0010) . "\n"; print " 0x0001 << 4: " . (0x0001 << 4) . "\n"; print " 0x0100 >> 4: " . (0x0100 >> 4) . "\n";

print "\n Incrementing/Decrementing Operations:\n"; $a = 10; $b = ++$a * 2; print " \$b = ++\$a * 2: $a, $b\n"; $a = 10; $b = $a++ * 2; print " \$b = \$a++ *2: $a, $b\n"; print "\n Arithmetic Operations:\n"; $a = 9; $b = 4; print " \$a * \$b: ". $a * $b . "\n"; print " \$a * \$b: ". $a / $b . "\n"; print " \$a * \$b: ". $a % $b . "\n";

print "\n Comparison Operations:\n"; $a = 9; $b = 4; print " \$a > \$b: ". ($a > $b) . "\n"; print " \$a < \$b: ". ($a < $b) . "\n";

print "\n Logical Operations:\n"; $a = 9; $b = 4; $c = 1; print " \$a > \$b && \$b > \$c: ". ($a > $b && $b > $c) . "\n";

print "\n String Operation:\n"; $name = "Herong"; $greeting = "Hello"; print " \$greeting . \$name: ". ($greeting . $name) . "\n";

print "\n Assignment Operation:\n";

17 Naresh i Technologies

Page 18: Hypertext Preprocessor Demystified

PHP Course Material print " \$name=\"Herong\": ". ($name="Herong") . "\n";?>

If you run this sample script, you should get:

Bitwise Operations: 0x00FF & 0x3210: 16 0x0001 | 0x0010: 17 0x0001 << 4: 16 0x0100 >> 4: 16

Incrementing/Decrementing Operations: $b = ++$a * 2: 11, 22 $b = $a++ *2: 11, 20

Arithmetic Operations: $a * $b: 36 $a * $b: 2.25 $a * $b: 1

Comparison Operations: $a > $b: 1 $a < $b:

Logical Operations: $a > $b && $b > $c: 1

String Operation: $greeting . $name: HelloHerong

Assignment Operation: $name="Herong": HerongPrecedence of Operations :This section provides the order of precedence for operations commonly used in PHP. Operations in a complex expression must be evaluated according to the order of operation precedence.

In the previous section, we learned that operations in a complex expression must be evaluated according to the order of operation precedence. The following table shows you the relative order of precedence for some commonly used operations:

Precedence Operations Notes16 (...) Operation group15 ++ -- Increment/decrement14 ~ - Unary negation13 ! Logical not12 * / % Multiplication, Division, ...11 + - Addition and Subtraction10 . String concatenation9 << >> Bitwise shift8 < > <= >= Comparisons 7 == != <> === !== Comparisons6 & Bitwise and5 ^ Bitwise xor4 | Bitwise or3 && And Logical and2 xor Logical xor

18 Naresh i Technologies

Page 19: Hypertext Preprocessor Demystified

PHP Course Material1 || Or Logical or0 = += -= ... Assignments

Remember that:

Operations with higher precedence values must be evaluated first. Operations of the same precedence value must be evaluated from left to right.

To show you some of reference rules mentioned above, I wrote the following PHP script, PrecedenceTest.php:

<?php # PrecedenceTest.php# print "\n Arithmetic, comparison and logical Operations:\n"; print " : ". (1 + 2 * 3 / 4) ."\n"; print " : ". (1 + 2 * 3 / 4 < 5 != FALSE) ."\n"; print " : ". (1 + 2 * 3 / 4 < 5 != FALSE || 6 < 7) ."\n";

print "\n Operations with groups:\n"; print " : ". (((1 + (2 * 3 / 4) < 5) != FALSE) || 6 < 7) ."\n"; print " : ". ((1 + (2 * 3 / 4) < 5) != (FALSE || 6 < 7)) ."\n";

print "\n Bitwise Operations:\n"; print " : " . (0x0001 | 0x00FF & 0x3210 << 4) . "\n"; print " : " . ((0x0001 | 0x00FF) & 0x3210 << 4) . "\n"; print " : " . (0x0001 | (0x00FF & 0x3210) << 4) . "\n"; print " : " . (0x0001 | 0x00FF & (0x3210 << 4)) . "\n";?>

If you run this sample script, you should get:

Arithmetic, comparison and logical Operations: : 2.5 : 1 : 1

Operations with groups: : 1 :

Bitwise Operations: : 1 : 0 : 257 : 1Data Type Automatic Conversion: This section provides rules on how operands are converted to data types required by the operation. PHP always finds a way to convert data from any type to any other type.

When the PHP evaluating an operation, it will automatically convert the data type of an operand if it does not match the data type required by the operator. Here are some basic data type automatic conversion rules:

19 Naresh i Technologies

Page 20: Hypertext Preprocessor Demystified

PHP Course Material

For logical operations, NULL, 0, or "" will be converted to FALSE. Any strings that can be parsed to 0 will also be converted to FALSE. Other values will be converted to TRUE.

For arithmetic operations, strings will be parsed into numeric values. TRUE will be converted to 1. FALSE will be converted to 0.

For comparison operations, if one operand is a numeric value, the other operand will be converted to a numeric value for a numeric comparison. If both operands are strings, it will be a string comparison.

For string operations, NULL will be converted to "". TRUE will be converted to "1". FALSE will be converted to "". Numeric values will be converted to decimal presentations.

To show you some of these rules, I wrote the following sample PHP script, TypeAutoConversion.php:

<?php # TypeAutoConversion.php# print "\n Logical operations:\n"; print " NULL==FALSE: "; var_dump(NULL==FALSE); print " 0==FALSE: "; var_dump(0==FALSE); print " \"\"==FALSE: "; var_dump(""==FALSE); print " \"0\"==FALSE: "; var_dump("0"==FALSE); print " \"0 - zero\"==TRUE: "; var_dump("0 - zero"==TRUE); print " \"zero\"==TRUE: "; var_dump("zero"==TRUE);

print "\n Logical operations:\n"; print " 3.14 * \"2.0\": "; var_dump(3.14 * "2.0"); print " 3.14 * \"2.0%\": "; var_dump(3.14 * "2.0%"); print " 3.14 * \"\$2.0\": "; var_dump(3.14 * "$2.0"); print " 3.14 * TRUE: "; var_dump(3.14 * TRUE); print " 3.14 * FALSE: "; var_dump(3.14 * FALSE);

print "\n Conparison operations:\n"; print " 3.14 < \"Hello\": "; var_dump(3.14 < "Hello"); print " 3.14 > \"Hello\": "; var_dump(3.14 > "Hello"); print " \"3.14\" > \"Hello\": "; var_dump("3.14" > "Hello");

print "\n String operations:\n"; print " \"Hello \" . TRUE: "; var_dump("Hello " . TRUE); print " \"Hello \" . FALSE: "; var_dump("Hello " . FALSE); print " \"Hello \" . NULL: "; var_dump("Hello " . NULL); print " \"Hello \" . 1.0/3.0: "; var_dump("Hello " . 1.0/3.0);?>

If you run this sample script, you should get:

Logical operations: NULL==FALSE: bool(true) 0==FALSE: bool(true) ""==FALSE: bool(true) "0"==FALSE: bool(true) "0 - zero"==TRUE: bool(true) "zero"==TRUE: bool(true)

20 Naresh i Technologies

Page 21: Hypertext Preprocessor Demystified

PHP Course Material Logical operations: 3.14 * "2.0": float(6.28) 3.14 * "2.0%": float(6.28) 3.14 * "$2.0": float(0) 3.14 * TRUE: float(3.14) 3.14 * FALSE: float(0)

Conparison operations: 3.14 < "Hello": bool(false) 3.14 > "Hello": bool(true) "3.14" > "Hello": bool(false)

String operations: "Hello " . TRUE: string(7) "Hello 1" "Hello " . FALSE: string(6) "Hello " "Hello " . NULL: string(6) "Hello " "Hello " . 1.0/3.0: string(20) "Hello 0.333333333333"

Conditional Statements - "if" and "switch"

This chapter provides tutorial examples and notes about conditional statements. Topics include 4 forms of 'if' statements, 'switch' statements, examples of controlling code executions with conditional statements.

"if" Statements

"if" Statement Examples

"switch" Statements

"switch" Statement Examples

Conclusion:

"if" must be followed by a condition. "elseif" is one word, no space.

"switch" must be followed by a test expression.

"default" clause will be executed, if no "case" clause matches the test expression.

Once a "case" is matched, all remaining statement blocks will be executed.

"break" statement should be used in "case" clauses to stop execution.

"if" StatementsThis section describes 4 forms of 'if' statements supported in PHP. The more complex form is 'if ... elseif ... else'.

here are 4 forms of "If" statements supported in PHP:

1. Single-statement "if":

21 Naresh i Technologies

Page 22: Hypertext Preprocessor Demystified

PHP Course Material if (condition) statement

where "condition" is a Boolean value, and "statement" specify another statement. The specified statement will be executed, if and only if the specified condition is evaluated to "TRUE".

2. Multi-statement "if":

if (condition) { statement; statement; ... }

The specified multi-statement block will be executed, if and only if the specified condition is evaluated to "TRUE".

3. "if ... else" Statement:

if (condition) { statement; statement; ... } else { statement; statement; ... }

Two statement blocks are specified. But only one statement block will be executed based on the value of the specified condition. If the specified condition is "TRUE", the first block will be executed. If the specified condition is "FALSE", the second block will be executed.

4. "if ... elseif" Statement:

if (condition_1) { statement; statement; ... } elseif (condition_2) { statement; statement; ... } elseif (condition_3) { statement; statement; ... ... } else { statement; statement; ... }"if" Statement Examples

22 Naresh i Technologies

Page 23: Hypertext Preprocessor Demystified

PHP Course Material

This section provides a tutorial example on how to use different types of 'if' statements to control code executions.

To help us understand how "if" statements work, I wrote the following the tutorial example PHP script:

<?php # IfStatements.php#

print("\n Single-statement \"if\":\n"); $isNewYear = TRUE; if (isNewYear) print(" Happy New Year!\n");

print("\n Multi-statement \"if\":\n"); $hasError = TRUE; if ($hasError) { print(" Open the log file.\n"); print(" Write an error message.\n"); print(" Close the log file.\n"); } print("\n \"if ... else\" statement:\n"); $login = "Herong"; if ($login == "Admin") { print(" Display the delete button.\n"); print(" Display the edit button.\n"); } else { print(" Display the view button.\n"); } print("\n \"if ... elseif\" statement:\n"); $dateInfo = getdate(); $wDay = $dateInfo["wday"]; $weekDay = $dateInfo["weekday"]; $openHours = "open"; if ($wDay == 0) { $openHours = "closed"; } elseif ($wDay >= 1 && $wDay <= 5) { $openHours = "open from 9:00am to 9:00pm"; } elseif ($wDay == 6 ) { $openHours = "open from 9:00am to 5:00pm"; } else { $openHours = "not at here"; } print(" Today is: $weekDay\n"); print(" The library is $openHours\n");?>

If you run this sample script, you should get:

Single-statement "if": Happy New Year!

Multi-statement "if": Open the log file. Write an error message.

23 Naresh i Technologies

Page 24: Hypertext Preprocessor Demystified

PHP Course Material Close the log file.

"if ... else" statement: Display the view button.

"if ... elseif" statement: Today is: Sunday The library is closed"switch" Statements

This section describes how 'switch' statements work. Execution will start at the 'case' clause whose expected value matches the test expression. Execution will continue with all remaining 'case' clauses.

"switch" statement is an alternative way of executing statements selectively based on certain conditions. Here is the syntax of "switch" statements:

switch (test_expression) { case expected_value_1: statement_block_1; break; case expected_value_2: statement_block_2; break; ... default: last_statement_block; }

where "test_expression" is an expression used to test against with expected values specified in "case" clauses, and "expected_value_*" are expected values.

The execution of a "switch" statement goes like this:

Each "case" clause will be visited sequentially from top to bottom. If the result of the test expression matches the expected value in a "case" clause, the

statement block in that clause will be executed.

One a statement block is executed, all remaining statement blocks will also be executed.

If no "case" clause is executed, the "default" clause will be executed.

To stop executing remaining statements, you can use the "break" statement.

"switch" Statement ExamplesThis section provides a tutorial example on how to use 'switch' statements to select one block of statements based on the equal condition of an expected value.

To help us understand how "switch" statements work, I wrote the following the tutorial example script:

<?php # SwitchStatements.php

24 Naresh i Technologies

Page 25: Hypertext Preprocessor Demystified

PHP Course Material# $dateInfo = getdate(); $wDay = $dateInfo["wday"]; $weekDay = $dateInfo["weekday"]; $openHours = "open";

print "\nLibrary Hours with \"switch\" statements:\n"; print " Today is: $weekDay\n"; switch ($weekDay) { case "Monday": case "Tuesday": case "Wednesday": case "Thursday": case "Friday": $openHours = "open from 9:00am to 9:00pm"; break; case "Saturday": $openHours = "open from 9:00am to 5:00pm"; break; case "Sunday": $openHours = "closed"; break; default: $openHours = "not at here"; } print " The library is $openHours\n";?>

If you run this sample script, you should get:

Library Hours with "switch" statements: Today is: Sunday The library is closedLoop Statements - "while", "for", and "do ... while"

This free PHP tutorial book is a collection of notes and sample codes written by the author while he was learning PHP himself. It can be used as a tutorial guide for beginners or a reference book for experienced developers. Topics include PHP, array, CGI, CLI, session, cookie, database, directory, file, HTTP, header lines, IIS, image, mail, MySQL, redirect, request, response, SMTP, SOAP, SOAP Extension, SQL, Unicode, WSDL.

"while" Statements

"while" Statement Examples

"for" Statements

"for" Statement Examples

"do ... while" Statements

"break" and "continue" Statements

25 Naresh i Technologies

Page 26: Hypertext Preprocessor Demystified

PHP Course Material

Conclusion:

"while" statement is the most commonly used loop statement in PHP. "for" statement is the most complex loop statement in PHP.

"do ... while" statement is just a variation of "while" statement.

"break" statement takes an optional parameter to break multiple level of loops.

"continue" statement takes an optional parameter to break and continue on the specified level of loops.

"while" StatementsThis section describes how 'while' statements works in PHP. One or more statements are repeatedly executed as long as the specified condition is true.

The "while" statement is the most commonly used loop statement in PHP. There are 3 forms of "while" statements supported in PHP:

1. Single-statement "while":

while (condition) statement;

2. Multi-statement "while":

while (condition) { statement; statement; ... }

3. Multi-statement "while ... endwhile":

while (condition): statement; statement; ... endwhile;

All forms of "while" statements are executed like this:

Step 1: Evaluate "condition" as a Boolean value.

Step 2: If "condition" returns TRUE, continue with Step 4.

Step 3: If "condition" returns "FALSE", terminate the loop.

Step 4: Execute the statement or statements enclosed in the loop.

Step 5: Continue with Step 1.

26 Naresh i Technologies

Page 27: Hypertext Preprocessor Demystified

PHP Course Material

Of course, you can use the "break" statement inside the loop to terminate the loop immediately.

"while" Statement ExamplesThis section provides a tutorial example on how to use 'while' statements to repeat execution of one or more statements while a specified condition is true.

To help us understand how "while" statements work, I wrote the following the tutorial example PHP script:

<?php # WhileStatements.php# $upperLimit = 20;# print("\n Single-statement \"while\":\n"); $sum = 0; $i = 0; while ($i<$upperLimit) $sum += ++$i; print(" Sum of 1 to 20: $sum\n");# print("\n Multi-statement \"while\":\n"); $i = 3; while ($i<$upperLimit) { $isPrime = true; $j = 2; while ($j<$i) { $isPrime = $i%$j > 0; if (!$isPrime) break; $j++; } if ($isPrime) print " $i is a prime number.\n"; $i++; }# print("\n Multi-statement \"while ... endwhile\":\n"); $i = 3; while ($i<$upperLimit): $isPrime = true; $j = 2; while ($j<$i): $isPrime = $i%$j > 0; if (!$isPrime) break; $j++; endwhile; if ($isPrime) print " $i is a prime number.\n"; $i++; endwhile;?>

If you run this sample script, you should get:

Single-statement "while": Sum of 1 to 20: 210

Multi-statement "while": 3 is a prime number. 5 is a prime number. 7 is a prime number.

27 Naresh i Technologies

Page 28: Hypertext Preprocessor Demystified

PHP Course Material 11 is a prime number. 13 is a prime number. 17 is a prime number. 19 is a prime number.

Multi-statement "while ... endwhile": 3 is a prime number. 5 is a prime number. 7 is a prime number. 11 is a prime number. 13 is a prime number. 17 is a prime number. 19 is a prime number."for" Statements

This section describes how 'for' statements works in PHP. One or more statements are repeatedly executed as long as the specified condition is true. 'for' statements has extra expressions for loop initialization and loop control update.

The "for" statement is the most complex loop statement in PHP. There are 4 forms of "while" statements supported in PHP:

1. Empty-statement "for":

for (initial_exepression; stop_condition; repeating_expression);

2. Single-statement "for":

for (initial_exepression; stop_condition; repeating_expression) statement;

3. Multi-statement "for":

for (initial_exepression; stop_condition; repeating_expression) { statement; statement; ... }

4. Multi-statement "for ... endfor":

for (initial_exepression; stop_condition; repeating_expression): statement; statement; ... endfor;

All forms of "for" statements are executed like this:

Step 1: "initial_exepression" is evaluated unconditionally. The "initial_exepression" is usually used to assign the initial value to a loop control variable, like $i=0.

28 Naresh i Technologies

Page 29: Hypertext Preprocessor Demystified

PHP Course Material

Step 2: Evaluate "stop_condition" as a Boolean value. The "stop_condition" is usually a comparison expression against the loop control variable, like $i<100.

Step 3: If "stop_condition" returns TRUE, continue with Step 5.

Step 4: If "stop_condition" returns "FALSE", terminate the loop.

Step 5: Execute the statement or statements enclosed in the loop.

Step 6: Evaluate "repeating_expression". The "repeating_expression" is usually an expression to increment the value of the loop control variable, like $i++.

Step 7: Continue with Step 2.

If you want to terminate the loop early, you can use the "break" statement inside the loop, which will terminate the loop immediately.

"for" Statement Examples

This section provides a tutorial example on how to use 'for' statements to repeatedly execute zero, one or more statements.

To help us understand how "for" statements work, I wrote the following the tutorial example script:

<?php # ForStatements.php# $upperLimit = 20;# print("\n No-statement \"for\":\n"); for ($sum = 0, $i = 0; $i<$upperLimit; $sum += ++$i); print(" Sum of 1 to 20: $sum\n");

print("\n Single-statement \"for\":\n"); for ($sum = 0, $i = 0; $i<$upperLimit; $i++) $sum += $i; print(" Sum of 0 to 19: $sum\n");# print("\n Multi-statement \"for\":\n"); for ($i=3; $i<$upperLimit; $i++) { $isPrime = true; for ($j=2; $j<=$i/2; $j++) { $isPrime = $i%$j > 0; if (!$isPrime) break; } if ($isPrime) print " $i is a prime number.\n"; }# print("\n Multi-statement \"for ... endfor\":\n"); for ($i=3; $i<$upperLimit; $i++): $isPrime = true; for ($j=2; $j<=$i/2; $j++): $isPrime = $i%$j > 0; if (!$isPrime) break;

29 Naresh i Technologies

Page 30: Hypertext Preprocessor Demystified

PHP Course Material endfor; if ($isPrime) print " $i is a prime number.\n"; endfor;?>

If you run this sample script, you should get:

No-statement "for": Sum of 1 to 20: 210

Single-statement "for": Sum of 0 to 19: 190

Multi-statement "for": 3 is a prime number. 5 is a prime number. 7 is a prime number. 11 is a prime number. 13 is a prime number. 17 is a prime number. 19 is a prime number.

Multi-statement "for ... endfor": 3 is a prime number. 5 is a prime number. 7 is a prime number. 11 is a prime number. 13 is a prime number. 17 is a prime number. 19 is a prime number.

"do ... while" Statements

This section describes how 'do ... while' statements works in PHP. One or more statements are repeatedly executed as long as the specified condition is true.

PHP also supports a variation of the "while" statement called "do ... while" statement. with 2 forms:

1. Single-statement "do ... while":

do statement while (condition);

2. Multi-statement "do ... while":

do { statement; statement; ... } while (condition);

All forms of "do ... while" statements are executed like this:

Step 1: Execute the statement or statements enclosed in the loop.

30 Naresh i Technologies

Page 31: Hypertext Preprocessor Demystified

PHP Course Material

Step 2: Evaluate "condition" as a Boolean value.

Step 3: If "condition" returns TRUE, continue with Step 1.

Step 4: If "condition" returns "FALSE", terminate the loop.

Of course, you can use the "break" statement inside the loop to terminate the loop immediately.

I will leave it to you to write some sample scripts for "do ... while" statements as exercises.

"break" and "continue" Statements

Function Declaration, Arguments, and Return Values

This chapter provides tutorial examples and notes about user-defined functions. Topics include defining function with arguments, calling functions in expressions, passing arguments by values or by references, variable-length argument list, providing default values for arguments, returning data by value or by reference.

What Is a Function?

"function" Statements - Defining Functions

Function Call Operations

Passing Arguments to Functions

Example of Passing Arguments by Values

Using Pass-by-Value Arguments for References

Example of Passing Arguments by References

Variable-Length Argument Lists

Providing Default Values to Argument Variables

Returning Values from Functions

Returning References from Functions

Conclusion:

A "function" statement defines a function with or without argument variables. A "return" statement in a function stops the execution of the function and returns a value to the

calling code.

31 Naresh i Technologies

Page 32: Hypertext Preprocessor Demystified

PHP Course Material

Function call option can provide more arguments than what are defined in the function.

"func_get_arg()", "func_get_args()", and "func_num_args()" allows us to access arguments without using argument variables.

An argument can be passed by references if you add "&" to the argument variable.

A function can return the reference of a variable, if you add "&" to the function name.

What Is a Function?

This section describes what is a function. A quick example is provided showing how to define and call a function.

What Is a Function? A function is a definition of a block of statements. The block of statements in a function will be executed only when the function is invoked. PHP provides a long list of built-in (predefined) functions. PHP supports user-defined functions - You define your own functions in PHP source code.

To learn how to use user-defined functions in PHP, we need to pay attentions in following areas:

1. How to define a function?

2. How to call a function to execute its statements?

3. How to pass input values into a function?

4. How to return a result from a function?

5. How to share variables with a function?

Here is a simple example script of defining a function, calling a function, passing data into a function, and returning result from a function:

function square($x) { $y = $x * $x; return $y; }

$radius = 2.0; $area = M_PI * square($radius); echo($area);

Notice that in this example script:

A function is defined with a "function" statement and named as "square". The function is called to execute as an operand in an expression in its name.

One input value is passed into the function at the calling time.

The result is returned using the "return" statement.

32 Naresh i Technologies

Page 33: Hypertext Preprocessor Demystified

PHP Course Material

"function" Statements - Defining Functions

This section describes the 'function' statement, which can be used to define your own function with a function name, argument list, function body.

A "function" statement defines a function with the following syntax:

function function_name($argument_1, $argument_2, ...) { statement_1; statement_2; ... }

where "function_name" is the name of the function, and "$argument_1, $argument_2, ..." is a list of variables acting as arguments of the function. "statement_1; statement_2; ..." is a block of statements that becomes the body of the function.

The "function_name" is the identifier of the function, it must follow PHP identifier naming conventions. The general rule is that don't use any special characters in function names.

The argument list is optional. If not needed, define your function with no arguments but keep the argument parentheses like this:

function function_name() { statement_1; statement_2; ... }

When a function is called in an expression, it will always return a value for the expression. The returning value can be controlled in 3 ways:

1. If the function body is executed to the last statement without hitting any "return" statement, the default value, NULL, will be returned to the calling expression.

2. If an empty "return" statement is reached during the function body execution, the remaining part of the function body will not be executed and the default value, NULL, will be returned to the calling expression.

3. If a "return" statement with an expression, like "return expression", is reached during the function body execution, the remaining part of the function body will not be executed and the resulting value of the specified expression will be returned to the calling expression.

To help us understand how to use "function" statements, I wrote the following the tutorial example PHP script:

<?php # FunctionStatements.php#

# Defining a real dummy function

33 Naresh i Technologies

Page 34: Hypertext Preprocessor Demystified

PHP Course Material function dummy() {} # Defining a function with no arguments function showMyFooter() { print("Copyright: Naresh IT\n"); print("Last Modified: 2003\n"); }

# Defining a function with arguments, but doing nothing function doNothing($a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k) {}

# Defining a function with arguments and doing something function showAnyFooter($author) { print("Copyright: $author\n"); print("Last Modified: 2003\n"); }

# Defining a function that returns a value function f2c($fahrenheit) { $celsius = ($fahrenheit - 32.0 ) / 1.8; return $celsius; }

# Defining a function that returns a random value function getValue() { $i = rand(1, 6); if ($i==1) { return TRUE; } elseif ($i==2) { return 9; } elseif ($i==3) { return 9.99; } elseif ($i==4) { return "Hello"; } elseif ($i==5) { return; } }?>

If you run this sample script, you will get no output, because this script only defines those functions. There is no expression that calls any of those functions

Function Call Operations

This section describes the function call operation, which triggers the execution of the called function with arguments provided on the call.

Calling a function in PHP is simple. All you have to do is to just use the function name with an argument list in any expression:

... function_name(argument_1, argument_2, ...) ...

When the execution reaches this function call operation, it will:

34 Naresh i Technologies

Page 35: Hypertext Preprocessor Demystified

PHP Course Material

Evaluate all calling arguments to values or variable references. Assign argument values and references to argument variables defined in the "function"

statement.

Start to execute the first statement of the function body.

Continue to execute the function body until the end of the function body or a "return" statement.

If a "return" statement is reached with a value specified, that value is returned as this function call operation.

If a "return" statement is reached with a no value specified, NULL is returned as this function call operation.

If no "return" statement is reached, NULL is returned as this function call operation.

Here is a simple example script showing us how to use function call operations:

<?php # FunctionCallOperations.php

# Defining a function that returns a value function f2c($fahrenheit) { $celsius = ($fahrenheit - 32.0 ) / 1.8; return $celsius; }

# Defining a function that returns NULL function showAnyFooter($author) { print(" Copyright: $author\n"); print(" Last Modified: 2003\n"); }

print("\n Function call as a standalone expression:\n"); showAnyFooter("Herong Yang");

print("\n Function call as an operand of another operation:\n"); if (f2c(20.0)<0.0) print(" It's cold here!\n");

print("\n Function call as an argument of another call:\n"); print(" How is the temperature? "); print(f2c(110.0));?>

If you run this sample script, you should get:

Function call as a standalone expression: Copyright: Naresh IT Last Modified: 2003

Function call as an operand of another operation: It's cold here!

Function call as an argument of another call: How is the temperature? 43.3333333333

35 Naresh i Technologies

Page 36: Hypertext Preprocessor Demystified

PHP Course Material

Passing Arguments to Functions

This section describes rules on how arguments can be passed from the calling code into the called function by value (the default) or by reference.

As shown in examples in previous sections, passing arguments to a function seems to be a simple job. But it may cause confusion if you don't following the rules. PHP has the following rules on passing arguments to function and subroutine procedures:

1. By default, a function argument is passed by value. In this case, the argument variable contains a copy of the data provided by the calling code.

2. But, a function argument can be passed by reference, if you define the argument variable as &$variable_name. In this case, the argument variable contains a reference of the original variable in the calling code. In another word, the argument variable is an alias of the original variable.

3. A pass-by-value argument variable is safer to use, because it will be assigned with a copy of the data from the calling code at the time of call. If the argument variable is re-assigned with a new data in the function, there will be no impact to the calling code.

4. A pass-by-reference argument variable offers an advantage and a risk. The advantage is that it can be used as an output channel for the function to send data back to the calling code. The risk is that if the argument variable is re-assigned with a new data in the function by a mistake, there will be some negative impact on the calling code.

5. An argument variable can be defined with a default value. Arguments with default values must be positioned at the end of the argument list.

6. If you want to use the default value of an argument variable, you can skip that argument in the function call operation.

7. Arguments passed in the function call be retrieved without using argument variables. You can use func_num_args(), func_get_arg(), and func_get_args() functions to access arguments. This feature can be used to support variable-length argument lists.

8. If an array is passed by value, a copy of the original array will be passed to the function. If an array is passed by reference, the function and the calling code is sharing the same array.

9. If a reference of a variable is passed by value, a copy of the reference will be passed to the function. But the copy and the reference are both referring to the same original variable. So passing a reference by value is equivalent to passing a variable by reference.

Example of Passing Arguments by Values

This section provides a tutorial example on how to use pass-by-value arguments, which allows the function to re-assign new values to original variables in the calling code.

36 Naresh i Technologies

Page 37: Hypertext Preprocessor Demystified

PHP Course Material

As we learned from the previous section, PHP functions use pass-by-value arguments by default. If an argument is defined as an pass-by-value argument, the calling operation can provide an expression for this argument. That expression will be assigned to this argument variable when function is called. For example, if we have "function f($var) {...}" defined, "f(exp)" is equivalent to "{$var=exp; ...}".

To see how passing arguments by values works, I wrote this tutorial example, PassByValue.php:

<?php # PassByValue.php# function swap($left, $right) { $temp = $left; $left = $right; $right = $temp; print(" Swapped in function: ".getString($left, $right)."\n");}

print("\n 1. Passing two literals:\n"); print(" Before call: ". getString("Apple", "Orange") ."\n"); swap("Apple", "Orange");

print("\n 2. Passing two variables:\n"); $x = "Dog"; $y = "Cat"; print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

print("\n 3. Passing two arrays:\n"); $x = array("Mon", "Tue"); $y = array("Jan", "Feb"); print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

print("\n 4. Passing two objects:\n"); $x = new DateTime("2005-01-01"); $y = new DateTime("2006-01-01"); print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

function getString($left, $right) { if (is_scalar($left)) { return "$left | $right"; } elseif (is_array($left)) { return "($left[0], $left[1]...) | ($right[0], $right[1]...)"; } elseif (is_object($left) && get_class($left)=="DateTime") { return $left->format("Y")." | ".$right->format("Y"); } else { return NULL; }}?>

If you run this sample script, you should get:

1. Passing two literals: Before call: Apple | Orange

37 Naresh i Technologies

Page 38: Hypertext Preprocessor Demystified

PHP Course Material Swapped in function: Orange | Apple

2. Passing two variables: Before call: Dog | Cat Swapped in function: Cat | Dog After call: Dog | Cat

3. Passing two arrays: Before call: (Mon, Tue...) | (Jan, Feb...) Swapped in function: (Jan, Feb...) | (Mon, Tue...) After call: (Mon, Tue...) | (Jan, Feb...)

4. Passing two objects: Before call: 2005 | 2006 Swapped in function: 2006 | 2005 After call: 2005 | 2006

The output confirms that:

My swap() function is very powerful. It swapped anything received from the argument list.

Pass-by-value arguments can be used for scalars, arrays and objects.

Pass-by-value arguments are safe to use. The swap() function has no impact on calling code.

Using Pass-by-Value Arguments for References

This section provides a tutorial example on how to references on pass-by-value arguments. Using a reference expression as a pass-by-value argument allows you to modify the original variable in the calling code.

In the previous section, we tested on passing regular variables to functions using the pass-by-value mode. But what will happen if we pass references to functions using the pass-by-value mode? To find out the answer, I wrote this tutorial example script:

<?php # PassByValueWithReference.php

# function swap($left, $right) { $temp = $left; $left = $right; $right = $temp; print(" Swapped in function: ".getString($left, $right)."\n");}

print("\n 1. Passing two variables:\n"); $x = "Dog"; $y = "Cat"; print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

print("\n 2. Passing two references:\n"); $y = "Bob"; $y = "Tom";

38 Naresh i Technologies

Page 39: Hypertext Preprocessor Demystified

PHP Course Material print(" Before call: ". getString($x, $y) ."\n"); swap(&$x, &$y); print(" After call: ". getString($x, $y) ."\n");

print("\n 3. Passing two references in variables:\n"); $a = "One"; $b = "Two"; $x = &$a; $y = &$b; print(" Before call: ". getString($a, $b) ."\n"); print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($a, $b) ."\n"); print(" After call: ". getString($x, $y) ."\n");

function getString($left, $right) { if (is_scalar($left)) { return "$left | $right"; } else { return NULL; }}?>

If you run this tutorial example, you should get:

1. Passing two variables: Before call: Dog | Cat Swapped in function: Cat | Dog After call: Dog | Cat

2. Passing two references: Before call: Dog | Tom Swapped in function: Tom | Dog After call: Tom | Dog

3. Passing two references in variables: Before call: One | Two Before call: One | Two Swapped in function: Two | One After call: One | Two After call: One | Two

Do you see anything interesting in the output?

There is nothing strange in test 1. Pass-by-value on regular variables left no changes on original variables.

But in test 2, pass-by-value on references caused original variables to be swapped. I think I know why. The swap() function received copies of references, &$x and &$y, swapping references actually swapped the original variables, $x and $y.

But in test 3, pass-by-value on references stored in variables caused original variables un-touched. Initially, I thought test 3 should behave like test 2. But by following the pass-by-value logic, I think I know why it behaves differently. In the call, swap($x, $y), copies of values of $x and $y are passed. Since $x and $y are reference variables, values of $x and $y are values of $a

39 Naresh i Technologies

Page 40: Hypertext Preprocessor Demystified

PHP Course Material

and $b, "One" and "Two". So copies of "One" and "Two" are passed into the function. Of course, swapping these copies will have no impact on original values of $a and $b (or $x and $y, since they are aliases of $a and $b).

Conclusion, If you call a function with a reference expression as a pass-by-value argument, you are equivalently using this argument as a pass-by-reference argument. Changes on this argument inside the function will be applied to the original variable in the calling code.

Example of Passing Arguments by References

This chapter provides tutorial examples and notes about user-defined functions. Topics include defining function with arguments, calling functions in expressions, passing arguments by values or by references, variable-length argument list, providing default values for arguments, returning data by value or by reference.

As we learned from the previous section, PHP supports pass-by-reference arguments if they are defined with a & prefix on the argument variables. If an argument is defined as an pass-by-reference argument, the calling operation can provide a variable, for this argument. The reference of that variable will be taken and assigned to this argument variable when function is called. For example, if we have "function f(&$var) {...}" defined, "f($arg)" is equivalent to "{$var=&$arg; ...}".

To see how passing arguments by references works, I wrote this tutorial example, PassByReference.php:

<?php # PassByReference.php

# function swap(&$left, &$right) { $temp = $left; $left = $right; $right = $temp; print(" Swapped in function: ".getString($left, $right)."\n");}

# print("\n 1. Passing two literals:\n");# print(" Before call: ". getString("Apple", "Orange") ."\n");# swap("Apple", "Orange");

print("\n 2. Passing two variables:\n"); $x = "Dog"; $y = "Cat"; print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

print("\n 3. Passing two arrays:\n"); $x = array("Mon", "Tue"); $y = array("Jan", "Feb"); print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

print("\n 4. Passing two objects:\n"); $x = new DateTime("2005-01-01"); $y = new DateTime("2006-01-01");

40 Naresh i Technologies

Page 41: Hypertext Preprocessor Demystified

PHP Course Material print(" Before call: ". getString($x, $y) ."\n"); swap($x, $y); print(" After call: ". getString($x, $y) ."\n");

function getString($left, $right) { if (is_scalar($left)) { return "$left | $right"; } elseif (is_array($left)) { return "($left[0], $left[1]...) | ($right[0], $right[1]...)"; } elseif (is_object($left) && get_class($left)=="DateTime") { return $left->format("Y")." | ".$right->format("Y"); } else { return NULL; }}?>

If you run this sample script, you should get:

2. Passing two variables: Before call: Dog | Cat Swapped in function: Cat | Dog After call: Cat | Dog

3. Passing two arrays: Before call: (Mon, Tue...) | (Jan, Feb...) Swapped in function: (Jan, Feb...) | (Mon, Tue...) After call: (Jan, Feb...) | (Mon, Tue...)

4. Passing two objects: Before call: 2005 | 2006 Swapped in function: 2006 | 2005 After call: 2006 | 2005

The output confirms that:

My swap() function is very powerful. It swapped references of any types of variables received from the argument list.

Pass-by-reference arguments can be used for scalar, array and object variables.

Pass-by-reference arguments allow functions to reassign data values to original variables in the calling code.

Pass-by-reference arguments can only take variables from the calling code. If you open test #1 in my sample script, the execution will fail with a message, "Fatal error: Only variables can be passed by reference".

Exercise: Try to test pass-by-reference arguments with:

swap("Apple", "Orange"); swap(array("Mon", "Tue"), array("Jan", "Feb")); swap(new DateTime("2005-01-01"), new DateTime("2006-01-01")); swap(&$a, &$b);

41 Naresh i Technologies

Page 42: Hypertext Preprocessor Demystified

PHP Course Material

Variable-Length Argument Lists

This section provides a tutorial example on how to access arguments in a function without using argument variables and how to pass arguments more than what are defined in the function statement.

As I mentioned earlier, PHP also allows you to access arguments provided in the function call operation without using argument variables. Here is how:

1. func_get_arg(position) - It returns the value of the specified argument provided in the function call operation. "position" is the position index of the specified argument. The position index of the first argument is 0. For example, if "func_get_arg(2)" is used in a function, it will return the value of the 3rd argument.

2. func_num_args() - It returns the total number of arguments provided in the function call operation. For example, if "func_num_args()" returns 1, you know that there is only 1 argument provided by calling code.

3. func_get_args() - It creats and returns an array which contains values of all arguments provided in the function call operation. For example, if "$args = func_get_args()" is used in a function, $args will be array containing all arguments.

With all these 3 functions, we say that PHP supports variable-length argument lists with some basic rules:

The function call can provide more arguments than the number of argument variables defined in the function statement.

You can pass arguments to a function that has no argument variable defined.

To help us understand how use variable-length argument list feature, I wrote this tutorial example:

<?php # ArgumentList.php

# function f2c($fahrenheit) { $celsius = (func_get_arg(0) - 32.0) / 1.8; return $celsius; }

print("\n Calling a function that uses func_get_arg():\n"); if (f2c(20.0)<0.0) print(" It's cold here!\n"); function myMax() { $max = NULL; if (func_num_args()>0) $max = func_get_arg(0); for ($i=1; $i<func_num_args(); $i++) { if ($max < func_get_arg($i)) $max = func_get_arg($i); } return $max; }

42 Naresh i Technologies

Page 43: Hypertext Preprocessor Demystified

PHP Course Material

print("\n Calling a function that uses func_num_args():\n"); print(" ".myMax()."\n"); print(" ".myMax(3)."\n"); print(" ".myMax(3, 1, 4)."\n"); print(" ".myMax(3, 1, 4, 1, 5, 9, 2, 6, 5)."\n");

function myMin() { $list = func_get_args(); $min = NULL; if (count($list)>0) $min = $list[0]; for ($i=1; $i<count($list); $i++) { if ($min > $list[$i]) $min = $list[$i]; } return $min; }

print("\n Calling a function that uses func_get_args():\n"); print(" ".myMin()."\n"); print(" ".myMin(5)."\n"); print(" ".myMin(5, 6, 2)."\n"); print(" ".myMin(5, 6, 2, 9, 5, 1, 4, 1, 3)."\n");?>

If you run this sample script, you should get:

Calling a function that uses func_get_arg(): It's cold here!

Calling a function that uses func_num_args():

3 4 9

Calling a function that uses func_get_args():

5 2 1

Providing Default Values to Argument Variables

This section provides a tutorial example on how to provide default values to argument variables.

PHP also allows us to provide default values to argument variables using the following syntax on the function definition statement:

function function_name($arg_1, $arg_2, ... $arg_n=exp) { ... }

where argument variable, $arg_n, has been assigned with a default value, evaluated from the specified expression, "exp".

43 Naresh i Technologies

Page 44: Hypertext Preprocessor Demystified

PHP Course Material

Assigning default values to argument variables has several simple rules:

Only scalar values and arrays can be used as argument variable default values. Objects can not be used as argument variable default values.

If argument variable has default value defined, the function call operation use that default value by skipping that argument.

To help us understand how use argument variable default values, I wrote this tutorial example:

<?php # ArgumentDefaultValues.php# function hello($name="Herong") { print(" Hello " . $name . "!\n"); }

print("\n Argument with a scalar default value:\n"); hello(); hello("World"); hello(NULL);

function showList($list=array("Apple", "Orange")) { print(" List: " . $list[0] . ", " . $list[1] . "\n"); }

print("\n Argument with an array default value:\n"); showList(); showList(array("Cat", "Dog"));

# function showDate($object=new DateTime()) {# print(" Year: " . $object->format("Y"));# }?>

If you run this sample script, you should get:

Argument with a scalar default value: Hello Herong! Hello World! Hello !

Argument with an array default value: List: Apple, Orange List: Cat, Dog

If you open last 3 commented-out statements, you will get an execution error: "Parse error: syntax error, unexpected T_NEW in C:\herong\php\ArgumentDefaultValues.php on line 21",

Returning Values from Functions

44 Naresh i Technologies

Page 45: Hypertext Preprocessor Demystified

PHP Course Material

This section provides a tutorial example on how to return values from functions - using the 'return' statement.

PHP supports function return values with some basic rules:

If a function is executed without reaching a return statement, it will return NULL. A function can use a "return" statement to return all 8 types of values: boolean, integer,

float, string, array, object, resource, null.

If you use a "return" statement to return a variable, a copy of the data in the variable will be returned to the calling code.

To help us understand these rules, I wrote this tutorial example:

<?php # FunctionReturnValues.php

# function returnType($arg) { if (is_null($arg)) return "NULL"; elseif (is_bool($arg)) return "BOOLEAN"; elseif (is_int($arg)) return "INTEGER"; elseif (is_float($arg)) return "FLOAT"; elseif (is_string($arg)) return "STRING"; elseif (is_array($arg)) return "ARRAY"; elseif (is_object($arg)) return "OBJECT"; elseif (is_resource($arg)) return "RESOURCE"; else return "UNKNOWN"; } print("\n Returning a scalar value:\n"); print(" 1: " . returnType(1) . "\n"); print(" 1.0: " . returnType(1.0) . "\n"); print(" array(1.0): " . returnType(array(1.0)) . "\n");

function createArray() { return func_get_args(); } print("\n Returning an array value:\n"); print(" createArray(): ".returnType(createArray(3,6,9))."\n");

function currentDate() { return new DateTime(); } print("\n Returning an object value:\n"); print(" currentDate(): " . returnType(currentDate()) . "\n");

function noReturn() { } print("\n Function without return statements:\n"); print(" noReturn(): " . returnType(noReturn(3,1,4)) . "\n");?>

If you run this sample script, you should get:

Returning a scalar value: 1: INTEGER

45 Naresh i Technologies

Page 46: Hypertext Preprocessor Demystified

PHP Course Material 1.0: FLOAT array(1.0): ARRAY

Returning an array value: createArray(): ARRAY

Returning an object value: currentDate(): OBJECT

Function without return statements: noReturn(): NULL

Returning References from Functions

This section provides a tutorial example on how to return references from functions - prefix the function name with & in both definition and call statements.

PHP supports function return references using this syntax:

function &function_name() { ... return $var_1; } $var_2 = &function_name();

When you use a function to return a reference, you need follow these rules:

To declare a function that returns a reference, the function name must be prefixed with '&' in the function definition statement.

If a function is declared to return a reference, it should use the 'return' statement to return a variable.

To call a function that returns a reference, the function name must be prefixed with '&' in the function call operation.

The returning reference from a function should be assigned to another variable.

To help us understand these rules, I wrote this tutorial example:

<?php # FunctionReturnReferences.php

# function pvrv($arg) { $arg = "Two"; return $arg; } print("\n 1. Pass by value and return by value:\n"); $x = "One"; $y = pvrv($x); $y = "Three"; print(" x: $x\n"); print(" y: $y\n");

46 Naresh i Technologies

Page 47: Hypertext Preprocessor Demystified

PHP Course Material function prrv(&$arg) { $arg = "Two"; return $arg; } print("\n 2. Pass by reference and return by value:\n"); $x = "One"; $y = prrv($x); $y = "Three"; print(" x: $x\n"); print(" y: $y\n");

function &pvrr($arg) { $arg = "Two"; return $arg; } print("\n 3. Pass by value and return by reference:\n"); $x = "One"; $y = &pvrr($x); $y = "Three"; print(" x: $x\n"); print(" y: $y\n");

function &prrr(&$arg) { $arg = "Two"; return $arg; } print("\n 4. Pass by reference and return by reference:\n"); $x = "One"; $y = &prrr($x); $y = "Three"; print(" x: $x\n"); print(" y: $y\n");?>

If you run this sample script, you should get:

1. Pass by value and return by value: x: One y: Three

2. Pass by reference and return by value: x: Two y: Three

3.Pass by value and return by reference: x: One y: Three

4. Pass by reference and return by reference: x: Three y: Three

Test 4. proves that the main code received the reference from prrr() correctly. $y is assigned with the reference of $arg. But $arg is an alias of $x, because $x is passed as a reference. So $y becomes an alias of $x.

47 Naresh i Technologies

Page 48: Hypertext Preprocessor Demystified

PHP Course Material

Arrays - Ordered Maps

This chapter provides tutorial examples and notes about arrays. Topics include creating arrays with the array constructor, using integer keys or string keys in arrays, accessing values through keys, array related built-in functions.

What Is an Array?

Creating Arrays - Examples

Array Related Built-in Functions

Conclusion:

An array can be created with the array constructor, array(). A pair of key and value can be specified as key=>value as an argument in the constructor.

A value stored in an array can be accessed as $array_variable["key"].

An array can be used as a stack through array_push() and array_pop() functions.

"foreach () {}" statement can be used to loop through all values in an array.

What Is an Array?

This section describes what is an array - an ordered pairs of keys and values. If sequential integer keys are used, an array is a simple indexed list. If string keys are used, an array is a map

What Is an Array? An array is a data type that represents an ordered pairs of keys and values. Arrays in PHP are different than arrays in most of other languages. Basic rules for PHP's arrays are:

1. An array can be constructed by the array constructor, like:

$myArray = array(k1=>v1, k2=>v2, ..., kn=>vn);

where k1, k2, ..., and kn are keys of integer type or string type. v1, v2, ..., and vn are values of any data types.

2. The value of a given key in an array can be expressed by the array variable followed by the key in square brackets, like:

print $myArray[kn];

3. The value of a given key in an array can be modified by an assignment statement, like:

$myArray[kn] = new_value.

4. A new pair of key and value can be added to an array by an assignment statement, like:

48 Naresh i Technologies

Page 49: Hypertext Preprocessor Demystified

PHP Course Material $myArray[kx] = vx

5. If a string key represents an integer, it will be used as an integer key. So $myArray['7'] is the same as $myArray[7].

6. If the key is missing in an array assignment or an array constructor, an integer key of 0, or the highest integer key plus 1, will be provided. So $myArray[] = "Last" assigns "Last" to a new integer key.

7. An empty string is also a valid string key, like:

$myArray[''] = vy;

8. A pair of key and value can be removed by using the unset() function, like:

unset($myArray[kn]);

9. Pairs of keys and values are ordered in an array like a queue. New pairs are always added at the end of the array.

Creating Arrays – Examples

This section provides a tutorial example on how to create arrays in different ways.

Here is a tutorial example PHP script to show you some of array rules described in the previous section:

<?php # ArrayTest.php# print "\nLibrary hours:\n"; $libraryHours = array( 'Monday - Friday'=>'09:00 - 21:00', 'Saturday'=>'09:00 - 17:00', 'Sunday'=>'closed'); print_r($libraryHours);# print "\nPrime numbers:\n"; $primeNumbers = array(3, 5, 7, 11); $primeNumbers[] = 13; print_r($primeNumbers);# print "\nFruits:\n"; $fruits[] = 'Apple'; $fruits[] = 'Orange'; $fruits[''] = 'Peach'; $fruits[''] = 'Banana'; $fruits['G'] = 'Grape'; $fruits['7'] = 'Pear'; $fruits[] = 'Fig'; print_r($fruits);# print "\nFruits array modified:\n"; unset($fruits[1]);

49 Naresh i Technologies

Page 50: Hypertext Preprocessor Demystified

PHP Course Material $fruits[1] = 'Orange'; print_r($fruits);?>

If you run this sample script, you should get:

Library hours:Array( [Monday - Friday] => 09:00 - 21:00 [Saturday] => 09:00 - 17:00 [Sunday] => closed)

Prime numbers:Array( [0] => 3 [1] => 5 [2] => 7 [3] => 11 [4] => 13)

Fruits:Array( [0] => Apple [1] => Orange [] => Banana [G] => Grape [7] => Pear [8] => Fig)

Fruits array modified:Array( [0] => Apple [] => Banana [G] => Grape [7] => Pear [8] => Fig [1] => Orange)

The behavior of the $fruits array is very interesting. Review it carefully

Array Related Built-in Functions:This section provides a tutorial example on how to create arrays in different ways.

PHP offers a number of interesting built-in functions to work with arrays:

array_combine() - Combines two arrays into a new array with the first array as keys and the second as values.

50 Naresh i Technologies

Page 51: Hypertext Preprocessor Demystified

PHP Course Material

array_count_values() - Counts the frequencies of values in an array and returns them as an array.

array_key_exists() - Searches for a key in an array.

array_keys() - Returns an array with all keys of an array.

array_search() - Searches for a value in an array.

array_values() - Returns an array with all values of an array.

array_push() - Treats the array like a stack and pushes extra values to the end of the stack.

array_pop() - Treats the array like a stack and pops the last value from the stack.

ksort() - Sorts an array by keys.

sort() - Sorts an array by values.

PHP also offers special loop statements to iterate over arrays:

foreach($myArray as $value) {}foreach($myArray as $key=>$value) {}

Here is a simple script with a "foreach" statement:

<?php # ArrayLoop.php# # print "\nLibrary hours:\n"; $libraryHours = array( 'Monday - Friday'=>'09:00 - 21:00', 'Saturday'=>'09:00 - 17:00', 'Sunday'=>'closed'); foreach($libraryHours as $day=>$hours) { print " $day: $hours\n"; }?>

Here is the output:

Library hours: Monday - Friday: 09:00 - 21:00 Saturday: 09:00 - 17:00 Sunday: closed

Configuring and Sending out Emails

This chapter provides tutorial examples and notes about sending emails. Topics include setting up Windows IIS as a SMTP mail server, configuring PHP to use SMTP servers, write PHP scripts to send out emails.

Using Local Windows System as a Mail Server

51 Naresh i Technologies

Page 52: Hypertext Preprocessor Demystified

PHP Course Material

Sending Out Emails from PHP Scripts

Conclusion:

IIS (Internet Information Services) can be used as a local SMTP mail server. PHP can be configured to use SMTP servers.

The built-in mail() function can be used to send out emails.

Using Local Windows System as a Mail Server

This section provides a tutorial example on how to setup your local Windows system to use IIS (Internet Information Services) as a SMTP mail server.

PHP provides us a nice built-in function, mail(), that allows us to send emails over the Internet. But it requires a SMTP mail server that the mail() function can communicate with.

If you don't have a service provider who provides you the SMTP mail service, you can set up your local system as a SMTP mail server to test mail().

If you are running a Linux/Unix system, setting up a mail server is easy. Just run sendmail as a daemon.

If you are running a Windows system, setting up a mail server is a little bit harder. But if IIS (Internet Information Services) is running on your system, it also provides SMTP services. Here is how you can check this:

1. Go to Control Panel / Services, and make sure Simple Mail Transfer Protocol (SMTP) is running.

2. Open a command window, and run the following command:

>telnet localhost 25

220 localhost Microsoft ESMTP MAIL Service, Version: 6.0.2600.1106...help214-This server supports the following commands:214 HELO EHLO STARTTLS RCPT DATA RSET MAIL QUIT HELP AUTH BDAT VRFYquit221 2.0.0 localhost Service closing transmission channel

If you got similar outputs as above, your IIS is running as SMTP mail server correctly.

Sending Out Emails from PHP Scripts

This section provides a tutorial example on how to configure the PHP engine to use the local SMTP mail server and write a PHP script to send an email.

52 Naresh i Technologies

Page 53: Hypertext Preprocessor Demystified

PHP Course Material

Once we have a SMTP mail server ready to use, we are ready to try to send out emails from PHP scripts.

First you need to verify the PHP initialization file, \php\php.ini, to make sure that the following settings are configured correctly:

SMTP = localhostsmtp_port = 25

Then write and run the following PHP script, MailTest.php:

<?php # MailTest.php

# mail("nobody","Testing","This is a test.","From: herong@localhost");?>

Go check to see the email is delivered or not in a command window:

>dir \inetpub\mailroot\drop

... d9765b3001c54a1200000001.eml

>type \inetpub\mailroot\drop\d9765b3001c54a1200000001.eml

x-sender: herong@localhostx-receiver: nobody@localhostReceived: from localhost ([127.0.0.1]) by localhost with Microsoft...Subject: TestingTo: nobodyFrom: herong@localhostReturn-Path: herong@localhost......

This is a test.

If you can follow me to here, you have successfully used the PHP engine to send out an email from a PHP sample script.

Retrieving Information from HTTP Requests

This chapter provides tutorial examples and notes about HTTP request. Topics include retrieving information from $_GET, $_POST, $_COOKIE, $_REQUEST, $_SERVER; promoting and registering $_REQUEST keys and values as global variables.

Predefined Variables Related to HTTP Requests

Operating System Information in $_SERVER

Web Server Information in $_SERVER

Information in $_GET and $_REQUEST

53 Naresh i Technologies

Page 54: Hypertext Preprocessor Demystified

PHP Course Material

Registering $_REQUEST Keys as Global Variables

Conclusion:

$_GET contains information submitted with the GET method. $_POST contains information submitted with the POST method.

$_COOKIE contains information stored as cookies.

$_REQUEST is the sum of $_GET, $_POST, and $_COOKIE.

$_SERVER contains information from the HTTP request, the Web server and the operating system.

Predefined Variables Related to HTTP Requests

This section describes predefined variables, $_GET, $_POST, $_COOKIE, $_REQUEST, and $_SERVER, that contains information included in the HTTP request received by the PHP engine from the Web server.

When the PHP engine is used on a Web server to handle a HTTP request, it converts information submitted in the HTTP request as predefined variables and pass them to PHP script.

1. $_GET - Associate array of HTTP request information submitted with the GET method. By default, all browsers submit HTTP requests with the GET method. Input information collected from Web page forms will be organized into pairs of names and values, which will be attached to the end of the URL in the first line of the HTTP request.

When the PHP engine receives a HTTP request, it will take those pairs of names and values from the end of the request URL and store them in the $_GET array as keys and values.

2. $_POST - Associate array of HTTP request information submitted with the POST method. If a Web page uses the POST method to submit input information collected from its form. The browser will organize input into names and values and attach them as the HTTP request body.

When the PHP engine receives a HTTP request, it will take those pairs of names and values from the request body and store them in the $_POST array as keys and values.

3. $_COOKIE - Associate array of submitted as cookies in the HTTP request. If a browser has cookies received previously from a Web server, it will automatically attach them in the next HTTP request to the same Web server.

When the PHP engine receives a HTTP request, it will take cookie names and cookie values from the request and store them in the $_POST array as keys and values.

4. $_REQUEST - Associate array of all elements from $_GET, $_POST, and $_COOKIE. To help you to get HTTP request input information in a single place, the PHP engine automatically combines all keys and values from $_GET, $_POST, and $_COOKIE into $_REQUEST.

54 Naresh i Technologies

Page 55: Hypertext Preprocessor Demystified

PHP Course Material

5. $_SERVER - Associate array of information from the Web server and the HTTP request. When the PHP engine receives a HTTP request, it will take other information included in the request and store it in the $_SERVER array as keys and values. For example, the following keys and values represent information received from the HTTP request:

CONTENT_LENGTH = 0 HTTP_ACCEPT = */* HTTP_ACCEPT_LANGUAGE = en-us HTTP_ACCEPT_ENCODING = gzip, deflate HTTP_CONNECTION = Keep-Alive OS = Windows_NT ORIG_PATH_INFO = /HttpRequestDetails.php ORIG_SCRIPT_NAME = /HttpRequestDetails.php REQUEST_METHOD = GET ......

The PHP engine also gathers additional information from the Web server and store it in the $_SERVER array as keys and values. For example, the following keys and values represent information received from the Web server:

GATEWAY_INTERFACE = CGI/1.1 NUMBER_OF_PROCESSORS = 1 ProgramFiles = C:\Program Files SERVER_NAME = localhost SERVER_PORT = 80 SERVER_PORT_SECURE = 0 DOCUMENT_ROOT = c:/inetpub/wwwroot SCRIPT_FILENAME = c:\inetpub\wwwroot\HttpRequestDetails.php ......

The PHP engine also gathers additional information from the operating system where the PHP engine is running and store it in the $_SERVER array as keys and values. For example, the following keys and values represent information received from the operating system:

CLIENTNAME = Console ComSpec = C:\WINDOWS\system32\cmd.exe HOMEDRIVE = C: PHPRC = c:php PROCESSOR_ARCHITECTURE = x86 SystemDrive = C: SystemRoot = C:\WINDOWS PHP_SELF = HttpRequestDetails.php

Operating System Information in $_SERVER

This section provides a tutorial example on how to dump operating system information stored in the $_SERVER array.

To help us understand how predefined variables, $_GET, $_POST, $_COOKIE, $_REQUEST, and $_SERVER, work, I wrote the following tutorial example script:

<?php # HttpRequestDetails.php

55 Naresh i Technologies

Page 56: Hypertext Preprocessor Demystified

PHP Course Material# print "<pre>\n"; print "\nContents of \$_GET:\n"; foreach ($_GET as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_POST:\n"; foreach ($_POST as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_COOKIE:\n"; foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_REQUEST:\n"; foreach ($_REQUEST as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_SERVER:\n"; foreach ($_SERVER as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>

If you run this example script standalone without using any Web server, you should get:

<pre>

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

Contents of $_REQUEST:

Contents of $_SERVER: CLIENTNAME = Console ComSpec = C:\WINDOWS\system32\cmd.exe HOMEDRIVE = C: PHPRC = c:\php PROCESSOR_ARCHITECTURE = x86 SESSIONNAME = Console SystemDrive = C: SystemRoot = C:\WINDOWS PHP_SELF = HttpRequestDetails.php SCRIPT_NAME = HttpRequestDetails.php SCRIPT_FILENAME = HttpRequestDetails.php PATH_TRANSLATED = HttpRequestDetails.php DOCUMENT_ROOT = argv = Array argc = 1 ......

56 Naresh i Technologies

Page 57: Hypertext Preprocessor Demystified

PHP Course Material</pre>

Note that $_GET, $_POST, $_COOKIE, and $_REQUEST are all empty, because we executed the script without any HTTP request. $_SERVER contains only information gathered from the operating system.

Web Server Information in $_SERVER

This section provides a tutorial example on how to dump Web server information stored in the $_SERVER array.

Now, let's run HttpRequestDetails.php on the local IIS Web server. First copy HttpRequestDetails.php to \inetpub\wwwroot, then run Internet Explorer (IE) with http://localhost/HttpRequestDetails.php. You should get:

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

Contents of $_REQUEST:

Contents of $_SERVER: CONTENT_LENGTH = 0 GATEWAY_INTERFACE = CGI/1.1 HTTP_ACCEPT = */* HTTP_ACCEPT_LANGUAGE = en-us HTTP_CONNECTION = Keep-Alive HTTP_HOST = localhost HTTP_ACCEPT_ENCODING = gzip, deflate HTTPS = off INSTANCE_ID = 1 LOCAL_ADDR = 127.0.0.1 NUMBER_OF_PROCESSORS = 1 OS = Windows_NT ProgramFiles = C:\Program Files REMOTE_ADDR = 127.0.0.1 REMOTE_HOST = 127.0.0.1 REQUEST_METHOD = GET SCRIPT_NAME = /HttpRequestDetails.php SERVER_NAME = localhost SERVER_PORT = 80 SERVER_PORT_SECURE = 0 SERVER_PROTOCOL = HTTP/1.1 SystemDrive = C: ORIG_PATH_INFO = /HttpRequestDetails.php ORIG_SCRIPT_NAME = /HttpRequestDetails.php DOCUMENT_ROOT = c:/inetpub/wwwroot SCRIPT_FILENAME = c:\inetpub\wwwroot\HttpRequestDetails.php PHP_SELF = /HttpRequestDetails.php ......

57 Naresh i Technologies

Page 58: Hypertext Preprocessor Demystified

PHP Course Material

Note that $_GET, $_POST, $_COOKIE, and $_REQUEST are still all empty, because HTTP request contains no information submitted using the GET or POST method. And there is no cookies in the HTTP request.

However, other information contained in the HTTP request and gathered from the Web server is stored in the $_SERVER array now. For example, "DOCUMENT_ROOT = c:/inetpub/wwwroot" is piece of information from the Web server telling us that the Web server picks up HTTP documents and scripts from the c:/inetpub/wwwroot directory.

Now, let's run HttpRequestDetails.php on the local IIS Web server. First copy HttpRequestDetails.php to \inetpub\wwwroot, then run Internet Explorer (IE) with http://localhost/HttpRequestDetails.php. You should get:

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

Contents of $_REQUEST:

Contents of $_SERVER: CONTENT_LENGTH = 0 GATEWAY_INTERFACE = CGI/1.1 HTTP_ACCEPT = */* HTTP_ACCEPT_LANGUAGE = en-us HTTP_CONNECTION = Keep-Alive HTTP_HOST = localhost HTTP_ACCEPT_ENCODING = gzip, deflate HTTPS = off INSTANCE_ID = 1 LOCAL_ADDR = 127.0.0.1 NUMBER_OF_PROCESSORS = 1 OS = Windows_NT ProgramFiles = C:\Program Files REMOTE_ADDR = 127.0.0.1 REMOTE_HOST = 127.0.0.1 REQUEST_METHOD = GET SCRIPT_NAME = /HttpRequestDetails.php SERVER_NAME = localhost SERVER_PORT = 80 SERVER_PORT_SECURE = 0 SERVER_PROTOCOL = HTTP/1.1 SystemDrive = C: ORIG_PATH_INFO = /HttpRequestDetails.php ORIG_SCRIPT_NAME = /HttpRequestDetails.php DOCUMENT_ROOT = c:/inetpub/wwwroot SCRIPT_FILENAME = c:\inetpub\wwwroot\HttpRequestDetails.php PHP_SELF = /HttpRequestDetails.php ......

Note that $_GET, $_POST, $_COOKIE, and $_REQUEST are still all empty, because HTTP request contains no information submitted using the GET or POST method. And there is no cookies in the HTTP request.

58 Naresh i Technologies

Page 59: Hypertext Preprocessor Demystified

PHP Course Material

However, other information contained in the HTTP request and gathered from the Web server is stored in the $_SERVER array now. For example, "DOCUMENT_ROOT = c:/inetpub/wwwroot" is piece of information from the Web server telling us that the Web server picks up HTTP documents and scripts from the c:/inetpub/wwwroot directory.

Now, let's run HttpRequestDetails.php on the local IIS Web server. First copy HttpRequestDetails.php to \inetpub\wwwroot, then run Internet Explorer (IE) with http://localhost/HttpRequestDetails.php. You should get:

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

Contents of $_REQUEST:

Contents of $_SERVER: CONTENT_LENGTH = 0 GATEWAY_INTERFACE = CGI/1.1 HTTP_ACCEPT = */* HTTP_ACCEPT_LANGUAGE = en-us HTTP_CONNECTION = Keep-Alive HTTP_HOST = localhost HTTP_ACCEPT_ENCODING = gzip, deflate HTTPS = off INSTANCE_ID = 1 LOCAL_ADDR = 127.0.0.1 NUMBER_OF_PROCESSORS = 1 OS = Windows_NT ProgramFiles = C:\Program Files REMOTE_ADDR = 127.0.0.1 REMOTE_HOST = 127.0.0.1 REQUEST_METHOD = GET SCRIPT_NAME = /HttpRequestDetails.php SERVER_NAME = localhost SERVER_PORT = 80 SERVER_PORT_SECURE = 0 SERVER_PROTOCOL = HTTP/1.1 SystemDrive = C: ORIG_PATH_INFO = /HttpRequestDetails.php ORIG_SCRIPT_NAME = /HttpRequestDetails.php DOCUMENT_ROOT = c:/inetpub/wwwroot SCRIPT_FILENAME = c:\inetpub\wwwroot\HttpRequestDetails.php PHP_SELF = /HttpRequestDetails.php ......

Note that $_GET, $_POST, $_COOKIE, and $_REQUEST are still all empty, because HTTP request contains no information submitted using the GET or POST method. And there is no cookies in the HTTP request.

However, other information contained in the HTTP request and gathered from the Web server is stored in the $_SERVER array now. For example, "DOCUMENT_ROOT =

59 Naresh i Technologies

Page 60: Hypertext Preprocessor Demystified

PHP Course Material

c:/inetpub/wwwroot" is piece of information from the Web server telling us that the Web server picks up HTTP documents and scripts from the c:/inetpub/wwwroot directory.

Information in $_GET and $_REQUEST

This section provides a tutorial example on how to dump information stored in the $_GET array and the $_REQUEST array.

Now try this URL, http://localhost/HttpRequestDetails.php?lang=PHP&search. You should get:

Contents of $_GET: lang = PHP search =

Contents of $_POST:

Contents of $_COOKIE:

Contents of $_REQUEST: lang = PHP search =

Contents of $_SERVER: ...... QUERY_STRING = lang=PHP&search ......

Notice that:

"?lang=PHP&search" attached at the end of the URL represents information submitted with the GET method.

"?lang=PHP&search" is parsed by the PHP engine into 2 pairs of names and values and stored in the $_GET array.

The PHP engine copied the same information from $_GET to $_REQUEST.

Exercise: Try to find a way to test how to provide information with the POST method and how to provide cookies.

Registering $_REQUEST Keys as Global Variables

This section provides a tutorial example on how to promote (or register) keys and values in the $_REQUEST array as global variables so that you don't have to use the array notation to access their values.

To access information stored in the $_REQUEST array, you can use the normal array element notation, $_REQUEST[$key]. For example, $_REQUEST["lang"] would return "PHP" in the example script used in the previous section.

60 Naresh i Technologies

Page 61: Hypertext Preprocessor Demystified

PHP Course Material

But key-value pairs in $_REQUEST can also be promoted (or registered) as standalone global variables using one of two ways described below:

1. To register $_REQUEST key-value pairs as global variables on the entire server, edit \php\php.ini and set:

register_globals = on

With this setting, the PHP engine will automatically create a global variable for each key in $_REQUEST with the key name as the variable name. of course, the value associated with the key will be copied to the variable at the same time. For example, if $_REQUEST["lang"] contains "PHP", $lang will created with the value "PHP".

2. To register $_REQUEST key-value pairs as local variables for the current script execution only, use the following function:

import_request_variables("GPC",$prefix);

where "GPC" indicates that key-value pairs copied from $_GET, $_POST and $_COOKIE will be registed as local variables. $prefix defines a prefix string that are to be added to variable names.

To test this, I turned on the register_globals setting in php.ini and wrote this sample script, RequestVariables.php:

<?php # RequestVariables.php# print "<pre>\n"; print "\nContents of \$_REQUEST:\n"; foreach ($_REQUEST as $k => $v) { print " $k = $v\n"; }# print "\nLocal imported variables from the request:\n"; import_request_variables("GPC","r_"); print " \$r_lang = $r_lang\n"; print " \$r_search = $r_search\n";# print "\nGlobaly imported variables from the request:\n"; print " \$lang = $lang\n"; print " \$search = $search\n"; print "</pre>\n";?>

Open this script with http://localhost/RequestVariables.php?lang=PHP&search, you will get:

Contents of $_REQUEST: lang = PHP search =

Local imported variables from the request: $r_lang = PHP $r_search =

61 Naresh i Technologies

Page 62: Hypertext Preprocessor Demystified

PHP Course Material

Globaly imported variables from the request: $lang = PHP $search =

To access information stored in the $_REQUEST array, you can use the normal array element notation, $_REQUEST[$key]. For example, $_REQUEST["lang"] would return "PHP" in the example script used in the previous section.

But key-value pairs in $_REQUEST can also be promoted (or registered) as standalone global variables using one of two ways described below:

1. To register $_REQUEST key-value pairs as global variables on the entire server, edit \php\php.ini and set:

register_globals = on

With this setting, the PHP engine will automatically create a global variable for each key in $_REQUEST with the key name as the variable name. of course, the value associated with the key will be copied to the variable at the same time. For example, if $_REQUEST["lang"] contains "PHP", $lang will created with the value "PHP".

2. To register $_REQUEST key-value pairs as local variables for the current script execution only, use the following function:

import_request_variables("GPC",$prefix);

where "GPC" indicates that key-value pairs copied from $_GET, $_POST and $_COOKIE will be registed as local variables. $prefix defines a prefix string that are to be added to variable names.

To test this, I turned on the register_globals setting in php.ini and wrote this sample script, RequestVariables.php:

<?php # RequestVariables.php# print "<pre>\n"; print "\nContents of \$_REQUEST:\n"; foreach ($_REQUEST as $k => $v) { print " $k = $v\n"; }# print "\nLocal imported variables from the request:\n"; import_request_variables("GPC","r_"); print " \$r_lang = $r_lang\n"; print " \$r_search = $r_search\n";# print "\nGlobaly imported variables from the request:\n"; print " \$lang = $lang\n"; print " \$search = $search\n"; print "</pre>\n";?>

62 Naresh i Technologies

Page 63: Hypertext Preprocessor Demystified

PHP Course Material

Open this script with http://localhost/RequestVariables.php?lang=PHP&search, you will get:

Contents of $_REQUEST: lang = PHP search =

Local imported variables from the request: $r_lang = PHP $r_search =

Globaly imported variables from the request: $lang = PHP $search = Creating and Managing Sessions in PHP Scripts

This chapter provides tutorial examples and notes about session. Topics include understanding of the session concept; writing scripts to create and use a session; storing data in the current session; managing session IDs as cookies and URL transparent parameters.

What Is a Session?

How Sessions Are Support in PHP?

SessionPage*.php - Session Test Script Pages

Running Session Test Script Pages

Managing Session IDs without Cookies

Where Is Session Data Stored?

Conclusion:

A session ID must be passed between HTTP requests and responses to link them into a single sequence.

Passing the session ID as a cookie value is more secure.

Passing the session ID as a transparent URL variable is less secure, because the session ID will be displayed in the Web page address field.

You must call the built-in function, session_start(), at the beginning of the PHP script to start a new session, or continue with an existing session.

The built-in array, $_SESSION, can be used to pass information from one script to another script that shares the same session as the first script.

Session data is persisted to the hard disk permanently on the server side.

What Is a Session?

63 Naresh i Technologies

Page 64: Hypertext Preprocessor Demystified

PHP Course MaterialThis section describes the session concept used by Web server side applications. A Web session represents a series of HTTP requests and responses exchanged between a browser and a Web server. Usually, a cookie is used to carry the ID of a Web session.

What Is a Session? A session is an abstract concept to represent a series of HTTP requests and responses exchanged between a specific Web browser and a specific Web server. The session concept is very useful for Web based applications to pass and share information from one Web page (request) to another Web page (request).

Since the current design of HTTP protocol does not support session concept, all Web server side scripting technologies, including PHP, have designed their own ways to support the session concept. The key design element of session support is about how to identify a session with an ID (identification) and how to maintain the session ID. One common way to maintain the session ID is use the cookie technology. The following diagram shows you how to do this:

Server BrowserID created | <-- Request #1 --- | | --- Response #1 --> | ID kept as cookie | <-- Request #2 --- | ID send back to server | --- Response #2 --> | | <-- Request #3 --- | ID send back to server | --- Response #3 --> | | ...... |

The session concept should be managed by the server. When the first request comes from a browser on a client host, the server should create a new session, and assigns a new session ID. The session ID will be then sent back to the same browser as a cookie. The browser will remember this ID, and send the ID back to the server in subsequent requests. When the server receives a request containing the same session ID, it knows that this request is a continuation of an existing session.

When the server receives a request from a browser on a new client host (request without a session ID), the server should not only create a new session ID, it should also create a new session object associated with the new session ID. This session object should become the storage place for different requests of the same session to store and share information between requests containing the same session ID.

If there is no subsequent request coming back for a long time for a particular session ID, that session should be timed out. After the session has been timed out, if the browser comes back again with the same session ID, the server should give an invalid session error.

How Sessions Are Support in PHP?This section describes how sessions are supported in PHP. Session IDs are passed as cookies or GET/POST variables. session_start() is the built-in function to start a session. $_SESSION is the built-in array to manage session data.

PHP supports Web sessions with following main elements:

64 Naresh i Technologies

Page 65: Hypertext Preprocessor Demystified

PHP Course Material

1. session.use_cookies = 1/0 - A setting in the configuration file, php.ini, to determine if the session ID should be stored and managed as a cookie.

session.use_cookies = 1 (the default setting) - Managing the session ID as a cookie. The session ID is stored in a cookie with a default name of "PHPSESSID". This "PHPSESSID" cookie will be automatically inserted into HTTP responses and retrieved from HTTP requests by the PHP engine.

session.use_cookies = 0 - Stop storing the session ID as a cookie.

2. session.use_trans_sid = 1/0 - A setting in the configuration file, php.ini, to control if the session ID should be stored and managed transparently as a parameter in the URL.

session.use_trans_sid = 1 - Managing the session ID as an extra transparent parameter in the URL. The extra URL parameter contains the session ID value with a default name of "PHPSESSID". This "PHPSESSID" parameter will be automatically inserted into all links in the HTTP response, and retrived from HTTP requests by the PHP engine.

session.use_trans_sid = 0 (the default setting) - Stop storing the session ID as a URL transparent parameter.

3. session.save_handler = files/mm/user - A setting in the configuration file, php.ini, to control how session data should be stored.

session.save_handler = files (the default setting) - Storing session data as files in a directory defined in the session.save_path = "/tmp" setting.

session.save_handler = mm - Storing session data in shared memory.

session.save_handler = user - Storing session data through user-defined functions.

4. session_start() - A built-in function to create a new session or resume an existing session. When session_start() is called, the PHP engine will check the current HTTP request to see if an existing session ID is included or not.

If no session ID is found, the PHP engine will create a new session with a new session ID.

If a session ID is found, the PHP engine will restore the session identified by this session ID. If the restored session has been timed out, an error will be issued.

5. $_SESSION - A built-in array attached to the current session acting as a storage. You can store any number of key-value pairs in $_SESSION in a PHP script and retrieve them later in another script if it shares the same session as the first script.

6. session_name() - A built-in function to set and get the name of the current session.

7. session_id() - A built-in function to set and get the session ID of the current session.

8. session_destroy() - A built-in function to destroy the current session. When the current session is destroyed, information stored in $_SESSION will be removed.

65 Naresh i Technologies

Page 66: Hypertext Preprocessor Demystified

PHP Course MaterialSessionPage*.php - Session Test Script PagesThis section provides a tutorial example on how to write multiple script pages and use the session concept to make them work together.

To help us testing the session concept, I wrote 3 PHP scripts.

1. SessionPage1.php:

<?php # SessionPage1.php

# session_start(); $quantity = 3; $_SESSION['quantity'] = $quantity; if (isset($_SESSION['count'])) { $count = $_SESSION['count']; } else { $count = 0; } $count++; $_SESSION['count'] = $count;# print "<pre>\n"; print "\nI am buying $quantity PHP books.\n"; print "\n<a href=SessionPage2.php>Next</a>\n"; print "\nCounter = $count\n"; print "Session name = ".session_name()."\n"; print "Session id = ".session_id()."\n";# print "\nContents of \$_GET:\n"; foreach ($_GET as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_POST:\n"; foreach ($_POST as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_COOKIE:\n"; foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>

2. SessionPage2.php:

<?php # SessionPage2.php# session_start(); $quantity = $_SESSION['quantity']; $price = 9.99; $_SESSION['price'] = $price; $count = $_SESSION['count']; $count++;

66 Naresh i Technologies

Page 67: Hypertext Preprocessor Demystified

PHP Course Material $_SESSION['count'] = $count;# print "<pre>\n"; print "\nI am buying $quantity PHP books.\n"; print "The unit price is $price per book.\n";# print "\n<a href=SessionPage3.php>Next</a> "; print " <a href=SessionPage1.php>Prev</a>\n"; print "\nCounter = $count\n"; print "Session name = ".session_name()."\n"; print "Session id = ".session_id()."\n";# print "\nContents of \$_GET:\n"; foreach ($_GET as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_POST:\n"; foreach ($_POST as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_COOKIE:\n"; foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>

3. SessionPage3.php:

<?php # SessionPage3.php# session_start(); $quantity = $_SESSION['quantity']; $price = $_SESSION['price']; $total = $quantity * $price; $count = $_SESSION['count']; $count++; $_SESSION['count'] = $count;# print "<pre>\n"; print "\nI am buying $quantity PHP books.\n"; print "The unit price is $price per book.\n"; print "The total price is $total.\n";# print "\n<a href=SessionPage2.php>Prev</a>\n"; print "\nCounter = $count\n"; print "Session name = ".session_name()."\n"; print "Session id = ".session_id()."\n";# print "\nContents of \$_GET:\n"; foreach ($_GET as $k => $v) { print " $k = $v\n"; }# print "\nContents of \$_POST:\n"; foreach ($_POST as $k => $v) {

67 Naresh i Technologies

Page 68: Hypertext Preprocessor Demystified

PHP Course Material print " $k = $v\n"; }# print "\nContents of \$_COOKIE:\n"; foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>Running Session Test Script PagesThis section provides a tutorial example on how to run multiple script pages that are connected by the session concept. Page outputs prove that the session concept is working.

If you run http://localhost/SessionPage1.php, you should get:

I am buying 3 PHP books.

Next

Counter = 1Session name = PHPSESSIDSession id = o9oipjgc4r3fqmfk8mlldl5sl5

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

If you click "Next" on the first page, you will be running http://localhost/SessionPage2.php, and should get:

I am buying 3 PHP books.The unit price is 9.99 per book.

Next Prev

Counter = 2Session name = PHPSESSIDSession id = o9oipjgc4r3fqmfk8mlldl5sl5

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE: PHPSESSID = o9oipjgc4r3fqmfk8mlldl5sl5

If you click "Next" on the second page, you will be running

//localhost/SessionPage3.php, and should get:

I am buying 3 PHP books.The unit price is 9.99 per book.The total price is 29.97.

68 Naresh i Technologies

Page 69: Hypertext Preprocessor Demystified

PHP Course Material

Prev

Counter = 3Session name = PHPSESSIDSession id = o9oipjgc4r3fqmfk8mlldl5sl5

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE: PHPSESSID = o9oipjgc4r3fqmfk8mlldl5sl5

As you can see, the session concept is working. Several points should be noted here:

Data can be stored into the session in one page, and retrieve it in another page. For example, the quantity is stored into the session in the first page, and retrieved in the second and third page.

The session name is a string defined in the php.ini file.

The session ID is created by PHP, and managed as a cookie.

You can use the session object to manage a count of pages visited in a particular session. But you can not use the session object to manage a count of pages visited in all sessions. To manage information across versions, you need a new concept higher than session. For example, the application and the server concept is higher than the session concept

Managing Session IDs without Cookies

Managing Session IDs without Cookies

This section provides a tutorial example on how to stop storing the session ID as a cookie, and using a URL transparent parameter to store the session ID.

If don't like to use the cookie technology to manage the session ID, you can try to use the URL transparent parameter to manage the session ID. Here is what I did to test the URL transparent parameter.

1. Open and edit the configuration file, \php\php.ini:

session.use_cookies = 0session.use_trans_sid = 1

2. Re-run http://localhost/SessionPage1.php, I got:

I am buying 3 PHP books.

Next

69 Naresh i Technologies

Page 70: Hypertext Preprocessor Demystified

PHP Course MaterialCounter = 1Session name = PHPSESSIDSession id = mg04r204ctuloo2uegmih14ri5Session module = files

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

3. Click "Next" on the first page, the URL address on the browser was changed to: http://localhost/SessionPage2.php?PHPSESSID=mg04r204ctuloo2uegmih14ri5. The browser displayed:

I am buying 3 PHP books.The unit price is 9.99 per book.

Next Prev

Counter = 2Session name = PHPSESSIDSession id = mg04r204ctuloo2uegmih14ri5

Contents of $_GET: PHPSESSID = mg04r204ctuloo2uegmih14ri5

Contents of $_POST:

Contents of $_COOKIE:

4. Click "Next" on the second page, the URL address on the browser was changed to: http://localhost/SessionPage3.php?PHPSESSID=mg04r204ctuloo2uegmih14ri5. The browser displayed:

I am buying 3 PHP books.The unit price is 9.99 per book.The total price is 29.97.

Prev

Counter = 3Session name = PHPSESSIDSession id = mg04r204ctuloo2uegmih14ri5

Contents of $_GET: PHPSESSID = mg04r204ctuloo2uegmih14ri5

Contents of $_POST:

Contents of $_COOKIE:

Output shows that the session concept still worked correctly. But a couple of interesting things happened here:

70 Naresh i Technologies

Page 71: Hypertext Preprocessor Demystified

PHP Course Material

If you ask PHP to use transparent session ID management, it will modify all the links to include the session ID as part of URL addresses. See the source code of the first page in the browser, you should see that the URL of "Next" button was modified as href=SessionPage2.php?PHPSESSID=mg04r204ctuloo2uegmih14ri5.

Outputs show that now the session ID is stored in the $_GET array.

Since the session ID is stored in the URL field of the browser, everyone can see it. So this is less secure that storing the session ID a cookie.

Where Is Session Data Stored?

This section provides a tutorial example on how to find out where the PHP engine stores session data. The session.save_path setting specifies the directory name for session data.

Where does PHP store session data? The answer is not so obvious.

Since I am running the PHP engine in CGI mode, PHP script pages are running with individual instances of the PHP executable program. So there is no easy to store session data in memory and share it between different PHP script pages. If not stored in memory, session data can be stored on hard disk and share it between PHP pages. Let's see if we can find where session data is stored on the hard disk.

First run http://localhost/SessionPage1.php again:

I am buying 3 PHP books.

Next

Counter = 1Session name = PHPSESSIDSession id = mg04r204ctuloo2uegmih14ri5Session module = files

Contents of $_GET:

Contents of $_POST:

Contents of $_COOKIE:

Then use the Windows find tool to search for file names with "mg04r204ctuloo2uegmih14ri5". No surprise, you should get \tmp\sess_mg04r204ctuloo2uegmih14ri5. Open this file in a text editor, you should see:

quantity|i:3;count|i:1;

The file format is so simple, session data is stored in clear text, with ";" as delimiters. If you want to change where session data is stored, you can modify the session.save_path setting in \php\php.ini. For example:

session.save_path = "\herong\temp"

71 Naresh i Technologies

Page 72: Hypertext Preprocessor Demystified

PHP Course Material

PHP Session Securitythings to watch out for when using sessions for your sites login system;

1. Shared web servers - anyone else on the server can read your session files (typically in the /tmp directory) if PHP is running as an Apache module (so the session files belong to the web user) and possibly when PHP is used as a CGI (depending on how sessions are implemented).

Someone browsing the session files (probably) won’t know the site the server the sessions apply to (so may not be able to use a username / password combination they found) but you may still be putting sensitive info (like credit card details) somewhere for all to see. Plus they’ve got a list of valid session IDs…

If you’re just storing passwords in the session, you can get away with this by using md5() (preferably twice) to one-way encypt the password. This doesn’t help though if you need to recover the value of a session variable.

Using a custom session handler to store the sessions in a database is probably the best solution. You might consider MySQL HEAP tables if performance is an issue (assuming MySQL running on same machine as Apache). If it gets to very high traffic, it’s time to think about getting your own server…

2. XSS exploits (and session hijacking) - using JavaScript users can be fooled into giving away their active session_id.

All someone needs to “hijack” a session is the unique session id. It’s like the key to a railway station locker. The locker doesn’t check you’re the valid owner of the key, before allowing you to open it so anyone with the key can get in.

Research XSS and how to prevent it.

Accept that session hijacking cannot be entirely prevented (checks on IP address, for example, is foiled by AOL, who assign a new client IP on more or less every page request) so double check “critical actions” a user can perform when logged in e.g. when changing password - require the old password, which the session hijacker will (hopefully) not know. Displaying credit card infomation - do like Amazon and only display the last four digits. Basically limit the damage someone can do if they hijack a session.

3. Session IDs in URL (and hijacking) - if you’re using session IDs in the URL (as opposed to a session cookie), make sure offsite links do not contain the session ID (or the remote site will be able to hijack) - PHP should take care of this. Also your visitors may give away the session ID in the referrer field - ideally pass off site links through a redirect page, to elimate the referrer (although, unfortunately, some browsers keep the last 3 pages viewed I believe - unsure of facts).

72 Naresh i Technologies

Page 73: Hypertext Preprocessor Demystified

PHP Course Material

Ideally, don’t pass session ids in the URL - require users to accept a cookie if they need to “log in”.

4. Session Fixation (pre-hijacking.

If you assign a session to a visitor to your site, before they are logged in (for example for clickpath analysis), make sure that you assign them a new session id when they do login, so that if someone pre-generated the initial session id for them, they won’t get the new ID.

For PHP 4.2.0+, see session_regenerate_id() (in particular the user submitted comments). For PHP < 4.2.0, you'll have to destroy the session and re-create it when the user logs in, carrying any stored data between the two. The session_id() function may also be useful (haven’t explored it in this context myself).

5. Sniffing Packets (use SSL [HTTPS]) - a session ID can be “sniffed” between the client and your server. If it’s a site where money is changing hands or other sensitive personal information is involved, SSL is a requirement.

Otherwise, without SSL, you have

to live with the risk (just like you do every time you use that FTP client…).

6. Cookies are not for session data - on a related note, don’t use cookies for store sensitive information.

Cookie data, unlike sessions, gets stored on the client site. Apart from the “sniffing risk”, a large majority of Windows users have little idea of security and may be “owned by haxor”.

Otherwise, cookies (aside from session cookie PHP creates for you) are generally meant for long term (i.e. between visits) data persistance (e.g. “Remember Me”) rather than “active session” persistance.

There’s probably more things to watch out for (or facts to correct) - suggestions appreciate

Sending and Receiving Cookies in PHP Scripts

This chapter provides tutorial examples and notes about cookie. Topics include understanding of the cookie concept; sending cookies with the setcookie() function; receiving cookies with the $_COOKIE array; enabling output buffering; creating persistent cookies; specifying cookie domain and path.

73 Naresh i Technologies

Page 74: Hypertext Preprocessor Demystified

PHP Course Material

What Is a Cookie?

Sending and Receiving Cookies

Sending and Receiving Cookies - Example

ob_start() - Output Buffering Function

Persistent Cookies Saved on Hard Disk

Other Cookie Properties - Domain and Path

Conclusion:

setcookie() must be called before any output to the HTTP response. The main reason is that PHP is not buffering the HTTP response. But you can alter this behavior by using the ob_start() functions.

A persistent cookie is stored in a cookie file on the browser's local machine.

A persistent cookie can have an expiration time expressed in number of seconds since epoch.

Web browser will only send back a cookie when both domain and path match the requested domain and path.

To make a cookie available for all sub domains of a top level domain, set the domain property to the top level domain name.

What Is a Cookie?

This section describes what is a cookie - a piece of information sent by a Web server to a browser. The server expects the browser to send all cookies back to the server.

What Is a Cookie? A cookie is a piece of information sent by a Web server to a Web browser, saved by the browser, and sent back to the server later. Cookies are transmitted inside the HTTP header.

Cookies move from server to browser and back to server as shown in the following diagram:

Web Web Local Web WebServer Browser System Browser Server

Send Receive Save Send back Receivecookies --> cookies --> cookies --> cookies --> cookies

74 Naresh i Technologies

Page 75: Hypertext Preprocessor Demystified

PHP Course Material

As you can see from the diagram, cookies are actually saved by the local system in memory or on the hard disk of Web browser user's machines. Many users are concerned about this. But I think it is pretty safe to allow your browser to save cookies.

If you are really concerned, you can change your browser's settings to reject cookies. But this may cause many Web based applications fail to run on your browser.

Cookies are mainly used to pass information from one PHP script to the next script.

Sending and Receiving Cookies

This section describes how PHP supports cookies. setcookie() is the function to set a cookie to the HTTP response. $_COOKIE is the array containing cookies received in the next HTTP request.

PHP supports cookies with following elements:

1. setcookie() - A built-in function that defines a cookie to be sent in the HTTP response as a header line. Like other header lines, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including <html> and <head> tags as well as any whitespace. If output exists prior to calling this function, setcookie() will fail and return FALSE.

The syntax of calling setcookie() is:

bool setcookie(string name, string value, int expire) "name" is the name of this cookie. "value" is the value of this cookie. "value" is optional. If "value" is not provided, this

cookie will be set in the HTTP response without any value.

"expire" is the time when this cookie should be expired. "expire" is optional. If "expire" is not provided, this cookie will saved in browser memory only. If "expire" is provided, it represents a time in number of seconds since the epoch. If the provided time is a future time, this cookie will be saved on the hard disk of the browser system.

For example, setcookie("user", "Herong") will set a cookie named as "user" in the HTTP response.

2. $_COOKIE - A built-in array that stores cookies returned back from the browser in the next HTTP request. Cookie names will be used as array keys. For example, $_COOKIE["user"] returns the cookie value, "Herong", included in the HTTP request.

Sending and Receiving Cookies – Example

This section provides a tutorial example on how to set and send a cookie with the setcookie() function, and how to receive a cookie with the $_COOKIE array.

75 Naresh i Technologies

Page 76: Hypertext Preprocessor Demystified

PHP Course Material

To help us understand how to send and receive cookies, I wrote the following PHP tutorial example script page, CookieTest.php:

<?php #CookieTest.php# $numCookies = count( array_keys($_COOKIE) ); $numCookies++; $cookieName = "Cookie_$numCookies"; $cookieValue = "My cookie value"; setcookie($cookieName, $cookieValue);

print("<pre>\n"); print("Cookies added by the server:\n"); print(" $cookieName: $cookieValue\n");

print("\nCookies received by the server:\n"); foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>

When I ran run this script with a browser, I got:

Cookies added by the server: Cookie_1: My cookie value

Cookies received by the server:

When I click the refresh button of the browser, the page changed with:

Cookies added by the server: Cookie_2: My cookie value

Cookies received by the server: Cookie_1 = My cookie value

What happened here was that when I opened the page the first time, the server received no cookie from the browser's HTTP request. So my page added the first cookie named as "Cookie_1" to the HTTP response.

When I clicked the refresh button, the browser sent my first cookie back to the server in the HTTP request. Then my page added the second cookie named as "Cookie_2" in the response.

If I keep clicking the refresh button, more and more cookies would be added to the request and response. But there is a limit. The browser will only take up to 20 cookies from one Web server.

ob_start() - Output Buffering Function

This section describes how to use the ob_start() function to turn on output buffering, which allows HTTP response header lines to be added after response body has been added.

76 Naresh i Technologies

Page 77: Hypertext Preprocessor Demystified

PHP Course Material

As you can see from setcookie() definition, the PHP engine provides no buffer for the HTTP response body. That means as soon the PHP script starts to send output to the HTTP response body, the HTTP header block will be finalized, and not allowed to change any more.

But this default behavior can be altered by calling output control functions:

setcookie() must be called before any output to the HTTP response. The main reason is that PHP is not buffering the HTTP response. But you can alter this behavior by using ob_*() functions.

ob_start() - A built-in function that turns on output buffering.

flush() - A built-in function that flushes out the contents of the output buffer to the HTTP response body.

Of course, default behavior can also be altered by the configuration file, php.ini. Open php.ini and set the following line:

output_buffering = 4096

The above configuration line tells the PHP engine to turn on output buffering, and set the buffer size to 4096 bytes. Once "output_buffering" is turned on, you don't have to call ob_start() in your scripts.

To test the PHP engine default behavior, I modified CookieTest.php into CookieOutputBuffer.php:

<?php #CookieOutputBuffer.php# print("<pre>\n"); print("Adding cookies by the server:\n");

$numCookies = count( array_keys($_COOKIE) ); $numCookies++; $cookieName = "Cookie_$numCookies"; $cookieValue = "My cookie value"; print(" $cookieName: $cookieValue\n");

setcookie($cookieName, $cookieValue);

print("\nCookies received by the server:\n"); foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n";?>

I then opened php.ini and set the following line:

output_buffering = 0

Running IE on CookieOutputBuffer.php gave me this:

77 Naresh i Technologies

Page 78: Hypertext Preprocessor Demystified

PHP Course MaterialAdding cookies by the server: Cookie_2: My cookie value

Cookies received by the server: User = Herong Yang

PHP Warning: Cannot modify header information - headers already sent by (output started at ...\CookieOutputBuffer.php:4) ...

Now I truly beblieve that PHP engine's default behavior is no output buffering. Make sure to change "output_buffering" back to 4096 before continuing to the next test.

Persistent Cookies Saved on Hard Disk

This section describes what is a persistent cookie - A cookie with an expiration time in the future and saved in a cookie file on the hard disk of the browser computer.

There are two kinds of cookies: persistent cookies and temporary cookies.

A persistent cookie is stored in a file on your computer's hard disk. It remains there after you close your Web browser. A persistent cookie will be picked up by the browser and included in HTTP requests for the Web server, where the cookie came from.

A temporary or session cookie is stored in memory only for your current browsing session. A temporary cookie will be deleted when you close your browser.

The default behavior of setcookie(name,value) is to set a cookie as a temporary cookie. To set a persistent cookie, we need to add another parameter to the setcookie() function call using the following syntax:

bool setcookie(string name, string value, int expire)

where "expire" specifies when this cookie should be expired. If the expiration time is a future time, like 30 days from today, this cookie will be set as a persistent cookie. Note that "expire" should be represented in number of seconds since the epoch. The best way to set "expire" is use the time() function, which represents the current time in number of seconds since the epoch. Example, 30 days from today can be expressed as "time()+60*60*24*30".

If "expire" is not given, a temporary cookie will be created.

To show you how to set a persistent cookie, and how the cookie is store in a file, I wrote the following PHP script page, CookiePersisted.php:

<?php #CookiePersisted.php

# $cookieName = "User"; $cookieValue = "Herong Yang"; $expiration = time()+60*60*24*30; setcookie($cookieName, $cookieValue, $expiration);

78 Naresh i Technologies

Page 79: Hypertext Preprocessor Demystified

PHP Course Material print("<pre>\n"); print("Cookies added by the server:\n"); print(" $cookieName: $cookieValue\n"); print(" Expires at: $expiration\n"); print "</pre>\n";?>

I opened this page with IE (Internet Explorer), I got:

Cookies added by the server: User: Herong Yang Expires at: 1134531525

To find out in which file this cookie is stored in my computer, I clicked at IE's "Tools" menu, selected "Internet Options...". and clicked the "Settings..." button in the "Temporary Internet files" section of the "General" tab. I saw where is my "Temporary Internet files folder". So I went to that folder, and saw a cookie file named something like "Cookie:user@localhost/". I double clicked on that file, and managed to open it in notepad:

UserHerong+Yanglocalhost/1024380146905629753439393426041629747404*

Actually, I saw a lots of other cookie files created by other Web sites that I have visited in the past. I deleted all of them.

Other Cookie Properties - Domain and Path

This section describes two other cookie properties, domain and path, which tells the browser to send back the cookie only to the specified domain and path.

A cookie also has two other properties:

1. "domain" - A property that defines the domain of Web servers to which this cookie should be made available. Web browsers will send a cookie back to a Web server when the Web server matches its defined domain. Web browsers will never send back a cookie to a domain other than its defined domain.

For example, if a cookie's domain is www.google.com, the browser will send back this cookie to the server only when the browser is visiting www.google.com. The browser will never send back this cookie to www.yahoo.com.

To make a cookie available for all sub domains of a top level domain, set the domain property to the top level domain name. For example, if a cookie's domain is set to ".google.com", this cookie will be available to all google sub domains, like groups.google.com and gmail.google.com.

79 Naresh i Technologies

Page 80: Hypertext Preprocessor Demystified

PHP Course Material

2."path" - A property that defines a Web server path to which this cookie should be made available. Web browsers will send a cookie back to a Web server when the Web server matches its defined domain, and the requested page matches its defined path. Web browsers will never send back a cookie to requested path other than its defined path.

Note that the defined path also includes all its sub paths. For example, if a cookie's domain is "www.amazon.com", and path is "/order/", then a browser will send back this cookie for requests like "http://www.amazon.com/order/checkout.html", and "http://www.amazon.com/order/report/invoice.html". But a browser should not send back this cookie for requests like "http://www.amazon.com/catelog/book.html".

The setcookie() function offers two more parameters to allow you to set "domain" and "path" properties on a cookie as in the following syntax:

bool setcookie(string name, string value, int expire, string path, string domain)

where "path" specifies the cookie's path property, and "domain" specifies the cookie's domain property. If "path" is not given, the cookie will have "/" as the default path. If "domain" is not given, the cookie will have the current domain as the default domain.

Okay. Let's play the properties with the following script, CookieProperties.php:

<?php #CookieProperties.php# print("<pre>\n"); print("\nAdding a cookie with default properties:\n");

$cookieName = "User"; $cookieValue = "Herong Yang"; $expiration = time()+60*60*24*30; setcookie($cookieName, $cookieValue, $expiration); print(" Name: $cookieName\n"); print(" Value: $cookieValue\n"); print(" Expiration: $expiration\n");

print("\nAdding a cookie with non-default properties:\n"); $cookieName = "Book"; $cookieValue = "Herong's Tutorial Notes on PHP"; $expiration = time()+60*60*24*30; $path = "/"; $domain = "localhost"; setcookie($cookieName, $cookieValue, $expiration, $path, $domain); print(" Name: $cookieName\n"); print(" Value: $cookieValue\n"); print(" Expiration: $expiration\n"); print(" Path: $path\n"); print(" Domain: $domain\n");

print("\nCookies received by the server:\n"); foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; }

print "</pre>\n";

80 Naresh i Technologies

Page 81: Hypertext Preprocessor Demystified

PHP Course Material?>

Ran this script in IE, I got:

Adding a cookie with default properties: Name: User Value: Herong Yang Expiration: 1134622043

Adding a cookie with non-default properties: Name: Book Value: Herong's Tutorial Notes on PHP Expiration: 1134622043 Path: / Domain: localhost

Clicked the refresh button on IE, I got:

Adding a cookie with default properties: Name: User Value: Herong Yang Expiration: 1134622059

Adding a cookie with non-default properties: Name: Book Value: Herong's Tutorial Notes on PHP Expiration: 1134622059 Path: / Domain: localhost

Cookies received by the server: User = Herong Yang

Apparently, my script did not set the properties correctly. The browser should have sent back my second cookie also. So either the "path=/" or "domain=localhost" did not match my local IIS environment. I could not figure it out why.

Controlling HTTP Response Header Lines in PHP Scripts

This chapter provides tutorial examples and notes about HTTP response header line. Topics include understanding of HTTP response structure and standard header lines; controling header lines using the header() function; dumping HTTP responses to view header lines; IIS and PHP engine added header lines for static files and PHP scripts; Location, Content-Type, and Content-Disposition header lines.

What Is an HTTP Response?

HTTP Response Header Lines

81 Naresh i Technologies

Page 82: Hypertext Preprocessor Demystified

PHP Course Material

header() - Inserting a Raw Header Lines

HttpRequestGet.php - Viewing Header Lines

Response Header Lines of Static Files

HttpHeaderLines.php - Examples of Inserting Header Lines

Location: - Forcing the Browser to Redirect to Another URL

Content-Type: - Generating Non-HTML Response Body

Content-Disposition: - Sending Files for Downloading

Conclusion:

HTTP response header lines must be generated before any other outputs from the script, unless you have the output_buffering turned on.

Setting header lines in PHP is simple - one built-in function, header(), does everything for you.

"Location" is a interesting header line. It tells the browser to redirect itself to a new URL.

"Content-disposition" tells the browser to prepare for downloading the entity body.

I like the powerful function, readfile(), reading the content of a file and sending it to the HTTP response directly

What Is an HTTP Response?

This section describes what is an HTTP response - The message returned from a Web server to the client machine in response to an HTTP request from that client machine.

What Is an HTTP Response? A HTTP response is the message a Web server needs to return back to a Web client machine in response to an HTTP request from the same client machine. Based on the HTTP/1.1 protocol, after receiving and interpreting an HTTP request from a client machine, a Web server must responds with an HTTP response message with the following structure:

status-lineheader-line...header-line

entity-body

Note that:

Response must have one status-line. Response can have zero, one, or many header lines.

82 Naresh i Technologies

Page 83: Hypertext Preprocessor Demystified

PHP Course Material

Response can only have zero or one entity-body.

There is a blank line between header lines and the entity body.

Status line, header line, and blank line must be ended with CRLF ("/r/n") characters.

Entity body is the actual data requested by the client request.

Header lines can be in any order.

Below is a sample HTTP response with two header lines:

HTTP/1.1 200 OKContent-Type: text/htmlContent-Length: 38

<html><body>Hello world!</body></html>

HTTP Response Header Lines

This section describes HTTP response header lines in 3 groups. Commonly used header lines are Date, Cache-Control, Last-Modified, Content-Length, Connection, Content-Type, Expires, Set-Cookie, Server, etc.

HTTP/1.1 response header lines allow the server to passes additional information about the response which cannot be placed in the status line. Header lines can be divided into three groups:

1. General header lines - Information about the transmission of the entire response message:

Cache-Control Connection Date Pragma Trailer Transfer-Encoding Upgrade Via Warning

2. Response header lines - Information about the response:

Accept-Ranges Age ETag Location Proxy-Authenticate Retry-After Server Vary WWW-Authenticate

3. Entity header lines - Information about the data requested by the client:

83 Naresh i Technologies

Page 84: Hypertext Preprocessor Demystified

PHP Course Material Allow Content-Encoding Content-Language Content-Length Content-Location Content-MD5 Content-Range Content-Type Expires Last-Modified

As examples, here is a list of all header lines from an HTTP response returned from the Yahoo Web serer:

Date: Sun, 13 Nov 2005 04:34:17 GMTP3P: policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP CO...Cache-Control: privateVary: User-AgentX-XRDS-Location: http://open.login.yahooapis.com/openid20/www.yaho...Last-Modified: Sun, 13 Nov 2005 04:31:16 GMTAccept-Ranges: bytesContent-Length: 9490Connection: closeContent-Type: text/html; charset=utf-8

header() - Inserting a Raw Header Lines

This section describes how to use the header() function to insert a raw HTTP response header line to reset the status line, replace an existing header line, or add a new header line.

When a PHP page is requested, the PHP engine will add some basic header lines in the HTTP response. But if you want to add new header lines or change those inserted by the PHP engine, you can use the header() function. Here are some rules on how to use the header() function:

1. The syntax of header() is:

void header(string $line, bool $replace, int $code)

2. $line specifies a complete header line string like "Content-Type: text/html".

3. $replace specifies a Boolean value controlling whether to replace a previously defined header line of the same identifier or not. If $replace = TRUE, the specified header line will replace any existing header lines with the same identifier. If $replace = FALSE, the specified header line will not replace any existing header lines with the same identifier. If $replace is not provided, PHP will assume $replace = TRUE.

4. $code specifies an integer to be used as the HTTP response status code. If $code is not provided, the PHP engine will decide the status code.

5. header() must be called before any output to the entity body, if the output buffering is turned off.

84 Naresh i Technologies

Page 85: Hypertext Preprocessor Demystified

PHP Course Material

6. If header() is called to set "Location" header line, the status line will be set to "HTTP/1.0 302".

7. When header() is called multiple times, the status line will be always generated first. Other header lines will be generated in same order as their calling statements.

Here a sample PHP script code segment that generates some header lines using the header() function:

header("HTTP/1.1 200 OK"); // Reset the status line header("Cache-Control: no-cache, must-revalidate"); header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Past time ok header("Content-Type: text/html; charset=utf-8"); header("Content-Length: 9490"); header("My-Header: SID=909494909", FALSE); // Allow duplicates header("My-Header: UID=Herong", FALSE); // Allow duplicates

HttpRequestGet.php - Viewing Header Lines

This section provides a tutorial example script, HttpRequestGet.php, on how to dump the entire HTTP response including all header lines from a Web server.

When a client program receives an HTTP response, it will look at header lines first. Based on the information contained in header lines, the client program will decide what to do with the actual response data in the entity body.

If you use a Web browser as an HTTP client program, it will process the data in the entity body differently depending on mainly the "Content-Type" entity header line: displaying the data as it is, rendering the data as an HTML document and displaying the resulting information, or passing the data to another registered program to handle it.

Once the Web browser finishes processing the entity body, you can get some limited information from the header lines. For example, you can click the right mouse button and select the properties command on Internet Explorer, it will display some general properties about this response in a pop up window. Properties displayed are not always identical to response header lines. The "Modified" property is probably identical to the "Last-Modified" entity header line. The "Type" property is sometime related to the "Content-Type" entity header line, and sometimes related to server side resource that generated the response.

How to view all header lines received in an HTTP response? I couldn't easily find any existing tools to do this. So I wrote the following program to dump the entire response including all header lines received from a Web server:

<?php # HttpRequestGet.php# $path = "/index.html"; $port = 80; $host = "localhost"; if (count($argv) > 1) $path = $argv[1]; if (count($argv) > 2) $port = $argv[2]; if (count($argv) > 3) $host = $argv[3];

85 Naresh i Technologies

Page 86: Hypertext Preprocessor Demystified

PHP Course Material $address = gethostbyname($host); $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($socket, $address, $port); $in = "GET $path HTTP/1.0\r\n\r\n"; socket_write($socket, $in, strlen($in)); while ($out = socket_read($socket, 2048)) { echo $out; } socket_close($socket);?>

Note that:

$argv is built-in array that contains all command line arguments, with $argv[0] representing the PHP file name, if you run your PHP file as "php file_name.php ...".

You need to make sure that "extension=php_sockets.dll" is turned on in your php.ini configuration file to use socket related functions.

Response Header Lines of Static Files

This section provides a tutorial example on how to test and view HTTP response header lines returned by IIS on 3 types of static files: HTML document, GIF image file, and PDF document.

Since I am using IIS (Internet Information Service) as the Web server, static files will be served directly by IIS server. It will set the status line and header lines for you based on the information collected from the static file the HTTP request is asking. For example, the "Content-Type" header line will be set based on the file name extension and the MIME settings of the server configuration. The "Content-Length" header line will be set to the size of the file.

Let's look at 3 examples of different types of static files. All of them are stored on my local machine at c:\inetpub\wwwroot, where the IIS is serving documents from.

1. Command: "php HttpRequestGet.php /hello.html" gives us:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Date: Sun, 13 Nov 2005 04:34:17 GMTContent-Type: text/htmlAccept-Ranges: bytesLast-Modified: Sun, 13 Nov 2005 04:31:16 GMTETag: "608fa7aaf8ebc51:c61"Content-Length: 38

<html><body>Hello world!</body></html>

Couple of interesting notes here:

Content-Type was set to "text/html", because the file name extension was "html". The request was marked as HTTP/1.0 in HttpRequestGet, but IIS responded with a higher

version, HTTP/1.1.

86 Naresh i Technologies

Page 87: Hypertext Preprocessor Demystified

PHP Course Material

I also tried to use HTTP/1.1 in my request, but IIS returned with an error. Why IIS could not support HTTP/1.1 request?

Notice that there was a blank line to separate the header lines and the entity body as required by the HTTP specification.

2. Command: "php HttpRequestGet.php /dot.gif" gives us:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Date: Sun, 13 Nov 2005 04:40:17 GMTContent-Type: image/gifAccept-Ranges: bytesLast-Modified: Sun, 11 Aug 2002 20:48:20 GMTETag: "04237ecd343c21:c61"Content-Length: 43

GIF89a......

As you can see, Content-Type was set correctly to "image/gif" for file name extension "gif", as defined in the MIME settings. I could not include the entire entity body here because it contains binary data.

3. Command: "php HttpRequestGet.php /hello.pdf" gives us:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Date: Sun, 13 Nov 2005 04:45:03 GMTContent-Type: application/pdfAccept-Ranges: bytesLast-Modified: Sun, 27 Jul 2003 20:22:12 GMTETag: "0b2f4c27c54c31:c61"Content-Length: 909

%PDF-1.3% ...4 0 obj......

Again, Content-Type was set correctly to "application/pdf" for file name extension "pdf", as defined in the MIME settings. I truncated the entity body to save some space.

HttpHeaderLines.php - Examples of Inserting Header Lines

This section provides a tutorial example on how to insert HTTP response header lines using the header() function.

Now let's see how the PHP engine defines header lines and how you can control them. First create this simple script, hello.php, and copy it to c:\inetpub\wwwroot.

Hello <?php echo "world!"; ?>

87 Naresh i Technologies

Page 88: Hypertext Preprocessor Demystified

PHP Course Material

Then obtain the response with "php HttpRequestGet.php /hello.php":

HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Date: Sat, 19 Nov 2005 02:39:52 GMTContent-type: text/htmlX-Powered-By: PHP/5.0.4

Hello world!

Comparing with the static files described in the previous section, the output shows:

PHP engine added its own header line, "X-Powered-By". IIS maintained the header line, "Server".

"ETag" was removed. I don't know what is ETag anyway.

PHP defaulted "Content-Type" to "text/html".

"Content-Length" is not provided. This is not a good behavior, if the client relies on this value.

Now, I am ready to instruct the PHP how to define header lines. Here is my testing script, HttpHeaderLines.php:

<?php #HttpHeaderLines.php# $text = "<html><body>Hello world!</body></html>"; print($text); header("Content-Type: text/xml;charset=utf-8"); header("Content-Length: ".strlen($text)); header("Version: Unknown"); header("Version: 2005"); header("Key-Word: PHP"); header("Key-Word: HTTP", false);?>

Here is the output:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Date: Sat, 19 Nov 2005 02:28:32 GMTContent-Type: text/xml;charset=utf-8X-Powered-By: PHP/5.0.4Content-Length: 38Version: 2005Key-Word: PHPKey-Word: HTTP

<html><body>Hello world!</body></html>

Okay. What can we say about the output?

88 Naresh i Technologies

Page 89: Hypertext Preprocessor Demystified

PHP Course Material

I was able to call header() after I started to output the entity body, because I had the output buffer turned on. I entered "output_buffering = 4096" in php.ini.

"Content-Type" defined ok.

"Content-Length" defined ok. But it was outputted after "X-Powered-By". Not sure why.

The "replace" flag worked. There is only one "Version", because by default replace is turned on. There are two "Key-Word", because I set "replace" to "false" in my second header() call.

Location: - Forcing the Browser to Redirect to Another URL

This section provides a tutorial example on how to insert the 'Location:' header line in a HTTP response to tell the browser to do a URL redirect - Send a HTTP request to the specified ULR immediately.

The PHP manual document says we can use header("Location: ...") to tell the browser to make a new HTTP request to a given URL. This is called "redirect". Here is my testing script, HttpRedirect.php:

<?php #HttpRedirect.php

# $text = "<html><body>Moved!</body></html>"; print($text); header("Content-Type: text/xml;charset=utf-8"); header("Content-Length: ".strlen($text)); header("Location: http://www.gmail.com/");?>

The output:

HTTP/1.1 302 Object MovedServer: Microsoft-IIS/5.1Date: Sat, 19 Nov 2005 03:46:58 GMTContent-Type: text/htmlX-Powered-By: PHP/5.0.4Content-Length: 32<head><title>Document Moved</title></head><body><h1>Object Moved</h1>This document may be found <a HREF="http://www.gmail.com/">here</a></body>

I am a little bit surprised by the output:

My entity body has been totally replaced by a short HTML document generated by the PHP engine. This is not mentioned in the PHP documentation at all!

The status line is changed to "HTTP/1.1 302 Object Moved".

The "Content-Length" still had my value, the number of bytes of my original HTML message, not the replacing message.

Content-Type: - Generating Non-HTML Response Body

89 Naresh i Technologies

Page 90: Hypertext Preprocessor Demystified

PHP Course Material

This section provides a tutorial example on how to change the 'Content-Type:' header line in a HTTP response to tell the browser to handle the response entity body as different document types, like ext/html, image/gif, application/pdf, application/msword, etc.

Sometimes, you may want to send back information in the response entity body that is not in the HTML format, for example, a PDF document, or a MS Word Document. In this case, we have to set Content-Type, Content-Length and other header lines carefully to provide correct information about the entity body for the client program. Here is a sample PHP script that shows you how to set header lines for different types of data in the entity body.

<?php #GetFile.php

# $ok = array_key_exists('QUERY_STRING', $_SERVER); if ($ok) { $p = $_SERVER['QUERY_STRING']; $ok = strlen($p)>0 && file_exists($p); } if ($ok) { if (strpos($p,".html")!=false) { header("Content-Type: text/html"); } else if (strpos($p,".gif")!=false) { header("Content-Type: image/gif"); } else if (strpos($p,".pdf")!=false) { header("Content-Type: application/pdf"); } else if (strpos($p,".doc")!=false) { header("Content-Type: application/msword"); } else { $ok = false; } } if ($ok) { header("Content-Length: ".filesize($p)); readfile($p); } else { print("<html><body>Bad request.</body></html>"); }?>

Ideas used in this script:

The objective is to send back the content of the requested file in entity body, and set the Content-Type and Content-Length header lines correctly.

The requested file name is given in the query string of the HTTP request. array_key_exists() is used to make sure the query string is provided to avoid array index error.

The extension of the requested file name is checked to determine the Content-Type header line. strpos() is used as a Boolean value to check the file name extension.

Then the requested file size is checked to set the Content-Length header line.

Then the requested file is outputted to the HTTP response with a single function readfile(). This function name is a little bit misleading, but the function is very useful.

90 Naresh i Technologies

Page 91: Hypertext Preprocessor Demystified

PHP Course Material

If any thing goes wrong, a HTML entity is returned with an error message. A Boolean variable $ok is used to monitor the error condition.

Now let's see how this page works. Assuming I have GetFile.php, hello.html, dot.gif, hello.pdf, and hello.doc copied to c:\inetpub\wwwroot directory. Of course, my IIS is configured to the PHP engine.

1. Use IE (Internet Explorer) to request: http://localhost/GetFile.php?hello.html, you should see the hello message properly displayed as a HTML document.

2. Use IE to request: http://localhost/GetFile.php?dot.gif, you should see a tiny dot displayed as an image.

3. Use IE to request: http://localhost/GetFile.php?hello.pdf, you should see IE calling Adobe Reader to display the hello message as a PDF document.

4. Use IE to request: http://localhost/GetFile.php?hello.doc, you should see IE calling MS Word to display the hello message as a MS Word document.

5. Use IE to request: http://localhost/GetFile.php?any.file, you should see IE displaying an error message. The reason, of course, is that the requested file doesn't exist.

6. Use IE to request: http://localhost/GetFile.php you should see IE displaying an error message. The reason is that there is no query string in the HTTP request.

Content-Disposition: - Sending Files for Downloading

This section provides a tutorial example on how to insert the 'Content-Disposition:' header line in a HTTP response to tell the browser to prompt the user the download and save the response entity body as a file.

In the previous section, the requested file is delivered to the browser for opening immediately. HTTP does also support another header line called "Content-Disposition" which tells the browser to not open the file immediately, but prepare for downloading the entity body. The following script will show you how to do this:

<?php #GetFile.php

# $ok = array_key_exists('QUERY_STRING', $_SERVER); if ($ok) { $p = $_SERVER['QUERY_STRING']; $ok = strlen($p)>0 && file_exists($p); } if ($ok) { if (strpos($p,".html")!=false) { header("Content-Type: text/html"); } else if (strpos($p,".gif")!=false) { header("Content-Type: image/gif"); } else if (strpos($p,".pdf")!=false) {

91 Naresh i Technologies

Page 92: Hypertext Preprocessor Demystified

PHP Course Material header("Content-Type: application/pdf"); } else if (strpos($p,".doc")!=false) { header("Content-Type: application/msword"); } else { $ok = false; } } if ($ok) { header("Content-Length: ".filesize($p)); header("Content-disposition: attachment; filename=".$p); readfile($p); } else { print("<html><body>Bad request.</body></html>"); }?>

In this page, anther header line, "Content-Disposition", is added to the response, in which I am telling the client program that the entity data is an attachment, with file name specified.

Now try to use IE to request http://localhost/Download.php?hello.pdf, you will see IE prompting you to save the attachment instead of calling Adobe Reader to display the data.

Try to use IE to request http://localhost/Download.php?other_existing_file, you will see IE prompting you to save the attachment. The script is working correctly.

MySQL Server Connection and Access Functions

This chapter provides tutorial examples and notes about MySQL server connection with PHP. Topics include configuring the PHP engine to use the MySQL extension library, commonly used MySQL functions, running SQL statements to create table, insert rows and fetch rows.

Configuring PHP for MySQL Server Access

mysql_connect() and Other MySQL Functions

92 Naresh i Technologies

Page 93: Hypertext Preprocessor Demystified

PHP Course Material

MySqlLoop.php - MySQL Functions Test

Conclusion:

PHP supports MySQL through an extension library, php_mysql.dll. Configuring the PHP engine to work with a MySQL server is simple - just turn on the

extension=php_mysql.dll in php.ini.

A database connection resource must be created with the mysql_connect() function.

You can execute any SQL statements using the mysql_query() function.

Configuring PHP for MySQL Server Access

This section provides a tutorial example on how to configure the PHP engine for MySQL server connection access. Setting, extension=php_mysql.dll, needs to be turned in the configuration file php.ini.

To use PHP with MySQL servers, of course you need to install a MySQL server on you system first. On my local system, I have a MySQL server installed in \mysql directory. If you need help on installing a MySQL server on your system, please read my other tutorial book, "Herong's Notes on SQL".

To make sure my MySQL server is running on my local system, I executed commands below to start my MySQL server and check its status:

>\mysql\bin\mysqld

>\mysql\bin\mysqladmin pingmysqld is alive

Now edit \php\php.ini with:

extension=php_mysql.dll

Then I added \php\ext to the PATH system environment variable, because php_mysql.dll is located in the \php\ext directory.

When I was ready to test the configuration, I ran this script:

<?php # MySqlTest.php

# $con = mysql_connect('localhost'); print "MySQL server info = ".mysql_get_server_info()."\n"; print "MySQL status = ".mysql_stat()."\n"; mysql_close($con);?>

I got this output:

93 Naresh i Technologies

Page 94: Hypertext Preprocessor Demystified

PHP Course MaterialC:\herong\php_20050403\src>php MySqlTest.phpMySQL server info = 5.0.2-alphaMySQL status = Uptime: 1167 Threads: 1 Questions: 5 Slow querie... Flush tables: 1 Open tables: 0 Queries per second avg: 0.004

Cool, this confirmed that my PHP engine configured to access my MySQL server.

mysql_connect() and Other MySQL Functions

This section describes functions supported by the MySQL extension library, php_mysql.dll. mysql_connect() creates a connection to the specified MySQL server.

PHP's MySQL support comes from an extension library, php_mysql.dll, which offers a number of functions:

mysql_connect() - Connects to a MySQL server, and returns a connection resource. In most cases, you need to call it with 3 arguments like mysql_connect($server, $username, $password). $server specifies the network address of machine where the MySQL server is running. $username specifies the user login name on the MySQL server. $password specifies the password for the login name.

mysql_close() - Closes a MySQL connection resource. Usually, you call it with 1 parameter like mysql_close($connection), where $connection represents the connection resource to be closed.

mysql_get_server_info() - Returns a string of server information.

mysql_status() - Returns a string of server status.

mysql_query() - Sends a query to the server, and returns a result set resource. For example, mysql_query('SELECT * FROM MyTable WHERE ID = 10').

mysql_affected_rows() - Returns the number of effected rows of the given result set, if the executed query is an INSERT or UPDATE statement.

mysql_num_rows() - Returns the number of rows of the given result set, if the executed query is a SELECT statement.

mysql_fetch_array() - Fetches a row from a given result set, and returns the row as an array with both numeric index, and column name map. It will return boolean false, if there is no row left in the result set.

mysql_free_result() - Frees the given result set.

MySqlLoop.php - MySQL Functions Test

This section provides a tutorial example on how to use MySQL functions to connect to a MySQL server, and run SQL statements to create a table, insert rows and fetch rows with the MySQL server.

94 Naresh i Technologies

Page 95: Hypertext Preprocessor Demystified

PHP Course Material

To show you how some of those MySQL functions should be used, I wrote this simple script, MySqlLoop.php:

<?php # MySqlLoop.php# # $con = mysql_connect('localhost'); $rs = mysql_query('DROP DATABASE MyBase'); $rs = mysql_query('CREATE DATABASE MyBase'); $rs = mysql_query('USE MyBase'); print "Creating a table...\n"; $rs = mysql_query('CREATE TABLE MyTable (ID INTEGER,' .' Value INTEGER)'); $n = 100; $i = 0; print "Inserting some rows to the table...\n"; while ($i < $n) { $rs = mysql_query('INSERT INTO MyTable VALUES ('.$i.', ' .rand(0,$n-1).')'); $i++; } print "Query some rows from the table...\n"; $rs = mysql_query('SELECT * FROM MyTable WHERE ID < 10'); print " ".mysql_field_name($rs,0)." " .mysql_field_name($rs,1)."\n"; while ($row = mysql_fetch_array($rs)) { print " ".$row[0].' '.$row[1]."\n"; } mysql_free_result($rs); mysql_close($con);?>

Note that if the connection resource is not specified in a query call, the last connection resource will be used. If you run this script, you will get something like:

Creating a table...Inserting some rows to the table...Query some rows from the table... ID Value 0 14 1 91 2 84 3 16 4 88 5 51 6 12 7 19 8 39 9 5

Functions to Manage Directories, Files and Images

This chapter provides tutorial examples and notes about functions to manage directories, files, and images. Topics include directory management functions like mkdir(), file testing functions like is_file(), file input and output functions like fopen(), image file management functions like imagecreatefromgif().

95 Naresh i Technologies

Page 96: Hypertext Preprocessor Demystified

PHP Course Material

opendir() and Directory Management Functions

file_exists() and File Testing Functions

FileExistsTest.php - File Testing Examples

fopen() and File Input/Output Functions

File_Input_Output_Test.php - File Input/Output Examples

readfile() and Special File Handling Functions

imagecreatetruecolor() and GD Imaging Library Functions

ShowPhoto.php - Simple Slid Show Script

Conclusion:

PHP supports directory management functions similar to Unix commands like chdir(), mkdir() and rmdir().

To navigate through the directory tree, you can use opendir() and is_dir() functions.

To obtain detailed information about a file, you can use the stat() function.

To read data from a file, you can use fopen() and fread() functions.

To write data to a file, you can use fopen() and fwrite() functions.

To read image from a GIF file, you can use the imagecreatefromgif() function.

opendir() and Directory Management Functions

This section describes opendir() and other directory management functions. A tutorial example is provided on how to open a directory as a directory resource handle and read its entries with the readdir() function in a loop.

PHP offers the following built-in functions to manage directories of file systems:

chdir($path) - This "change directory" function changes the current directory to the specified path. If the specified path is invalid, it returns FALSE. For example, chdir("/swami/php") changes the current directory to /swami/php.

getcwd() - This "get current working directory" function returns the path name of the current directory.

opendir($path) - This "open directory" function creates and returns a directory resource handle that represents the directory of the specified path. The returned directory resource handle contains a current entry pointer initially set to the position before the first entry of the directory. If the specified path is invalid, it returns FALSE. For example, $dir = opendir("/swami/php") assigns a directory resource handle to $dir represents /swami/php.

96 Naresh i Technologies

Page 97: Hypertext Preprocessor Demystified

PHP Course Material

closedir($dir) - This "close directory" function closes the specified directory resource handle.

readdir($dir) - This "read directory" function moves the internal pointer to the next entry in the directory represented by the specified directory resource handle and returns the entry as a string. If the internal pointer is currently pointing to the end of the directory, it returns FALSE, because there is no next entry.

rewinddir($dir) - This "rewind directory" function resets its internal pointer to the position before the first entry.

scandir($path,$order) - The "scan directory" function returns all entries in the directory of the specified path as an array sorted in the specified order. If $order is not specified or $order=0, entries are sorted alphabetically in ascending order. If $order=0, entries are sorted alphabetically in descending order.

dir($path) - This "directory" class constructor returns a directory object representing the directory of the specified path.

mkdir($path) - This "make directory" function creates a new directory with the specified path.

rmdir($path) - This "remove directory" function removes the directory of the specified path.

To show you how to use some of these functions should be used, I wrote this simple script:

<?php # OpendirTest.php

# $path = "/php";

print "\n First 10 entries in $path:\n"; $dir = opendir($path); $i = 0; while (FALSE !== ($entry = readdir($dir)) && $i<10) { $i++; print " $entry\n"; }

print "\n First 10 entries in $path again:\n"; $dir = dir($path); $i = 0; while (FALSE !== ($entry = $dir->read()) && $i<10) { $i++; print " $entry\n"; }?>

If you run this script, you should get:

First 10 entries in /php: . ..

97 Naresh i Technologies

Page 98: Hypertext Preprocessor Demystified

PHP Course Material chm dev ext extras fdftk.dll fribidi.dll gds32.dll go-pear.bat

First 10 entries in /local/php again: . .. chm dev ext extras fdftk.dll fribidi.dll gds32.dll go-pear.bat

file_exists() and File Testing Functions

This section describes some built-in file testing functions. file_exists() allows you test if a directory or file exists or not. is_file() returns true if the given path is a file, not a directory.

PHP offers a lots of nice built-in functions to test and manage files:

disk_total_space($path) - The "disk total space" function returns the total disk space of the specified path in number of bytes. For example, disk_total_space("/herong") returns the total disk space where /herong is located.

disk_free_space($path) - The "disk free space" function returns the disk free space of the specified path in number of bytes. For example, disk_free_space("/herong") returns the disk free space where /herong is located.

pathinfo($path) - This "path information" function returns information of the specified path in an array with element keys of dirname, basename, extension, and filename.

realpath($path) - This "real path" function returns the absolute path name of $path.

dirname - This "directory name" function returns the directory part of the specified path name. For example, dirname("/herong/html/index.php") returns "/herong/html".

basename($path, $suffix) - This "base name" function returns the file name part of the specified path name with the specified suffix removed. For example, basename("/herong/html/index.php", ".php") returns "index".

file_exists($file) - This "file exists" function returns TRUE, if the specified file exists.

fileatime($file) - This "file access time" function returns the time of when the specified file was last accessed.

98 Naresh i Technologies

Page 99: Hypertext Preprocessor Demystified

PHP Course Material

filemtime($file) - This "file modified time" function returns the time of when the specified file was last modified.

fileperms($file) - This "file permissions" function returns permission settings of the specified file.

filesize($file) - This "file size" function returns the size of the specified file in number of bytes.

filetype($file) - This "file type" function returns the type of the specified file.

stat($path) - This 'statistics" functions returns file information of the specified path in an array with element keys of dev, ino, mode, nlink, uid, gid, rdev, size, atime, mtime, ctime, blksize, and blocks.

is_dir($path) - This "is directory" function returns TRUE, if the specified path is a directory.

is_file($path) - This "is file" function returns TRUE, if the specified path is a file.

is_executable($path) - This "is executable" function returns TRUE, if the specified path is an executable program.

is_readable($path) - This "is readable" function returns TRUE, if the specified path is a readable file.

is_writable($path) - This "is writable" function returns TRUE, if the specified path is a writable file.

copy($source, $dest ) - This "copy" function copies a file specified as the source to a new file specified as the destination.

rename($old_name, $new_name) - This "rename" function renames a file or a directory.

unlink($path) - This "un link" function removes the link to an actual file of the specified path. If this is the last link, the actual file will be removed. unlink() removes the actual file on Windows systems, since links are not supported on Windows systems.

FileExistsTest.php - File Testing Examples

This section provides a tutorial example script on how to use file testing functions like file_exists(), is_dir(), and stat(). The example script displays detailed information of any given file.

To show you how to use some of those file testing functions described in the previous section, I wrote this simple script:

<?php # FileExistsTest.php# if (count($argv) > 1) { $path = $argv[1]; } else {

99 Naresh i Technologies

Page 100: Hypertext Preprocessor Demystified

PHP Course Material print("\n Please specify a file path name.\n"); exit(); }

if (file_exists($path)) { print("\n Very good. $path does exists!.\n");

if (is_dir($path)) { print("\n $path is a directory.\n"); } else if (is_file($path)) { print("\n $path is a file.\n");

$type = filetype($file); $fileInfo = stat($path); print("\n filetype() returns $type\n"); print("\n stat()[size] returns ".$fileInfo['size']."\n"); print("\n stat()[atime] returns ".$fileInfo['atime']."\n"); print("\n stat()[mtime] returns ".$fileInfo['mtime']."\n"); print("\n stat()[ctime] returns ".$fileInfo['ctime']."\n"); } else { print("\n $path is not a directory or a file.\n"); exit(); } } else { print("\n Too bad. $path does not exists!.\n"); exit(); }?>

If you run this sample script with different path names, you should get:

cd \swami\php

C:\swami\php>\php\php FileExistsTest.php \php

Very good. \php does exists!.

\php is a directory.

C:\swami\php>\php\php FileExistsTest.php \php\php.exe

Very good. \php\php.exe does exists!.

\php\php.exe is a file. filetype() returns stat()[size] returns 32821 stat()[atime] returns 1236906289 stat()[mtime] returns 1178148192 stat()[ctime] returns 1178148192

C:\swami\php>\php\php FileExistsTest.php \php\something

Too bad. \php\something does not exists!.

100 Naresh i Technologies

Page 101: Hypertext Preprocessor Demystified

PHP Course Material

fopen() and File Input/Output Functions

This section describes some file input and output built-in functions. fopen() opens a file for reading and writing. fclose() closes an opened file. fread() reads data from input files. fwrite() writes data to output files.

PHP offers a number of built-in functions to read and write files:

fopen($path,$mode) - This "file open" function opens a file at the specified path to read or write data and returns a file resource handle. The $mode argument specifies "r", "w", or "a" as the open mode for reading, writing or appending data to the file. On Windows system, The $mode argument takes another letter, "t" or "b", to control whether the file should be opened in text mode or binary mode. In text mode, the PHP engine will do automatic conversion between \n and \r\n. In binary mode, the PHP engine will not do any conversions. For example, fopen($path,"rb") opens a file for binary reading.

fclose($file) - This "file close" function closes the specified file resource handle.

fread($file,$length) - This "file read" function reads $length number of bytes from $file. and returns input bytes as a string.

fgets($file) - This "file get string" function reads one line from $file and returns it as a string.

feof($file) - This "file end of file" function returns true, if $file is pointing to the end of file currently.

fwrite($file,$data,$length) - This "file write" function writes $length number of bytes from $data to $file.

fscanf($file,$format,$var1,$var2,...) - This "file scan formatted" function parses input data into $var1, $var2,..., according to $format.

fprintf($file,$format,$var1,$var2,...) - This "file print formatted" function writes data from $var1, $var2,..., according to $format.

fflush($file) - This "file flush" function forces all buffered output to be written the actual $file.

ftruncate($file) - This "file truncate" function truncates $file to a given length.

ftell($file) - This "file tell" function returns the current position of the $file pointer in the actual file as an offset from the beginning of the file.

fseek($file,$offset) - This "file seek" function moves $file to the $offset position in the actual file.

rewind($file) - This "rewind" function $file position to beginning of the actual file.

flock($file,$locker) - This "file lock" function applies a locker on $file. 4 locker types are supported: LOCK_SH, LOCK_EX, LOCK_UN, and LOCK_NB.

101 Naresh i Technologies

Page 102: Hypertext Preprocessor Demystified

PHP Course Material

($file) - This "file statistics" function returns an array containing statistics information about $file. The returned array contains element keys of dev, ino, mode, nlink, uid, gid, rdev, size, atime, mtime, ctime, blksize, and blocks.

fgetc($file) - This "file get character" function reads 1 byte and return it as a string.

File_Input_Output_Test.php - File Input/Output Examples

This section provides a tutorial example script on how to use file input and output functions like fopen(), fread(), fwrite(), and fclose(). The example script copies any file in binary mode.

To show you how to use some of those file testing functions described in the previous section, I wrote this simple script:

<?php # File_Input_Output_Test.php# if (count($argv) > 1) { $path = $argv[1]; } else { print("\n Please specify a file path name.\n"); exit(); }

if (file_exists($path)) { print("\n Good. $path does exists!.\n");

if (is_file($path)) { print("\n Very good. $path is a file.\n");

print("\n Starting to copy $path to $path.bck...\n"); $input = fopen($path,"rb"); # For binary read $output = fopen($path.".bck","wb"); # For binary write $inCount = 0; $outCount = 0; while (!feof($input)) { $buffer = fread($input,1024); $inCount += strlen($buffer); $outCount += fwrite($output,$buffer); } fclose($input); fclose($output);

print(" # of bytes read: $inCount\n"); print(" # of bytes write: $outCount\n"); } else { print("\n Too bad. $path is not a file.\n"); exit(); } } else { print("\n Bad. $path does not exists!.\n"); exit(); }?>

If you run this sample script with different path names, you should get:

102 Naresh i Technologies

Page 103: Hypertext Preprocessor Demystified

PHP Course Materialcd \swami\php

C:\swami\php>\php\php File_Input_Output_Test.php \php\php.exe

Good. \php\php.exe does exists!.

Very good. \php\php.exe is a file.

Starting to copy \php\php.exe to \php\php.exe.bck... # of bytes read: 32821 # of bytes write: 32821

C:\swami\php>\php\php File_Input_Output_Test.php \php

Good. \php does exists!.

Too bad. \php is not a file.

readfile() and Special File Handling Functions

This section describes some special file handling functions. readfile() copies a file to standard output. fgetss() reads a line with tags removed. tmpfile() opens a temporary file. file() reads a file into an array.

PHP also offers a number of other built-in functions to perform some special file input and output tasks:

file_get_contents($path) - This "file get contents" returns the entire content of the specified file as a string.

file_put_contents($path, $data) - This "file put contents" writes the specified data to the specified file.

file($path) - This "file" function returns the entire content of the specified file as an array. Each element in the array represents one line in the file.

readfile($path) - This "read file" function reads the entire content of a file and writes to the standard output.

fpassthru($file) - This "file pass through" function reads remaining data from $file and writes to the standard output.

fgetss($file) - This "file get string strip" function reads one line from $file and returns it as a string with HTML and PHP tags stripped off.

fgetcsv($file) - This "file get CSV" function reads one line from $file and returns it as an array by parsing the line in CSV format into array elements.

fputcsv($file,$array) - This "file put CSV" function writes elements from $array to $file in CSV format.

103 Naresh i Technologies

Page 104: Hypertext Preprocessor Demystified

PHP Course Material

tmpfile() - This "temporary file" function opens a temporary file in read-write (w+) mode and returns the file resource handle. This temporary file will be removed with its file resource handle is closed.

tempnam($path,$prefix) - This "temporary name" function creates a temporary file name in $path with a $prefix.

imagecreatetruecolor() and GD Imaging Library Functions

This section describes some GD Imaging library functions. imagecreatetruecolor() creates an image in true color mode. imagecreatefromgif() creats an image from a GIF file. imagegif() writes an image to a GIF file. imagerotate() rotates an image. imagecopyresized() copies and resizes an image.

If you are interested in managing image files, you enable the GD Imaging library by turning on the extension=php_gd2.dll setting in php.ini.

The GD Imaging library offers a lots of nice functions to manage image files:

gd_info() - This "GD information" function returns information about the GD Imaging library as an array.

imagecreate($width,$height) - This "image create" function creates a blank image object.

imagecreatetruecolor($width,$height) - This "image create true color" function creates a blank image object with in true color mode, which uses RGB color format with 256 value for each color component.

imagecreatefromgif($path) - This "image create from GIF" function creates an image object from a GIF image file.

imagecreatefromjpeg($path) - This "image create from JPEG" function creates an image object from a JPEG (JPG) image file.

imagecreatefromwbmp($path) - This "image create from BMP" function creates an image object from a BMP image file.

imagegif($image,$path) - This "image GIF" function writes an image object to a GIF image file.

imagejpeg($image,$path) - This "image JPEG" function writes an image object to a JPEG (JPG) image file.

imagerotate($image,$angle,$color) - This "image rotate" function rotates an image object of $angle degrees and returns the rotated image. $color is used to fill uncovered area after the rotation.

imagesx($image) - This "image size x" function returns the width of $image.

imagesy($image) - This "image size y" function returns the height of $image.

imagedestroy($image) - This "image destroy" function descries an image object.

104 Naresh i Technologies

Page 105: Hypertext Preprocessor Demystified

PHP Course Material

imagecopyresized($dst_image,$src_image, $dst_x,$dst_y, $src_x,$src_y, $dst_w,$dst_h, $src_w,$src_h) - This "image copy resized" function copies a part of an image from $src_image to $dst_image. $src_x and $src_y specifies the copy-from location. $dst_x and $dst_y specifies the copy-to location. $src_w and $src_h specifies the copy-from size. $dst_w and $dst_h specifies the copy-to size. If the copy-to size is larger or smaller than the copy-from size, the copied part will be resized.

imagecopyresampled($dst_image,$src_image, $dst_x,$dst_y, $src_x,$src_y, $dst_w,$dst_h, $src_w,$src_h) - This "image copy resampled" function does the same job as imagecopyresized() with a better qualit.

imagecopy($dst_image,$src_image, $dst_x,$dst_y, $src_x,$src_y, $src_w,$src_h) - This "image copy" function does the same job as imagecopyresized() except that the copied part will not be resized.

imagecopymerge($dst_image,$src_image, $dst_x,$dst_y, $src_x,$src_y, $src_w,$src_h, $percentage) - This "image copy merge" function does the same job as imagecopy() except that the copied part will be merged to $dst_image with a $percentage factor.

imagecolortransparent($image,$color) - This "image color transparent" function sets new color as the transparent color.

imagecolorat($image, $x,$y) - This "image color at" function returns the color value from $image at $x and $y position. In true color mode, the returned $rgb value can be decomposed as $r = ($rgb >> 16) & 0xFF, $g = ($rgb >> 8) & 0xFF, and $b = $rgb & 0xFF.

imagecolorsforindex(image, $color) - This "image color for index" function return RGB color values and alpha key of the specified color index.

imagesetpixel($image, $x,$y, $color) - This "image set pixel" function set one pixel at $x and $y with $color.

imagefill($image, $x,$y, $color) - This "image fill" function performs a flood fill at $x and $y position with a given $color.

imagecolorallocate($image, $r,$g,$b) - This "image color allocate" function allocates a color index with $r, $g and $b values. The allocated color index is returned.

imagecolorallocatealpha($image, $r,$g,$b, $alpha) - This "image color allocate alpha" function does the same job as imagecolorallocate() except that it applies a transparency parameter $alpha between 0, completely opaque, and 127, completely transparent.

imagestring($image, $font, $x,$y, $string, $color) - This "image string" function draws a $string horizontally at $x and $y with $font in $color.

imagettftext($image, $size, $angle, $x,$y, $color, $font, $text) - This "image TTF Text draws a $text at $x and $y with a $font of $size in a $color at an $angle.

imageline($image, $x1,$y1, $x2,$y2, $color) - This "image line" function draws a line in a $color.

105 Naresh i Technologies

Page 106: Hypertext Preprocessor Demystified

PHP Course Material

imagerectangle($image, $x1,$y1, $x2,$y2, $color) - This "image rectangle" function draws a retangle in a $color.

ShowPhoto.php - Simple Slid Show Script

This section provides a tutorial example on how to display image files in a directory in a slide show format. The getimagesize() function is used to retrieve image sizes from image files.

Another nice function for image file management is the "get image size" function, getimagesize($path), which returns the size and other information about the image stored in a file located at $path.

To show you how to use this getimagesize() function, I wrote the following sample script:

<?php # PhotoShow.php# #- Get the photo file name $i = intval($_GET['i']); $c = 0; $p = ""; if ($d = opendir(".")) { while (($f = readdir($d)) != false) { if (preg_match('/.jpg$/',$f)) { if ($i==$c) { $p = $f; } $c++; } } closedir($d); }

#- Build the page $h = fopen("header.html", "r"); $s = fread($h, filesize("header.html")); fclose($h); print "$s\n";

if (strlen($p)>0) { $i1 = ($i+$c-1) % $c; $i2 = ($i+$c+1) % $c; list($width, $height, $type, $attr) = getimagesize($p); if ($width>700) { $width = $width/2; $height = $height/2; } print "<center><a href=\"ShowPhoto.php?i=$i1\"><=</a>&nbsp;" ."<a href=\"ShowPhoto.php?i=$i2\">=></a></center>\n" ."<center><img src=\"$p\" border=\"1\" width=\"$width\" " ."height=\"$height\"></center><br\>\n" ."<center><a href=\"ShowPhoto.php?i=$i1\"><=</a>&nbsp;" ."<a href=\"ShowPhoto.php?i=$i2\">=></a></center>\n"; } else { print "<p>Wrong URL. Please go back to the home page.</p>\n"; }

106 Naresh i Technologies

Page 107: Hypertext Preprocessor Demystified

PHP Course Material $h = fopen("footer.html", "r"); $s = fread($h, filesize("footer.html")); fclose($h); print "$s\n";?>

This script will display image files stored in a directory one image at a time like a slid show.

Try it out. It's very easy to use. You can easily customize it to meet your requirements.

SOAP Extension Function and Calling Web Services

This chapter provides tutorial examples and notes about SOAP extension functions. Topics include PHP implementations of SOAP, the SOAP extension library, SOAP client functions, Calling Web services with and without using the WSDL standard, example scripts to dump SOAP communication detailed debug information.

PHP Implementations of SOAP

Turning on the Default SOAP Extension

Get_Temperature.php - First Example of SOAP

SoapClient - SOAP Client Class and Functions

Get_Temperature_Dump.php - Dumping Debugging Information

What Is WSDL?

Using SOAP Extension in non-WSDL Mode

Conclusion:

There seems to be 3 popular PHP implementations of SOAP: PEAR SOAP, NuSOAP, and PHP Group SOAP Extension.

The PHP Group SOAP Extension 5.0.4 seems to be supporting SOAP 1.2. But it uses SOAP 1.1 by default.

WSDL is an XML based standard designed to describes protocol bindings and message formats of Web services.

WSDL document does help simplifying the set up process of SOAP calls. But without WSDL documents, making SOAP calls is not that hard.

www.xmethods.net is doing a great job for offering this demonstration SOAP service.

Exercise: Go to http://www.xmethods.net/ and play with another demonstration Web service called: Delayed Stock Quote.

107 Naresh i Technologies

Page 108: Hypertext Preprocessor Demystified

PHP Course Material

PHP Implementations of SOAP

This section describes the SOAP protocol and PHP implementations of SOAP. PEAR::Package::SOAP, NuSOAP, and php_soap.dll (from the PHP Group) seems to be 3 different SOAP implementations.

What Is SOAP? SOAP (Simple Object Access Protocol) is an XML based protocol intended for exchanging structured information in a distributed application environment.

If you search the Web with key words of "PHP Implementation of SOAP", you will find two popular implementations:

PEAR::Package::SOAP at http://pear.php.net/package/SOAP. Current release: 2005-05-31 - Version 0.9.1 (beta).

NuSOAP - SOAP Toolkit for PHP at http://sourceforge.net/projects/nusoap/. Current release: August 4, 2005 - Version 0.7.2.

But when I looked at my PHP installation, I found that a SOAP extension library is included in the PHP distribution package:

>dir \php\ext\php_soap.dll

03/31/2005 02:52 AM 217,146 php_soap.dll

Unfortunately, I could not find any good article discussing differences among these 3 implementations: PEAR::Package::SOAP, NuSOAP, and php_soap.dl

Turning on the Default SOAP Extension

This section provides a tutorial example on how to turn on the SOAP extension inluded in the default distribution package - extension=php_soap.dll in the php.ini file.

The PHP distribution package comes with a default SOAP extension library. But it is not turned on automatically. I did the following test to see if SOAP turned on or not with the phpinfo() function:

>type PhpInfo.php <?php phpinfo();?>

>php PhpInfo.php > PhpInfo.txt

>find /? "soap" PhpInfo.txt---------- PHPINFO.TXT

>php -vPHP 5.0.4 (cli) (built: Mar 31 2005 02:45:48)Copyright (c) 1997-2004 The PHP GroupZend Engine v2.0.4-dev, Copyright (c) 1998-2004 Zend Technologies

108 Naresh i Technologies

Page 109: Hypertext Preprocessor Demystified

PHP Course Material

So SOAP function is not available in my default installation, which is PHP 5.0.4 by The PHP Group.

The next thing I did is to to turn on the SOAP extension by editing \php\php.ini and insert the following line:

extension=php_soap.dll

I checked again:

>php PhpInfo.php > PhpInfo.txt

>find /? "soap" PhpInfo.txt---------- PHPINFO.TXTsoapSoap Client => enabledSoap Server => enabledsoap.wsdl_cache_dir => /tmp => /tmpsoap.wsdl_cache_enabled => 1 => 1soap.wsdl_cache_ttl => 86400 => 86400

Cool. Some settings related to SOAP showed up now.

The next question is what SOAP implementation is this php_soap.dll. Is it PEAR SOAP, NuSOAP, or something else? To check this out, I right-mouse clicked on the file \php\ext\php_soap.dll, and selected Properties. The pop up window told me this:

Internal Name: php_soap.dllFile Version: 5.0.4.4Copyright (c) 1997-2004 The PHP Group

So the php_soap.dll is indeed another PHP implementation of SOAP. Let's call it the PHP Group SOAP. I then browsed the installed documentation at \php\html\ref.soap.html, and got the following information:

SOAP Functions

Introduction

The SOAP extension can be used to write SOAP Servers and Clients. It supports subsets of SOAP 1.1, SOAP 1.2 and WSDL 1.1 specifications.

Get_Temperature.php - First Example of SOAP

This section provides a tutorial example on how to use the SOAP extension to call a Web service provided by xmethods.org to get the current temperature.

To show you an example of how PHP SOAP extension can be used in a SOAP client application, here is my first SOAP PHP script, Get_Temperature.php

109 Naresh i Technologies

Page 110: Hypertext Preprocessor Demystified

PHP Course Material<?php # Get_Temperature.php

# $client = new SoapClient ("http://www.xmethods.net/sd/2001/DemoTemperatureService.wsdl"); echo("\nReturning value of getTemp() call: ". $client->getTemp("12345"));?>

Run it while your connected to the Internet. You will get:

>php Get_Temperature.php

Returning value of getTemp() call: 52

Very nice. This confirms that:

PHP SOAP extension is easy to use. Two statements are enough to call a SOAP service. You PHP SOAP extension is installed correctly and working.

PHP SOAP extension supports WSDL.

www.xmethods.net is doing a great job for offering this demonstration SOAP service.

SoapClient - SOAP Client Class and Functions

This section describes the SoapClient class and functions provided in the SOAP extension library for writing SOAP client application. __soapCall() allows you to make a RPC function call on the target SOAP node.

If you read the SOAP Extension reference page, you will see that SOAP extension support SOAP client applications with a class called SoapClient, which offers the following functions:

SoapClient->__construct() - constructs a new SoapClient object SoapClient->__soapCall() - Calls a SOAP function

SoapClient->__getFunctions() - Returns list of SOAP functions

SoapClient->__getLastRequestHeaders() - Returns last SOAP request headers

SoapClient->__getLastRequest() - Returns last SOAP request

SoapClient->__getLastResponseHeaders() - Returns last SOAP response headers

SoapClient->__getLastResponse() - Returns last SOAP response

...

SoapClient->__construct() allows you to construct a new SoapClient object with the following syntax:

__construct ( mixed wsdl [, array options] );

110 Naresh i Technologies

Page 111: Hypertext Preprocessor Demystified

PHP Course Material

where "wsdl" specifies the URL of the WSDL document, and "options" specifies a list of options:

'location' => "...", # the URL where to send the request 'uri' => "...", # the name space of the SOAP service 'soap_version' => SOAP_1_1 | SOAP_1_2, 'trace' => 0 | 1, ...

Note that SoapClient object can be constructed in two modes, WSDL mode and non-WSDL mode:

__construct( "..."[, array options] ); # WSDL mode, many options # are provided by the WSDL document __construct( null, array options ); # non-WSDL mode, 'location' # and 'uri' are required options.

SoapClient->__getFunctions() allows you to get a list of functions supported by the target node. This function is only valid in WSDL mode:

array $a = $obj->__getFunctions();

SoapClient->__soapCall() allows you to make a RPC function call on the target SOAP node.

$obj->__soapCall(string func_name[, array arguments [, ...]]);

Note that in WSDL mode, you can also make a RPC call as a local method on the SoapClient object:

$obj->func_name(arg1, arg2, ...);

SoapClient->__getLastRequestHeaders() allows you to retrieve the HTTP request header lines of the last SOAP request executed. This function works only if the SoapClient object was created with the option of "trace=1".

string $s = $obj->__getLastRequestHeaders();

SoapClient->__getLastRequest() allows you to retrieve SOAP request message of the last SOAP request executed. This function works only if the SoapClient object was created with the option of "trace=1".

string $s = $obj->__getLastRequest();

SoapClient->__getLastResponseHeaders() allows you to retrieve the HTTP response header lines of the last SOAP request executed. This function works only if the SoapClient object was created with the option of "trace=1".

string $s = $obj->__getLastRequestHeaders();

111 Naresh i Technologies

Page 112: Hypertext Preprocessor Demystified

PHP Course Material

SoapClient->__getLastResponse() allows you to retrieve SOAP response message of the last SOAP request executed. This function works only if the SoapClient object was created with the option of "trace=1".

string $s = $obj->__getLastResponse();

Get_Temperature_Dump.php - Dumping Debugging Information

This section provides a tutorial example on how to use SOAP client functions to make Web service call on the target SOAP node and print detailed debug information.

After learning the basic functions of the SoapClient class, I revised my Get_Temperature.php client program to get more information on how SOAP Extension works, and to show you how to debug a SOAP client program. The new client program is called, Get_Temperature_Dump.php:

<?php # Get_Temperature_Dump.php# # $zip = "123456"; $client = new SoapClient ("http://www.xmethods.net/sd/2001/DemoTemperatureService.wsdl", array('trace' => 1));

echo("\nDumping client object:\n"); var_dump($client);

echo("\nDumping client object functions:\n"); var_dump($client->__getFunctions());

$return = $client->getTemp($zip); echo("\nReturning value of getTemp() call: ".$return);

$return = $client->__soapCall("getTemp",array($zip)); echo("\nReturning value of __soapCall() call: ".$return);

echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders());

echo("\nDumping request:\n".$client->__getLastRequest());

echo("\nDumping response headers:\n" .$client->__getLastResponseHeaders());

echo("\nDumping response:\n".$client->__getLastResponse());?>

If you run this sample script, you will get:

Dumping client object:object(SoapClient)#1 (3) { ["trace"]=> int(1) ["_soap_version"]=> int(1) ["sdl"]=> resource(5) of type (Unknown)

112 Naresh i Technologies

Page 113: Hypertext Preprocessor Demystified

PHP Course Material}

Dumping client object functions:array(1) { [0]=> string(30) "float getTemp(string $zipcode)"}

Returning value of getTemp() call: 52

Returning value of __soapCall() call: 52

Dumping request headers:POST /soap/servlet/rpcrouter HTTP/1.1Host: services.xmethods.netConnection: Keep-AliveUser-Agent: PHP SOAP 0.1Content-Type: text/xml; charset=utf-8SOAPAction: ""Content-Length: 510Cookie: JSESSIONID=uuqkGDvtzw_IPlMLsodnVX9j;

Dumping request:<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethods-Temperature-Demo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body><ns1:getTemp> <zipcode xsi:type="xsd:string">123456</zipcode> </ns1:getTemp></SOAP-ENV:Body></SOAP-ENV:Envelope>

Dumping response headers:HTTP/1.1 200 OKServer: Enhydra-MultiServer/3.1.1b1Status: 200Content-Type: text/xml; charset=utf-8Servlet-Engine: Enhydra Application Server/3.1.1b1 (JSP 1.1; Servlet 2.2; Java 1.4.2_03; Linux 2.4.7-10smp i386; java.vendor=Sun Microsystems Inc.)Content-Length: 470X-Cache: MISS from www.xmethods.netKeep-Alive: timeout=15, max=99Connection: Keep-Alive

Dumping response:<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Body><ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature-Demo" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

113 Naresh i Technologies

Page 114: Hypertext Preprocessor Demystified

PHP Course Material<return xsi:type="xsd:float">52.0</return></ns1:getTempResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

The output is very useful. It confirms that:

The default SOAP version is SOAP 1.1. For SOAP 1.2, the envelope namespace should be http://www.w3.org/2003/05/soap-envelope, not http://schemas.xmlsoap.org/soap/envelope/.

The transportation protocol is HTTP/1.1. See the request header lines.

There is only one RPC function supported in this WSDL: "float getTemp(string $zipcode)". See the __getFunctions() dump.

SOAP Extension converts my getTemp() RPC call nicely in a SOAP request message based on the definitions in the WSDL document.

The returning value is also converted properly into a "float" type of value, not a "string". The SOAP response message shows "52.0", but the print out of $return is "52".

What Is WSDL?

This section describes what is WSDL - an XML based standard designed to describes protocol bindings and message formats of Web services.

What Is WSDL? WSDL (Web Services Definition Language) is an XML based standard designed to describes protocol bindings and message formats of Web services. WSDL is often pronounced as "Whiz-Dull".

A WSDL document is an XML document written in WSDL to describe Web service. Here is a copy of the WSDL document for the demonstration Web service used in previous sections. You can download one yourself by going to http://www.xmethods.net/sd/2001/DemoTemperatureService.wsdl with your Web browser:

<?xml version="1.0"?><definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="getTempRequest"> <part name="zipcode" type="xsd:string"/> </message> <message name="getTempResponse"> <part name="return" type="xsd:float"/> </message> <portType name="TemperaturePortType"> <operation name="getTemp"> <input message="tns:getTempRequest"/> <output message="tns:getTempResponse"/> </operation>

114 Naresh i Technologies

Page 115: Hypertext Preprocessor Demystified

PHP Course Material </portType> <binding name="TemperatureBinding" type="tns:TemperaturePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getTemp"> <soap:operation soapAction=""/> <input> <soap:body use="encoded" namespace="urn:xmethods-Temperature-Demo" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="urn:xmethods-Temperature-Demo" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="TemperatureService"> <documentation>Returns current temperature in a given U.S. zipcode </documentation> <port name="TemperaturePort" binding="tns:TemperatureBinding"> <soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/> </port> </service></definitions>

I cannot read this document well before learning the WSDL specifications. But it seems to be describing precisely how this Web service should be used. See my other book: "Herong's Tutorial Notes on Web Service and SOAP" for more information on SOAP and WSDL.

Using SOAP Extension in non-WSDL Mode

This section provides a tutorial example on how to use SOAP client functions to make Web service call without using the WSDL standard on the target SOAP node and print detailed debug information.

I think we had enough fun with the WSDL mode. Let's try the non-WSDL mode now. Here is the third version of my Get_Temperature.php SOAP client program, Get_Temperature_Non_Wsdl.php:

<?php # Get_Temperature_Non_Wsdl.php# $zip = "123456"; $client = new SoapClient(null, array( 'location' => "http://services.xmethods.net:80/soap/servlet/rpcrouter", 'uri' => "urn:xmethods-Temperature-Demo", 'trace' => 1 ));

echo("\nDumping client object:\n"); var_dump($client);

$return = $client->__soapCall("getTemp",array($zip));

115 Naresh i Technologies

Page 116: Hypertext Preprocessor Demystified

PHP Course Material echo("\nReturning value of __soapCall() call: ".$return);

echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders());

echo("\nDumping request:\n".$client->__getLastRequest());

echo("\nDumping response headers:\n" .$client->__getLastResponseHeaders());

echo("\nDumping response:\n".$client->__getLastResponse());?>

If you run this sample script, you will get:

Dumping client object:object(SoapClient)#1 (4) { ["uri"]=> string(29) "urn:xmethods-Temperature-Demo" ["location"]=> string(54) "http://services.xmethods.net:80/soap/servlet/rpcrouter" ["trace"]=> int(1) ["_soap_version"]=> int(1)}

Returning value of __soapCall() call: 52

Dumping request headers:POST /soap/servlet/rpcrouter HTTP/1.1Host: services.xmethods.netConnection: Keep-AliveUser-Agent: PHP SOAP 0.1Content-Type: text/xml; charset=utf-8SOAPAction: "urn:xmethods-Temperature-Demo#getTemp"Content-Length: 508

Dumping request:<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethods-Temperature-Demo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body><ns1:getTemp> <param0 xsi:type="xsd:string">123456</param0> </ns1:getTemp></SOAP-ENV:Body></SOAP-ENV:Envelope>

Dumping response headers:HTTP/1.1 200 OKDate: Wed, 05 Oct 2005 02:02:46 GMTServer: Enhydra-MultiServer/3.1.1b1Status: 200Content-Type: text/xml; charset=utf-8

116 Naresh i Technologies

Page 117: Hypertext Preprocessor Demystified

PHP Course MaterialServlet-Engine: Enhydra Application Server/3.1.1b1 (JSP 1.1; Servlet 2.2; Java 1.4.2_03; Linux 2.4.7-10smp i386; java.vendor=Sun Microsystems Inc.)Content-Length: 470Set-Cookie: JSESSIONID=RTiE9NZhFiqCdnPB36zgsXMi;Path=/soapX-Cache: MISS from www.xmethods.netKeep-Alive: timeout=15, max=100Connection: Keep-Alive

Dumping response:<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Body><ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature-Demo" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><return xsi:type="xsd:float">52.0</return></ns1:getTempResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

The output shows that:

My Get_Temperature_Non_Wsdl.php works the same as the WSDL mode version. If you compare this output with the WSDL output, SOAP Extension generates the request

headers with one difference: SOAPAction is not blank any more. It has the value of "urn:xmethods-Temperature-Demo#getTemp".

SOAP Extension also generates the request message differently in non-WSDL mode. The input parameter is provided with an element named as "param0". In the WSDL version, that element is named as "zipcode".

SOAP Server Functions and Examples

This chapter provides tutorial examples and notes about SOAP server functions and examples. Topics include introduction to SOAP server class and functions, SOAP server example - HelloServer.php, server examples with SOAP 1.1 and 1.2, server example in WSDL mode.

SoapServer - SOAP Server Class and Functions

HelloServer.php - First SOAP Server Application

HelloServer12.php - First SOAP 1.2 Server Application

HelloServerWsdl.php - SOAP 1.2 Server Application in WSDL Mode

Conclusion:

SOAP Extension is easy to use for setting up SOAP server to provide Web services quickly.

117 Naresh i Technologies

Page 118: Hypertext Preprocessor Demystified

PHP Course Material

SOAP Extension does support SOAP 1.1 and 1.2 specifications.

WSDL document is actually easy to understand.

Exercise: Write a temperature conversion SOAP service.

SoapServer - SOAP Server Class and Functions

This section describes the SoapServer class and functions provided in the SOAP extension library for writing SOAP server application.

If you read the SOAP Extension reference page, you will see that SOAP Extension support SOAP server applications with a class called SoapServer, which offers the following functions:

SoapServer->__construct() - construct a new SoapServer object SoapServer->addFunction() - Adds one or several functions those will handle SOAP

requests

SoapServer->setClass() - Sets class which will handle SOAP requests

SoapServer->handle() - Handles a SOAP request

SoapServer->getFunctions() - Returns list of defined functions

...

SoapServer->__construct() allows you to construct a new SoapServer object with the following syntax:

__construct ( mixed wsdl [, array options] );

where "wsdl" specifies the URL of the WSDL document, and "options" specifies a list of options:

'uri' => "...", # the name space of the SOAP service 'soap_version' => SOAP_1_1 |SOAP_1_2, 'actor' => "...", # the actor 'encoding' => "...", # the encoding name 'classmap' => "...", # a map of WSDL types to PHP classes ...

Note that SoapServer object can be constructed in two modes, WSDL mode and non-WSDL mode:

__construct( "..."[, array options] ); # WSDL mode, many options # are provided by the WSDL document __construct( null, array options ); # non-WSDL mode, # 'uri' is a required option.

SoapServer->addFunction() allows you to add one or more functions to handle SOAP requests. The functions to be added are functions defined in the current PHP program file.

118 Naresh i Technologies

Page 119: Hypertext Preprocessor Demystified

PHP Course Material $obj->addFunction("func"); # adds one function $obj->addFunction(array("func1",...)); # adds many functions $obj->addFunction(SOAP_FUNCTIONS_ALL); # adds all functions

SoapServer->setClass() allows you to call methods in the specified class to handle SOAP requests.

$obj->setClass("cls");

SoapServer->handle() allows you to return the execution back the SOAP Extension to handle the incoming SOAP request.

$obj->handle();

SoapServer->getFunctions() allows you to get a list of all functions that have been assigned to handle SOAP requests.

array $a = $obj->getFunctions();

HelloServer.php - First SOAP Server Application

This section provides a tutorial example on how to write a simple SOAP server application. The HelloServer.php example defines a hello() function, adds it to the SOAP server, waits for the client program to call.

Okay. Now let's build our first SOAP server. I want the first server to perform a very simple function of return a greeting string based on the input name. Here is my version called, HelloServer.php:

<?php # HelloServer.php

#function hello($someone) { return "Hello " . $someone . "!";} $server = new SoapServer(null, array('uri' => "urn://www.herong.home/res")); $server->addFunction("hello"); $server->handle(); ?>

The sever application is ready. Note that:

This SOAP server application can not be used as a standalone SOAP server. It needs a HTTP server to receive SOAP requests, and a PHP runtime to act as a CGI to feed SOAP requests.

The "uri" value is just an unique identification, used as the namespace for the response message.

119 Naresh i Technologies

Page 120: Hypertext Preprocessor Demystified

PHP Course Material

The HTTP server I will be using is the MS IIS (Internet Information Services). It has already configured correctly to interface with PHP CGI. All I have to do is to move my server application to IIS document directory:

>copy HelloServer.php \Inetpub\wwwroot

To test my server application, I wrote this client application, HelloClient.php:

<?php # HelloClient.php# $client = new SoapClient(null, array( 'location' => "http://localhost/HelloServer.php", 'uri' => "urn://www.herong.home/req", 'trace' => 1 ));

$return = $client->__soapCall("hello",array("world")); echo("\nReturning value of __soapCall() call: ".$return);

echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders());

echo("\nDumping request:\n".$client->__getLastRequest());

echo("\nDumping response headers:\n" .$client->__getLastResponseHeaders());

echo("\nDumping response:\n".$client->__getLastResponse());?>

Check your IIS server to make sure it is running. Then run HelloClient.php. You will get:

Returning value of __soapCall() call: Hello world!

Dumping request headers:POST /HelloServer.php HTTP/1.1Host: localhostConnection: Keep-AliveUser-Agent: PHP SOAP 0.1Content-Type: text/xml; charset=utf-8SOAPAction: "urn://www.herong.home/req#hello"Content-Length: 499

Dumping request:<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn://www.herong.home/req" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body><ns1:hello> <param0 xsi:type="xsd:string">world</param0> </ns1:hello></SOAP-ENV:Body></SOAP-ENV:Envelope>

120 Naresh i Technologies

Page 121: Hypertext Preprocessor Demystified

PHP Course MaterialDumping response headers:HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Connection: closeContent-Type: text/xml; charset=utf-8X-Powered-By: PHP/5.0.4Content-Length: 522

Dumping response:<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn://www.herong.home/res" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body><ns1:helloResponse> <return xsi:type="xsd:string">Hello world!</return> </ns1:helloResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

Very exciting, right? Both server and client work nicely.

If you are interested in how the execution was carried out on the server, I have a simplified execution flow diagram on the server side:

IIS PHP (SOAP Extension) HelloServer.php HTTP request | -------------->| SOAP message | | CGI | PHP CGI API |------->|------------------------>| | addFunction() | SOAP Extension API | handle() |<------------------------| | | SOAP Extension API |------------------------>| | SOAP Extension API | hello() |<------------------------| CGI | |<-------| HTTP response | <--------------| SOAP message |

HelloServer12.php - First SOAP 1.2 Server Application

This section provides a tutorial example on how to write a simple SOAP 1.2 server application. The HelloServer.php example defines a hello() function, adds it to the SOAP server, waits for the client program to call.

121 Naresh i Technologies

Page 122: Hypertext Preprocessor Demystified

PHP Course Material

HelloServer12.php - First SOAP 1.2 Server Application

This section provides a tutorial example on how to write a simple SOAP 1.2 server application. The HelloServer.php example defines a hello() function, adds it to the SOAP server, waits for the client program to call.

So far, we have tried only with SOAP 1.1. Can we do some tests with SOAP 1.2? Sure. Here is my hello server modified for SOAP 1.2, HelloServer12.php:

<?php # HelloServer12.php#function hello($someone) { return "Hello " . $someone . "! - SOAP 1.2";} $server = new SoapServer(null, array( 'uri' => "urn://www.herong.home/res", 'soap_version' => SOAP_1_2)); $server->addFunction("hello"); $server->handle(); ?>

Here is my hello client modified for SOAP 1.2, HelloClient12.php:

<?php # HelloClient12.php# $client = new SoapClient(null, array( 'location' => "http://localhost/HelloServer12.php", 'uri' => "urn://www.herong.home/req", 'soap_version' => SOAP_1_2, 'trace' => 1 ));

$return = $client->__soapCall("hello",array("world")); echo("\nReturning value of __soapCall() call: ".$return);

echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders());

echo("\nDumping request:\n".$client->__getLastRequest());

echo("\nDumping response headers:\n" .$client->__getLastResponseHeaders());

echo("\nDumping response:\n".$client->__getLastResponse());?>

Remember to move HelloServer12.php to IIS document directory. Then run HelloClient12.php. You will get:

Returning value of __soapCall() call: Hello world! - SOAP 1.2

Dumping request headers:POST /HelloServer12.php HTTP/1.1Host: localhostConnection: Keep-AliveUser-Agent: PHP SOAP 0.1

122 Naresh i Technologies

Page 123: Hypertext Preprocessor Demystified

PHP Course MaterialContent-Type: application/soap+xml; charset=utf-8; action="urn://www.herong.home/req#hello"Content-Length: 458

Dumping request:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn://www.herong.home/req" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding"> <env:Body> <ns1:hello env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"> <param0 xsi:type="xsd:string">world</param0> </ns1:hello> </env:Body></env:Envelope>

Dumping response headers:HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Connection: closeContent-Type: application/soap+xml; charset=utf-8X-Powered-By: PHP/5.0.4Content-Length: 570

Dumping response:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn://www.herong.home/res" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding"> <env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"> <ns1:helloResponse env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"> <rpc:result>return</rpc:result> <return xsi:type="xsd:string">Hello world! - SOAP 1.2</return> </ns1:helloResponse> </env:Body></env:Envelope>

Now the output is more interesting:

SOAP 1.2 HTTP Binding rules are applied. See the HTTP request header line: Content-Type. It has a value of "application/soap+xml", and parameter of "action=...".

SOAP 1.2 Message rules are applied. See the envelope namespace value in both request message and response message: xmlns:env="http://www.w3.org/2003/05/soap-envelope.

SOAP 1.2 RPC Presentation rules are applied. See the "result" sub element in the response element of the response message. But SOAP Extension does not put the returning value directly in this sub element. It inserts a second sub element in the

123 Naresh i Technologies

Page 124: Hypertext Preprocessor Demystified

PHP Course Material

response element, and puts the returning value in this second element. The value in the required "result" element is just a reference to the second element. This seems to be violating the SOAP 1.2 RPC Presentation specifications.

HelloServerWsdl.php - SOAP 1.2 Server Application in WSDL Mode

This section provides a tutorial example on how to write a simple SOAP 1.2 server application in WSDL mode. The HelloServer.php example defines a hello() function, adds it to the SOAP server, waits for the client program to call.

Now let's move forward one step further: creating a SOAP 1.2 server application in WSDL mode. Here is the same hello server modified to work in WSDL mode, HelloServerWdsl.php:

<?php # HelloServerWsdl.php#function hello($someone) { return "Hello " . $someone . "! - With WSDL";} ini_set("soap.wsdl_cache_enabled", "0"); $server = new SoapServer("http://localhost/Hello.wsdl", array('soap_version' => SOAP_1_2)); $server->addFunction("hello"); $server->handle(); ?>

Nothing special in the program. The server object is now created with the location of the WSDL document.

Here is the WSDL document, Hello.wsdl

<?xml version="1.0"?><definitions name="MyDefinition" targetNamespace="urn:myTargetNamespace" xmlns:tns="urn:myTns" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="myRequest"> <part name="reqParam" type="xsd:string"/> </message> <message name="myResponse"> <part name="resParam" type="xsd:string"/> </message> <portType name="MyPortType"> <operation name="hello"> <input message="tns:myRequest"/> <output message="tns:myResponse"/> </operation> </portType> <binding name="MyBinding" type="tns:MyPortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="hello"> <soap:operation soapAction=""/>

124 Naresh i Technologies

Page 125: Hypertext Preprocessor Demystified

PHP Course Material <input> <soap:body use="encoded" namespace="urn:myInputNamespace" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="urn:myOutputNamespace" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="MyService"> <documentation>Returns a greeting string. </documentation> <port name="MyPort" binding="tns:MyBinding"> <soap:address location="http://localhost/HelloServerWsdl.php"/> </port> </service></definitions>

The WSDL document looks complicated. But it actually very simple to understand, as long as you remember the following points:

Read the document backward. The goal of this document is to define a "service" with two pieces of information: "binding" definition, and "url" where to reach the server. The "binding" is then defined with "type", "style", "transportation" and "operation". And so on.

The values of "name" attributes in most of the elements are identifiers local to this document only. You can use any strings. Some of them will be used on the SOAP messages.

The values of "namespace" attributes can also be any strings. They are just used to distinguish name spaces.

To install HelloServerWsdl.php to my IIS server, copy these two files to the IIS document directory:

>copy HelloServerWsdl.php \inetpub\wwwroot>copy Hello.wsdl \inetpub\wwwroot

Of course, we need to modify out hello client program as, HelloClientWsdl.php:

<?php # HelloClientWsdl.php# $client = new SoapClient("http://localhost/Hello.wsdl", array('soap_version' => SOAP_1_2,'trace' => 1 ));

echo("\nDumping client object functions:\n"); var_dump($client->__getFunctions());

$return = $client->__soapCall("hello",array("world")); echo("\nReturning value of __soapCall() call: ".$return);

125 Naresh i Technologies

Page 126: Hypertext Preprocessor Demystified

PHP Course Material

# $return = $client->hello("world");# echo("\nReturning value: ".$return);

echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders());

echo("\nDumping request:\n".$client->__getLastRequest());

echo("\nDumping response headers:\n" .$client->__getLastResponseHeaders());

echo("\nDumping response:\n".$client->__getLastResponse());?>

When you are ready to test, run HelloClientWsdl.php. You will get:

Dumping client object functions:array(1) { [0]=> string(30) "string hello(string $reqParam)"}

Returning value of __soapCall() call: Hello world! - With WSDL

Dumping request headers:POST /HelloServerWsdl.php HTTP/1.1Host: localhostConnection: Keep-AliveUser-Agent: PHP SOAP 0.1Content-Type: application/soap+xml; charset=utf-8; action=""Content-Length: 457

Dumping request:<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn:myInputNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding"> <env:Body> <ns1:hello env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"> <reqParam xsi:type="xsd:string">world</reqParam> </ns1:hello> </env:Body></env:Envelope>

Dumping response headers:HTTP/1.1 200 OKServer: Microsoft-IIS/5.1Connection: closeContent-Type: application/soap+xml; charset=utf-8X-Powered-By: PHP/5.0.4Content-Length: 573

Dumping response:

126 Naresh i Technologies

Page 127: Hypertext Preprocessor Demystified

PHP Course Material<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn:myOutputNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding"> <env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"> <ns1:helloResponse env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"> <rpc:result>resParam</rpc:result> <resParam xsi:type="xsd:string">Hello world! - With WSDL</resParam> </ns1:helloResponse> </env:Body></env:Envelope>

Anything interesting here? Yes. Some names defined in the WSDL document did show up in the SOAP request message and response message, like: "urn:myInputNamespace", "reqParam", "urn:myOutputNamespace", etc.

Localization Overview of Web Applications

This chapter provides tutorial examples and notes about Web application localization. Topics include what is localization; software components in Web applications; travel paths of output and input character strings; outputting ASCII character from PHP scripts.

What Is Localization / Internationalization?

Localization of Web Based Applications

Character String Traveling Paths

Output ASCII Character Strings from PHP Scripts

Conclusion:

Localization is mainly a process of managing input and output character strings in a specific language tailored to the end user.

In a Web application, characters must travel through different paths involving a number of programs and systems.

ASCII characters have no problems to travel through different programs and systems.

Non ASCII characters must be encoded into a safe format to travel through different programs and systems.

Tutorial notes are provided in the next 5 chapters for handling non ASCII characters in different areas: HTML documents, PHP string literals, HTML input forms, PHP string functions, and MySQL databases.

What Is Localization / Internationalization?

127 Naresh i Technologies

Page 128: Hypertext Preprocessor Demystified

PHP Course Material

This section describes what is localization and internationalization. Locale is a concept that defines geographical and cultural specific preferences on the user interface.

Localization (software localization), sometimes shortened to "l10n", is a process that tailors software user interface for the user based on his/her specific geographical, and cultural preferences.

Internationalization (software Internationalization), sometimes shortened to "i18n", is a process of enabling software for localization.

Users specific geographical and cultural preferences can be abstracted into a concept of locale. A locale usually determines the following aspects of the user interface:

Using the specific language for system output and user input. Using the specific time zone and date/time format.

Using the specific currency and numbering system.

We know that the main task of localization is to communicate with user in the local language. This means that software must present information as characters of the local language, and take information as characters of the local language.

In this part of the book, we will concentrate on presenting and managing information as characters of the local language.

Localization of Web Based Applications

This section describes what are involved in localization of a Web based application, which uses multiple programs: Web browser, Web server, application server, and database server.

Managing character strings of a specific language in a Web based application is not a simple task, because there are a number of software components involved in a typical Web based application. We have to understand how each of them manages character strings and how we transfer character strings from one component to another component.

First, let me try to abstract software programs involved in a Web application into the following list:

Web browser: End user interface program responsible for presenting and taking characters to and from users.

Web server: Communication program responsible for forwarding characters between Web browser and application program.

Application program: Program developed by you for processing characters received from the Web server and/or retrieved from the database server.

Database server: Storage program responsible for storing characters.

128 Naresh i Technologies

Page 129: Hypertext Preprocessor Demystified

PHP Course Material

Development environment: Software program responsible for embedding characters into the source code of the application program.

Before we get into details of how characters are handled in those programs, we need to understand how characters of a specific language are represented in computers. Here is my understanding:

Characters of English language can be represented by ASCII encoding schema. ASCII encoding schema represents one English character into one byte.

Characters of a non English language can be represented either in Unicode encoding schema or in a specific encoding scheme designed for that language. For example, characters of simplified Chinese can be represented either in Unicode or in GB2312. Characters of Japanese can be represented either in Unicode or in Shift-JIS.

Unicode encoding schema has several encoding variations: Unicode internal code, UTF-8, UTF16, etc.

To read more about character encoding and Unicode, see my other book: "Herong's tutorial notes on Unicode".

Character String Traveling Paths

This section describes steps of connection paths that character strings must travel through in a typical Web based application: output characters strings come from PHP files or data base tables and input character strings come from user's Web browser.

In a typical Web based application, character strings will travel from one part of the application to another part. Here are some possible paths character strings may travel through.

From PHP file to Web browser: The following diagram illustrates steps that character strings must travel through from a PHP file to a browser screen. It also shows the computing technologies that are used at different steps:

A1. Key Sequences from keyboard | |- Text editor vA2. PHP File | |- PHP CGI engine vA3. HTML Document | |- Web server vA4. HTTP Response | |- Internet TCP/IP Connection vA5. HTTP Response |

129 Naresh i Technologies

Page 130: Hypertext Preprocessor Demystified

PHP Course Material |- Web browser vA6. Visual characters on the screen

From Database to Web browser: The following diagram illustrates steps that character strings must travel through from a database table to a browser screen. It also shows computing technologies that are used at different steps:

B1. Byte sequences in storage | |- Database server vB2. Byte stream | |- Database connection driver vB3. Byte stream | |- PHP Application vB4. HTTP Response | |- Internet TCP/IP Connection vB5. HTTP Response | |- Web browser vB6. Visual characters on the Screen

From Web browser to Database: The following diagram illustrates steps that character strings must travel from a Web browser to a database table. It also shows computing technologies that are used at different steps:

C1. Key sequences on keyboard | |- Language input tool (optional) vC2. Byte sequences | |- Browser input form vC3: HTTP request | |- Internet TCP/IP Connection v C4. HTTP request | |- Web server vC5. CGI variables and input stream | |- PHP Application vC6. PHP variables |

130 Naresh i Technologies

Page 131: Hypertext Preprocessor Demystified

PHP Course Material |- Database connection driver vC7. Byte stream | |- Database server vC8. Byte sequence in storage

Since all computing technologies are using ASCII encoding by default, text of ASCII characters can safely travel through those steps without any issues.

However, for non ASCII characters, we have to watch out each steps carefully to make sure that characters are not damaged and are encoded and decoded correctly.

Now I will try to provide some tutorials in this chapter and next 5 chapters to show you how to handle characters correctly in different steps of different connection paths.

Output ASCII Character Strings from PHP Scripts

This section provides tutorial example on how to include output ASCII character strings in a PHP script file. ASCII characters can be entered directly as string literals in PHP code segments or as text in non-PHP code segments. No special techniques are needed.

As I mentioned earlier, ASCII characters can travel from PHP files to browsers easily without any trouble. Here is a simple PHP file with ASCII characters only:

<?php #HelpASCII.php# print("<html><body>\n"); print("<b>Help</b><br/>\n"); print("This is a very simple help page...<br/>\n");?>This is a very simple help page...<br/></body></html>

If you view this page with a browser, you will get the following output:

HelpThis is a very simple help page...This is a very simple help page...

Perfect, right? ASCII text entered as a PHP string literal travels through correctly. Text entered as HTML static text outside the PHP block travels through also correctly.

Using Non-ASCII Characters in HTML Documents

This chapter provides tutorial examples and notes about non-ASCII characters in HTML documents. Topics include basic rules on using non-ASCII characters in HTML documents; examples of using French characters with UTF-8 and ISO-8859-1 encodings; examples of using Chinese characters with UTF-8 and GB2312 encodings.

131 Naresh i Technologies

Page 132: Hypertext Preprocessor Demystified

PHP Course Material

Basic Rules of Using Non-ASCII Characters in HTML Documents

French Characters in HTML Documents - UTF-8 Encoding

French Characters in HTML Documents - ISO-8859-1 Encoding

Chinese Characters in HTML Documents - UTF-8 Encoding

Chinese Characters in HTML Documents - GB2312 Encoding

Characters of Multiple Languages in HTML Documents

Conclusion:

You can only use one encoding schema in a HTML document. You should a <meta> tag to specify the encoding name.

Entering non ASCII characters into a HTML document with the desired encoding is a challenge. If you are not sure on what encoding used by the editor to store HTML document, open the document with another editor to validate.

Use UTF-8 as the HTML document encoding instead of encodings of a particular local language, like GB2312. This may cause problems for users on local systems where Unicode fonts are not supported. But more and more local systems are supporting Unicode and UTF-8 encoding.

Basic Rules of Using Non-ASCII Characters in HTML Documents

This section describes basic rules on how non-ASCII character strings should be managed at different steps to ensure localized text strings can be used in HTML documents and displayed correctly on the browser window.

As you can see from the previous chapters, a Web based application always delivers information to the user interface as a HTML document. The application can either take a static HTML document from the file system, or generate a dynamic HTML document from a PHP script.

First, let's concentrate on how to handle non ASCII characters in static HTML documents. Here are the steps and technologies involved in entering a HTML document and delivering it to the user interface:

H1. Key Sequences from keyboard | |- Text editor vH2. HTML Document | |- Web server vH3. HTTP Response | |- Internet TCP/IP Connection vH4. HTTP Response

132 Naresh i Technologies

Page 133: Hypertext Preprocessor Demystified

PHP Course Material | |- Web browser vH5. Visiual characters on the Screen

Based on my experience, here are some basic rules related to those steps:

1. You must decide on the character encoding schema to be used in the HTML document first. For most of human written languages, you have two options, a) use a encoding schema specific to that language; b) use a Unicode schema. For example, you can use either GB2312 (a simplified Chinese character schema) or UTF-8 (a Unicode character schema) for Chinese characters. My suggestion used to be "a". But from now on, I am suggesting "b", because Unicode schema can support all characters of all languages.

2. PHP seems to be a nice language. The data type of string is defined as a sequence of bytes, like C language. This is different than Java language, where string is defined as a sequence of Unicode characters. String literals in PHP can take any sequence of bytes. Therefore you can enter non ASCII characters as PHP string literals in any encoding schema.

3. From step "H1" to "H2", you need select good text editor that supports the encoding schema you have selected. The end goal of this step is simple - characters in the HTML documents must be stored in a file using the selected encoding schema. Don't under estimate the difficulty level of this step. It could be very frustrating, because most computer keyboards support alphabetic letters only. You may have to use some language specific input software to translate alphabetic letters into language specific characters. The editor sometimes may also store characters in memory in one encoding schema, and offer you different encoding schema when saving files to harddisk.

4. From step "H3" to "H4", it is the job for the Internet to send data from the Web server to the Web browser. The HTTP response will be transmitted as is to the browser. The characters in the HTML document attached in the HTTP response will also be maintained as is.

5. From step "H4" to "H5", the browser opens the received HTML document and displays encoded characters as written characters of the specific language. To do this, the browser needs your help. The first help is to specify the character encoding name, "charset", used in the HTML document as a <meta> tag. The second help is to make sure the browser can access the a character font file designed for the specified encoding schema.

If no character encoding name is specified in the <meta> tag, some browsers will try to detect the encoding schema based on the HTML document content. If not successful, browsers will use default encoding schemas. For example, Internet Explorer (IE) use "Western European" as the default encoding schema. "Western European" seems to be referring to "ISO-8859-1" standard.

French Characters in HTML Documents - UTF-8 Encoding

This section provides a tutorial example on how enter and use French characters in HTML documents using Unicode UTF-8 encoding. The HTML document should include a meta tag with charset=utf-8 and be stored in UTF-8 format.

133 Naresh i Technologies

Page 134: Hypertext Preprocessor Demystified

PHP Course Material

Let's play to some French characters in UTF-8 encoding first.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following HTML document:

<html><!-- HelpUtf8French.html --><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><body><b>Help</b><br/>English: System load is very high.<br/>French: L'utilisation de système est très haute.<br/></body></html>

3. To enter the French character, "e with grave", you can run Start > All Programs > System Tools > Character Map. Select "e with grave" on the character map. Click the Select button, then the Copy button. Go back to your Notepad and click Ctrl-V to paste "e with grave" into your HTML document.

4. Select menu File > Save as. Enter the file name as HelpUtf8French.html. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelpUtf8French.html to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelpUtf8French.html. Your should see the French characters displayed correctly as shown below:

HelpEnglish: System load is very high.French: L'utilisation de système est très haute.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

Note that how I specify the <meta> tag:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

Another interesting thing you should know is about how Notepad stores a UTF-8 file. When you use UTF-8 encoding to store a file in Notepad, it will insert a UTF-8 marker (3 bytes) at the beginning of the file. Use the "type" command in a command window, you will see this:

>type HelpUtf8French.htmln++<html><!-- HelpUtf8French.html --><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

134 Naresh i Technologies

Page 135: Hypertext Preprocessor Demystified

PHP Course Material<body><b>Help</b><br/>English: System load is very high.<br/>French: L'utilisation de système est très haute.<br/></body></html>

The hex value of the UTF-8 marker is 0xEFBBBF. IIS server will send it the client. IE browser will not show it on the page, but it will use it to detect the encoding schema, if needed. Not sure on how other browsers will behave on this marker.

French Characters in HTML Documents - ISO-8859-1 Encoding

This section provides a tutorial example on how enter and use French characters in HTML documents using Unicode ISO-8859-1 encoding. The HTML document should include a meta tag with charset=ISO-8859-1 and be stored in ANSI format.

Now we know how to make French characters working in a HTML document in UTF-8 encoding schema. Next let's see how to use French characters in HTML documents in ISO-8859-1 encoding schema.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following HTML document:

<html><!-- HelpIsoFrench.html --><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/><body><b>Help</b><br/>English: System load is very high.<br/>French: L'utilisation de système est très haute.<br/></body></html>

3. To enter the French character, "e with grave", you can run Start > All Programs > System Tools > Character Map. Select "e with grave" on the character map. Click the Select button, then the Copy button. Go back to your Notepad and click Ctrl-V to paste "e wtih grave" into your HTML document.

4. Select menu File > Save as. Enter the file name as HelpIsoFrench.html. Select "ANSI" in the Encoding field and click the Save button. Note that ANSI is encoding schema defined by Microsoft and used on Windows system. ANSI contains more characters than ISO-8859-1. But it is compatible with ISO-8859-1.

5. Copy HelpIsoFrench.html to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

135 Naresh i Technologies

Page 136: Hypertext Preprocessor Demystified

PHP Course Material

6. Now run Internet Explorer (IE) with http://localhost/HelpIsoFrench.html. Your should see the French characters displayed correctly as shown below:

HelpEnglish: System load is very high.French: L'utilisation de système est très haute.

7. On the IE window, select menu View > Encoding. You should see "Western European" is selected. Again "Western European" is a different name for ISO-8859-1.

Easy to do, right? We could make it even easier. You can remove the <meta> tag setting in HelpIsoFrench.html. French characters will still show up on the IE window. This is because ISO-8859-1 is the default encoding schema to IE.

Chinese Characters in HTML Documents - UTF-8 Encoding

This section provides a tutorial example on how enter and use Chinese characters in HTML documents using Unicode UTF-8 encoding. The HTML document should include a meta tag with charset=utf-8 and be stored in UTF-8 format.

Now let's play with Chinese characters. They are definitely harder to work with than French characters. My first example shows you how to handle Chinese characters in HTML documents with UTF-8 encoding.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following HTML document:

<html><!-- HelpUtf8Chinese.html--><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><body><b>说明</b><br/>这是一份非常间单的说明书…<br/></body></html>

3. As I mentioned earlier in this book, entering Chinese characters is not an easy job. You need to use a Chinese Windows system, or a Chinese input tool on a non-Chinese Windows system. If you don't have any Chinese input tool, you can simply go to the Yahoo Chinese Web site, http://www.yahoo.com.cn/, copy some Chinese characters, and paste them into Notepad. The Yahoo Chinese Web site is encoded in UTF-8.

4. Select menu File > Save as. Enter the file name as HelpUtf8Chinese.html. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelpUtf8Chinese.html to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

136 Naresh i Technologies

Page 137: Hypertext Preprocessor Demystified

PHP Course Material

6. Now run Internet Explorer (IE) with http://localhost/HelpUtf8Chinese.html. Your should see the Chinese characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

Chinese Characters in HTML Documents - GB2312 Encoding

This section provides a tutorial example on how enter and use Chinese characters in HTML documents using GB2312 encoding. The HTML document should include a meta tag with charset=GB2312 and be stored in GB2312 format.

We are ready to test Chinese characters in HTML documents with GB2312 encoding schema.

1. This time, we can not use Notepad, because Notepad is not compatible with GB2312 encoding. It will actually convert GB2312 encoding to UTF-8 encoding. So don't use Notepad.

You need to go get another text editor, like Jext, to help you enter the Chinese characters in GB2312 encoding.

2. In a good text editor, enter the following HTML document:

<html><!-- HelpGb2312Chinese.html --><meta http-equiv="Content-Type" content="text/html; charset=gb2312"/><body><b>??</b><br/>????????????<br/></body></html>

When I copy this HTML document into this book, I have to replace all GB2312 encoded Chinese characters with "?"s, because my book is written in HTML document with UTF-8 encoding schema. To follow my tutorial, just enter any Chinese character whenever you see "?".

3. Entering Chinese characters in GB2312 encoding also requires some Chinese input tools. If you don't have any Chinese input tool, you can simply go to my GB2312 page, http://www.herongyang.com/gb2312_gb/, open the source code of the page, copy some Chinese characters, and paste them into the editor. My GB2312 page is encoded in GB2312. Warning, do not copy Chinese characters from the IE browser window. The browser window copy function is assuming UTF-8 encoding and will corrupt the copied characters.

4. Select menu File > Save as. Enter the file name as HelpGb2312Chinese.html and click the Save button.

5. Copy HelpGb2312Chinese.html to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

137 Naresh i Technologies

Page 138: Hypertext Preprocessor Demystified

PHP Course Material

6. Now run Internet Explorer (IE) with http://localhost/HelpGb2312Chinese.html. Your should see the Chinese characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see Gb2312 is selected.

Still not hard to do, right? The key point is to use an editor that compatible with GB2312.

Characters of Multiple Languages in HTML Documents

This section provides a tutorial example on how enter and use characters of multiple languages in a single HTML document with Unicode UTF-8 encoding.

After going through above examples, you should feel comfortable now on how to handle non-ASCII characters of any single language. You have a choice of using UTF-8 or a language specific encoding.

If you want to have characters of multiple languages in a single HTML document, then you have to use UTF-8 encoding. Here are the steps you can follow make a HTML document in UTF-8 to support multiple languages in a single HTML document.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following HTML document:

<html><!-- HelloUtf8MultiLanguages.html --><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><body><b>Test</b><br/>English: Hello world!<br/>Spanish: ¡Hola mundo!<br/>Korean: 여보세요 세계 !<br/>Chinese: 你好世界!<br/></body></html>

3. Don't try to enter those hello messages yourself. Go to the Google language tool site, http://www.google.com/language_tools. You can enter "Hello world!" and translate it to other languages. On the translation output page, just copy those translations and paste them back to Notepad. This should cause no corruption, because Google site, Windows IE, and Notepad all support UTF-8.

4. Select menu File > Save as. Enter the file name as HelloUtf8MultiLanguages.html. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelloUtf8MultiLanguages.html to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

138 Naresh i Technologies

Page 139: Hypertext Preprocessor Demystified

PHP Course Material

6. Now run Internet Explorer (IE) with http://localhost/HelloUtf8MultiLanguages.html. Your should see all characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

Using Non-ASCII Characters as PHP Script String Literals

This chapter provides tutorial examples and notes about non-ASCII characters in PHP scripts. Topics include basic rules on using non-ASCII characters in PHP scripts as string literals; examples of using French characters with UTF-8 and ISO-8859-1 encodings; examples of using Chinese characters with UTF-8 and GB2312 encodings.

Basic Rules of Using Non-ASCII Characters in HTML Documents

French Characters in String Literals - UTF-8 Encoding

French Characters in HTML Documents - ISO-8859-1 Encoding

Chinese Characters in String Literals - UTF-8 Encoding

Chinese Characters in String Literals - GB2312 Encoding

Characters of Multiple Languages in String Literals

Conclusion:

PHP string data type is defined as sequences of bytes. PHP string literal can almost non ASCII characters in almost any encoding schema.

The best choice of encoding schema is UTF-8.

Using UTF-8 encoding in PHP scripts requires a good UTF-8 compatible editor.

PHP script generates HTML document using print() function, which is a byte stream output function, offers no encoding conversion by default.

Basic Rules of Using Non-ASCII Characters in HTML Documents

This section describes basic rules on how non-ASCII character strings should be managed at different steps to ensure localized text strings can be used in PHP script string literals and displayed correctly on the browser window.

As you can see from the previous chapters, when PHP scripts are involved in a Web based application, they are always used behind a Web server. PHP scripts are expected to generate HTML documents and pass them back to the Web server. There are about four ways non ASCII characters can get into the HTML document through PHP scripts: a) Enter them as string literals; b) Receive them from HTTP request; c) Retrieve them from files; d) Retrieve them from a database.

139 Naresh i Technologies

Page 140: Hypertext Preprocessor Demystified

PHP Course Material

In this chapter, we will concentrate on how to include non ASCII characters in PHP scripts as string literals. Here are the steps involved in this scenario:

A1. Key Sequences from keyboard | |- Text editor vA2. PHP File | |- PHP CGI engine vA3. HTML Document

Based on my experience, here are some basic rules related to those steps:

1. You must decide on the character encoding schema to be used in your PHP script file. For most of the languages, you have two options, a: use a encoding schema specific to that language; b: use a Unicode schema. For example, you can use either GB2312 (a simplified Chinese character schema) or UTF-8 (a Unicode character schema) for Chinese characters. My suggestion used to be "a". But today, I am suggesting "b", because Unicode schema can support all characters of all languages.

2. From step "A1" to "A2", you need select good text editor that supports the encoding schema you have decided. The end goal of this step is simple - characters in string literals must be stored in the PHP file using the decided encoding schema. Don't under estimate the difficulty level of this step. It could be very frustrating, because most computer keyboards support alphabetic letters only. You may have to use some language specific input software to translate alphabetic letters into language specific characters. The editor sometimes may also store characters in memory in one encoding schema, and offer you different encoding schema when saving files to harddisk.

3. String data type is defined as a sequence of bytes in PHP, like C language. This is different than Java language, where string data type is defined as a sequence of Unicode characters. String literals in PHP are also taken as sequences of bytes. This is a nice feature. It allows us to enter non ASCII characters in almost any encoding schema.

4. All PHP built-in string functions assume that strings are sequences of bytes. For example, strlen() returns the number of bytes of the given string, not the number of characters of a specific language. To manage strings as sequences of characters, we need to use Multibyte String functions, mb_*().

5. From step "A2" to "A3", HTML documents are generated from PHP script mainly through the print() function. The print() function will nicely copy every bytes from the specified string to HTML documents. This guarantees that any non ASCII characters encoded in any encoding schema will be copied correctly to the HTML document. Again, this is different than JSP pages, where strings will be converted into bytes stream based a specified encoding schema, if you are using character based output stream functions.

140 Naresh i Technologies

Page 141: Hypertext Preprocessor Demystified

PHP Course Material

6. If you do want to convert from one encoding schema to another encoding schema during the print() function call, you can use mb_output_handler as the call back function on the output buffer: ob_start("mb_output_handler").

French Characters in String Literals - UTF-8 Encoding

This section provides a tutorial example on how enter and use French characters PHP string literals using Unicode UTF-8 encoding. The PHP script file should be stored in UTF-8 format.

First, let's play to some French characters in UTF-8 encoding first.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following PHP script:

<?php #HelpUtf8French.php# print('<html>'); print('<meta http-equiv="Content-Type"'. ' content="text/html; charset=utf-8"/>'); print('<body>'); print('<b>Help</b><br/>'); print('English: System load is very high.<br/>'); print('French: L\'utilisation de système est très haute.<br/>'); print('</body>'); print('</html>');?>

3. To enter the French character, "e with grave", you can run Start > All Programs > System Tools > Character Map. Select "e with grave" on the character map. Click the Select button, then the Copy button. Go back to your Notepad and click Ctrl-V to paste "e with grave" into your PHP script.

4. Select menu File > Save as. Enter the file name as HelpUtf8French.php. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelpUtf8French.php to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelpUtf8French.php. Your should see the French characters displayed correctly as shown below:

HelpEnglish: System load is very high.French: L'utilisation de système est très haute.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

141 Naresh i Technologies

Page 142: Hypertext Preprocessor Demystified

PHP Course Material

Another interesting thing you should know is about how Notepad stores a UTF-8 file. When you use UTF-8 encoding to store a file in Notepad, it will insert a UTF-8 marker (3 bytes) at the beginning of the file. Use the "type" command in a command window, you will see this:

>type HelpUtf8French.phpn++<?php #HelpUtf8French.php

# print('<html>'); print('<meta http-equiv="Content-Type"'. ' content="text/html; charset=utf-8"/>'); print('<body>'); print('<b>Help</b><br/>'); print('English: System load is very high.<br/>'); print('French: L\'utilisation de système est très haute.<br/>'); print('</body>'); print('</html>');?>

The hex value of the UTF-8 marker is 0xEFBBBF. IIS server will send it the client. IE browser will not show it on the page, but it will use it to detect the encoding schema, if needed. Not sure on how other browsers will behave this marker.

French Characters in HTML Documents - ISO-8859-1 Encoding

This section provides a tutorial example on how enter and use French characters PHP string literals using ISO-8859-1 encoding. The PHP script file should be stored in ANSI format.

Now we know how to make French characters working in a PHP string literal in UTF-8 encoding schema. Next let's see how to them working in ISO-8859-1 encoding schema.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following PHP script:

<?php #HelpIsoFrench.php# print('<html>'); print('<meta http-equiv="Content-Type"'. ' content="text/html; charset=iso-8859-1"/>'); print('<body>'); print('<b>Help</b><br/>'); print('English: System load is very high.<br/>'); print('French: L\'utilisation de système est très haute.<br/>'); print('</body>'); print('</html>');?>

3. To enter the French character, "e with grave", you can run Start > All Programs > System Tools > Character Map. Select "e with grave" on the character map. Click the Select button, then the Copy button. Go back to your Notepad and click Ctrl-V to paste "e with grave" into your PHP script.

142 Naresh i Technologies

Page 143: Hypertext Preprocessor Demystified

PHP Course Material

4. Select menu File > Save as. Enter the file name as HelpIsoFrench.php. Select "ANSI" in the Encoding field and click the Save button. Note that ANSI is encoding schema defined by Microsoft and used on Windows system. ANSI contains more characters than ISO-8859-1. But it is compatible with ISO-8859-1.

5. Copy HelpIsoFrench.php to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelpIsoFrench.php. Your should see the French characters displayed correctly as shown below:

HelpEnglish: System load is very high.French: L'utilisation de système est très haute.

7. On the IE window, select menu View > Encoding. You should see "Western European" is selected. Again "Western European" is a different name for ISO-8859-1.

Easy to do, right? We could make it even easier. You can remove the <meta> tag setting in HelpIsoFrench.html. French characters will still show up on the IE window. This is because ISO-8859-1 is the default encoding schema to IE.

Chinese Characters in String Literals - UTF-8 Encoding

This section provides a tutorial example on how enter and use Chinese characters PHP string literals using Unicode UTF-8 encoding. The PHP script file should be stored in UTF-8 format.

Now let's play with Chinese characters. They are definitely harder to work with than French characters. My first example shows you how to handle Chinese characters in PHP scripts with UTF-8 encoding.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following HTML document:

<?php #HelpUtf8French.php

# print('<html>'); print('<meta http-equiv="Content-Type"'. ' content="text/html; charset=utf-8"/>'); print('<body>'); print('<b>说明</b><br/>'); print('这是一份非常间单的说明书…<br/>'); print('</body>'); print('</html>');?>

3. As I mentioned earlier in this book, entering Chinese characters is not an easy job. You need to use a Chinese Windows system, or a Chinese input tool on a non-Chinese Windows system. If

143 Naresh i Technologies

Page 144: Hypertext Preprocessor Demystified

PHP Course Material

you don't have any Chinese input tool, you can simply go to the Yahoo Chinese Web site, http://www.yahoo.com.cn/, copy some Chinese characters, and paste them into Notepad. The Yahoo Chinese Web site is encoded in UTF-8.

4. Select menu File > Save as. Enter the file name as HelpUtf8Chinese.php. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelpUtf8Chinese.php to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelpUtf8Chinese.php. Your should see the Chinese characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

Chinese Characters in String Literals - GB2312 Encoding

This section provides a tutorial example on how enter and use Chinese characters PHP string literals using GB2312 encoding. The PHP script file should be stored in GB2312 format.

I think we are ready to test Chinese characters in PHP scripts with GB2312 encoding schema now.

1. This time, we can not use Notepad, because Notepad is not compatible with GB2312 encoding. It will actually convert GB2312 encoding to UTF-8 encoding. So don't use Notepad.

You need to go get another text editor, like Jext, to help you enter the Chinese characters in GB2312 encoding.

2. In a good text editor, enter the following HTML document:

<?php #HelpGb2312Chinese.php# print('<html>'); print('<meta http-equiv="Content-Type"'. 'content="text/html; charset=gb2312"/>'); print('<body>'); print('<b>??</b><br/>'); print("????????????<br/>"); print('</body>'); print('</html>');?>

When I copy this HTML document into this book, I have to replace all GB2312 encoded Chinese characters with "?"s, because my book is written in HTML document with UTF-8 encoding schema. To follow my tutorial, just enter any Chinese character whenever you see "?".

3. Entering Chinese characters in GB2312 encoding also requires some Chinese input tools. If you don't have any Chinese input tool, you can simply go to my GB2312 page, http://www.herongyang.com/gb2312_gb/, open the source code of the page, copy some Chinese

144 Naresh i Technologies

Page 145: Hypertext Preprocessor Demystified

PHP Course Material

characters, and paste them into the editor. My GB2312 page is encoded in GB2312. Warning, do not copy Chinese characters from the IE browser window. The browser window copy function is assuming UTF-8 encoding and will corrupt the copied characters.

4. Select menu File > Save as. Enter the file name as HelpGb2312Chinese.php and click the Save button.

5. Copy HelpGb2312Chinese.php to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelpGb2312Chinese.php. Your should see the Chinese characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see Gb2312 is selected.

Still not hard to do, right? The key point is to use an editor that compatible with GB2312.

Characters of Multiple Languages in String Literals

This section provides a tutorial example on how enter and use characters of multiple languages in a single PHP script with Unicode UTF-8 encoding.

After going through the above examples, you should feel comfortable now on how to handle non-ASCII characters of any single language. You have a choice of using UTF-8 or a language specific encoding.

If you want to have characters of multiple languages in a single PHP script, then you have to use UTF-8 encoding. Here are the steps you can follow make a PHP script in UTF-8 for a number of languages.

1. On a Windows system, run Start > All Programs > Accessories > Notepad.

2. In Notepad, enter the following PHP script:

<?php #HelpUtf8MultiLanguages.php# print('<html>'); print('<meta http-equiv="Content-Type"'. ' content="text/html; charset=utf-8"/>'); print('<body>'); print('<b>Test</b><br/>'); print('English: Hello world!<br/>'); print('Spanish: ¡Hola mundo!<br/>'); print('Korean: 여보세요 세계 !<br/>'); print('Chinese: 你好世界!<br/>'); print('</body>'); print('</html>');?>

145 Naresh i Technologies

Page 146: Hypertext Preprocessor Demystified

PHP Course Material

3. Don't try to enter those hello messages yourself. Go to the Google language tool site, http://www.google.com/language_tools. You can enter "Hello world!" and translate it to other languages. On the translation output page, just copy those translations and paste them back to Notepad. This should cause no corruption, because Google site, Windows IE, and Notepad all support UTF-8.

4. Select menu File > Save as. Enter the file name as HelloUtf8MultiLanguages.php. Select "UTF-8" in the Encoding field and click the Save button.

5. Copy HelloUtf8MultiLanguages.php to c:\inetpub\wwwroot. Make sure your Internet Information Service is running the local default Web site.

6. Now run Internet Explorer (IE) with http://localhost/HelloUtf8MultiLanguages.php. Your should see all characters displayed correctly.

7. On the IE window, select menu View > Encoding. You should see UTF-8 is selected.

Receiving Non-ASCII Characters from Input Forms

This chapter provides tutorial examples and notes about non-ASCII characters in Web forms. Topics include basic rules on receiving non-ASCII characters from Web input forms; examples of using the $_REQUEST array to receive non-ASCII characters submitted with GET or POST method; examples of handling non-ASCII character submitted with UTF-8 and ISO-8859-1 encodings.

Basic Rules of Receiving Non-ASCII Characters from Input Forms

Receiving Non-ASCII Characters with GET Method

Receiving Non-ASCII Characters with POST Method

Receiving Non ASCII Characters in UTF-8 Encoding

Decoding HTML Entities

Conclusion:

How non ASCII characters are recorded on a Web page depends on the "charset" setting of the page.

URL encoding is applied when input strings are transferred to the server.

PHP CGI module applies URL decoding when parsing input strings into $_REQUEST.

My suggestion is to use "charset=utf-8" for your input pages. No need to worry about HTML entity conversion.

Basic Rules of Receiving Non-ASCII Characters from Input Forms

146 Naresh i Technologies

Page 147: Hypertext Preprocessor Demystified

PHP Course Material

This section describes basic rules on how non-ASCII character strings should be managed at different steps to ensure localized text strings can be entered in HTML forms and received correctly by PHP scripts that process those forms.

As you see from the previous chapters, when PHP scripts are involved in a Web based application, they are always used behind a Web server. PHP scripts are expected to generate HTML documents and pass them back to the Web server. There are about four ways non ASCII characters can get into the HTML document through PHP scripts: a) Enter them as string literals; b) Receive from HTTP request; c) Retrieve them from files; d) Retrieve them from a database.

In this chapter, we will concentrate on how to handle non ASCII characters received in the HTTP request. Here are the steps involved in this scenario:

C1. Key sequences on keyboard | |- Language input tool (optional) vC2. Byte sequences | |- Web browser vC3: HTTP request | |- Internet TCP/IP Connection vC4. HTTP request | |- Web server vC5. CGI variables and input stream | |- PHP CGI interface vC6. PHP built-in variable and input stream

Based on my experience, here are some basic rules related to those steps:

1. Page encoding - Input strings entered in a HTML page will be encoded immediately based on the page's "charset" setting. For example, if the page has "charset=iso-8859-1", double-byte Unicode characters will be encoded as HTML entities in the form of "&#nnnnn;", where "nnnnn" represents the decimal value of the Unicode character code. For example, "&#20320;" is Unicode character encoded as a HTML entity.

If the page has "charset=utf-8", double-byte Unicode characters will be encoded as UTF-8 byte sequences. For example, "\xE4\xBD\xA0" is a Unicode character encoded as a UTF-8 byte sequence.

2. URL encoding - Web browser will then apply "x-www-form-urlencoded" to all input strings when sending them to the server as part of the HTTP request. URL encoding converts all non ASCII bytes in the form of "%xx", "xx" is the HEX value of the byte. URL encoding also converts special characters in the form of "%xx", with one exception for the space character " ". It will be converted to "+".

147 Naresh i Technologies

Page 148: Hypertext Preprocessor Demystified

PHP Course Material

For example, if the page "charset=iso-8859-1", a Unicode character is entered into the page. It will be encoded immediately as a HTML entity, like "你". When sending it to the server, it will be encoded again as "%26%2320320%3B".

If the page has "charset=utf-8", the same Unicode character is entered into the page. It will be encoded immediately as a UTF-8 byte sequence, like '\xE4\xBD\xA0". When sending it to the server, it will be encoded again as "%E4%BD%A0".

3. From step "C3" to "C4", Internet will maintain the URL encoded input strings as is.

4. From step "C4" to "C5", Web server will maintain the URL encoded input strings as is.

5. From step "C5" to "C6", PHP CGI interface is doing something interesting for you:

$_SERVER['QUERY_STRING'] stores the URL encoded input strings as is, if input is submitted with the GET method.

If input is submitted with the POST method, the URL encoded input strings will be maintained in the input stream.

PHP parses input strings out of $_SERVER['QUERY_STRING'] or input stream into an array called $_REQUEST. During this parsing process, URL decoding is applied. All input strings are converted back to how they are entered on the page.

6. What do you want to do with the characters in the input data is your decision. You could output them back to the HTML document, or store them in a file. Of course, you can apply any conversion you want to.

In the sections below, I will show you some sample PHP scripts to validate those rules.

Receiving Non-ASCII Characters with GET Method

This section provides a tutorial example on how enter non-ASCII characters in HTML forms and receive them correctly with the GET method. The HTML form is using the iso-8859-1 encoding.

We know that there are two methods you can use to submit input data in a HTML form: GET and POST. Let's work with GET method first. I wrote the following PHP script to demonstrate how non ASCII characters are managed in the steps described in the previous section.

<?php # InputIsoGet.php# #- Promoting CGI values to local variables global $r_English, $r_Spanish, $r_Korean, $r_ChineseUtf8; global $r_ChineseGb2312; import_request_variables("GPC","r_");

#- Generating HTML document print("<html>"); print('<meta http-equiv="Content-Type"' .' content="text/html; charset=iso-8859-1"/>'); print("<body>\n");

148 Naresh i Technologies

Page 149: Hypertext Preprocessor Demystified

PHP Course Material print("<form action=InputIsoGet.php method=get>"); print("English ASCII: <input name=English" ." value='$r_English' size=16><br>\n"); print("Spanish UTF-8: <input name=Spanish" ." value='$r_Spanish' size=16><br>\n"); print("Korean UTF-8: <input name=Korean" ." value='$r_Korean' size=16><br>\n"); print("Chinese UTF-8: <input name=ChineseUtf8" ." value='$r_ChineseUtf8' size=16><br>\n"); print("Chinese GB2312: <input name=ChineseGb2312" ." value='$r_ChineseGb2312' size=16><br>\n"); print("<input type=submit name=submit value=Submit>\n"); print("</form>\n");

#- Outputing input strings back to HTML document print("<hr>"); print("<pre>"); foreach ($_GET as $k => $v) { print "$k = ($v)\n"; } print("</pre>"); print("</body>"); print("</html>");

#- Dumping input strings to a file $file = fopen("\\temp\\InputIsoGet.txt", 'ab'); $str = "------\n"; fwrite($file, $str, strlen($str)); if (array_key_exists('QUERY_STRING',$_SERVER)) { $str = $_SERVER['QUERY_STRING']; } else { $str = NULL; } fwrite($file, $str, strlen($str));

$str = "------\n"; fwrite($file, $str, strlen($str)); foreach ($_REQUEST as $k => $v) { $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); } fclose($file);?>

Couple of notes for this script:

The "global" statement declares all variables in the global scope. I don't really need them to be in the global scope. But this statement also make those variables defined to avoid the "undefined variable" error message at run time.

import_request_variables() is a nice method to bring in all input strings in $_GET, $_POST, and $_COOKIE as variables. This saves a lots of coding like this: "if (array_key_exists('English',$_GET)) { $r_English = $_GET['English']; } else { $r_English = NULL;}"

149 Naresh i Technologies

Page 150: Hypertext Preprocessor Demystified

PHP Course Material

I used the single quote "'" in "<input name=English value='$r_English' ...>" to stop white spaces damaging the tag syntax. But I didn't do enough to escape "'". I will leave that to you.

I dumped all input strings to a file in a binary mode to see what we are really getting from the PHP CGI interface. "b" is used in fopen() to make sure file is open binary mode. fwrite() is used for output binary data. String length is given in fwrite() to stop the magic_quotes_runtime stripping slashes in the string.

iso-8859-1 is used as the HTML document encoding.

Now, move this script to your IIS server. Open your IE to http://localhost/InputIsoGet.php. You should see a simple Web form.

Next, enter the following strings on the form:

English ASCII: Hello world!Spanish UTF-8: ¡Hola mundo!Korean UTF-8: ???? ?? !Chinese UTF-8: ????!Chinese GB2312: ˀ½腣 ºã¡

Don't try to enter those hello messages in UTF-8 yourself. Go to the Google language tool site, http://www.google.com/language_tools. You can enter "Hello world!" and translate it to other languages. On the translation output page, just copy those translations and paste them back to this page. This should cause no corruption, because Google site, Windows IE, and Notepad all support UTF-8.

But for the "Chinese GB2312" field, you can enter the message in GB2312 compatible editor. Then copy and paste it to the Web form. Do not enter it directly on the Web form, IE will convert it to Unicode encoding without telling you.

When you are ready, click the submit button. You will see the form comes back with input strings maintained in the field. The input strings are also display below the form as:

English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (여보세요 세계 !)ChineseUtf8 = (你好世界!)ChineseGb2312 = (????!)submit = (Submit)

As you can see that the input strings return to the Web page appear to be matching values I entered on the form. But they do not match at all. If you view the source code of the page, you will see that HTML entity encoded strings are generated in the HTML document:

<html><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/><body><form action=InputIsoGet.php method=get>English ASCII: <input name=English value='Hello world!' size=16><br>Spanish UTF-8: <input name=Spanish value='¡Hola mundo!' size=16><br>

150 Naresh i Technologies

Page 151: Hypertext Preprocessor Demystified

PHP Course MaterialKorean UTF-8: <input name=Korean value='&#50668;&#48372;&#49464; &#50836; &#49464;&#44228; !&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !' size=16><br>Chinese UTF-8: <input name=ChineseUtf8 value='&#20320;&#22909; &#19990;&#30028;!' size=16><br>Chinese GB2312: <input name=ChineseGb2312 value='ˀ½腣 ºã¡' size=16><br><input type=submit name=submit value=Submit></form><hr><pre>English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !&#50668; &#48372;&#49464;&#50836; &#49464;&#44228; !)ChineseUtf8 = (&#20320;&#22909;&#19990;&#30028;!)ChineseGb2312 = (ˀ½腣 ºã¡)submit = (Submit)</pre></body></html>

This matches well with the rule that form input strings are stored in $_REQUEST in the decode format, for example, "&#20320;", where "20320" is the decimal value of Unicode character "\u4F60".

If you open the dump file, \temp\InputIsoGet.txt, you will see how input strings are URL encoded in query string, and decoded in $_REQUEST.

------English=Hello+world%21&Spanish=%A1Hola+mundo%21&Korean=%26%2350668%3B%26%2348372%3B%26%2349464%3B%26%2350836%3B+%26%2349464%3B%26%2344228%3B+%21%26%2350668%3B%26%2348372%3B%26%2349464%3B%26%2350836%3B+%26%2349464%3B%26%2344228%3B+%21&ChineseUtf8=%26%2320320%3B%26%2322909%3B%26%2319990%3B%26%2330028%3B%21&ChineseGb2312=%CA%C0%BD%E7%C4%E3%BA%C3%A3%A1&submit=Submit------English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !)ChineseUtf8 = (&#20320;&#22909;&#19990;&#30028;!)ChineseGb2312 = (????!)submit = (Submit)

For example, the Chinese character entered as Unicode was recorded by the browser as "&#20320;". It was then URL encoded into "%26%2320320%3B" when submitted to the server. PHP CGI module recorded it in $_SERVER['QUERY_STRING'] without any changes. But it was decoded back to "&#20320;" when PHP CGI module copy it to $_REQUEST.

Receiving Non-ASCII Characters with POST Method

This section provides a tutorial example on how enter non-ASCII characters in HTML forms and receive them correctly with the POST method. The HTML form is using the iso-8859-1 encoding.

151 Naresh i Technologies

Page 152: Hypertext Preprocessor Demystified

PHP Course Material

To test the POST method, I wrote the following script, InputIsoPost.php:

<?php # InputIsoPost.php# #- Promoting CGI values to local variables global $r_English, $r_Spanish, $r_Korean, $r_ChineseUtf8; global $r_ChineseGb2312; import_request_variables("GPC","r_");

#- Generating HTML document print("<html>"); print('<meta http-equiv="Content-Type"' .' content="text/html; charset=iso-8859-1"/>'); print("<body>\n"); print("<form action=InputIsoPost.php method=post>"); print("English ASCII: <input name=English" ." value='$r_English' size=16><br>\n"); print("Spanish UTF-8: <input name=Spanish" ." value='$r_Spanish' size=16><br>\n"); print("Korean UTF-8: <input name=Korean" ." value='$r_Korean' size=16><br>\n"); print("Chinese UTF-8: <input name=ChineseUtf8" ." value='$r_ChineseUtf8' size=16><br>\n"); print("Chinese GB2312: <input name=ChineseGb2312" ." value='$r_ChineseGb2312' size=16><br>\n"); print("<input type=submit name=submit value=Submit>\n"); print("</form>\n");

#- Outputing input strings back to HTML document print("<hr>"); print("<pre>"); foreach ($_POST as $k => $v) { print "$k = ($v)\n"; } print("</pre>"); print("</body>"); print("</html>");

#- Dumping input strings to a file $file = fopen("\\temp\\InputIsoPost.txt", 'ab'); $str = "------\n"; fwrite($file, $str, strlen($str)); foreach ($_REQUEST as $k => $v) { $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); } fclose($file);?>

If you test this script with Internet Explorer, you will get the same result as InputIsoGet.php.

I was looking for a way to dump the input strings submitted by the POST method. But I could not find the right function to do this.

Receiving Non ASCII Characters in UTF-8 Encoding

152 Naresh i Technologies

Page 153: Hypertext Preprocessor Demystified

PHP Course Material

This section provides a tutorial example on how enter non-ASCII characters in HTML forms and receive them correctly with the GET method. The HTML form is using the Unicode UTF-8 encoding.

In the previous scripts, "charset=iso-8859-1" is used for the input page. Now let's play with "charset=utf-8". Here is my sample script:

<?php # InputUtf8Get.php# #- Promoting CGI values to local variables global $r_English, $r_Spanish, $r_Korean, $r_ChineseUtf8; global $r_ChineseGb2312; import_request_variables("GPC","r_");

#- Generating HTML document print("<html>"); print('<meta http-equiv="Content-Type"' .' content="text/html; charset=utf-8"/>'); print("<body>\n"); print("<form action=InputUtf8Get.php method=get>"); print("English ASCII: <input name=English" ." value='$r_English' size=16><br>\n"); print("Spanish UTF-8: <input name=Spanish" ." value='$r_Spanish' size=16><br>\n"); print("Korean UTF-8: <input name=Korean" ." value='$r_Korean' size=16><br>\n"); print("Chinese UTF-8: <input name=ChineseUtf8" ." value='$r_ChineseUtf8' size=16><br>\n"); print("Chinese GB2312: <input name=ChineseGb2312" ." value='$r_ChineseGb2312' size=16><br>\n"); print("<input type=submit name=submit value=Submit>\n"); print("</form>\n");

#- Outputing input strings back to HTML document print("<hr>"); print("<pre>"); foreach ($_GET as $k => $v) { print "$k = ($v)\n"; } print("</pre>"); print("</body>"); print("</html>");

#- Dumping input strings to a file $file = fopen("\\temp\\InputUtf8Get.txt", 'ab'); $str = "------\n"; fwrite($file, $str, strlen($str)); if (array_key_exists('QUERY_STRING',$_SERVER)) { $str = $_SERVER['QUERY_STRING']; } else { $str = NULL; } fwrite($file, $str, strlen($str));

$str = "------\n"; fwrite($file, $str, strlen($str)); foreach ($_REQUEST as $k => $v) {

153 Naresh i Technologies

Page 154: Hypertext Preprocessor Demystified

PHP Course Material $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); } fclose($file);?>

If you enter the same input strings as in the previous tests:

English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (여보세요 세계 !)ChineseUtf8 = (你好世界!)ChineseGb2312 = (????!)submit = (Submit)

The page returned with the input strings displayed below the form. They look correct to me.

If you open the dump file, \temp\InputUtf8Get.txt, you will see how input strings are URL encoded in query string, and decoded in $_REQUEST.

------English=Hello+world%21&Spanish=%C2%A1Hola+mundo%21&Korean=%EC%97%AC%EB%B3%B4%EC%84%B8%EC%9A%94+%EC%84%B8%EA%B3%84+%21&ChineseUtf8=%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C%21&ChineseGb2312=%C3%8A%C3%80%C2%BD%C3%A7%C3%84%C3%A3%C2%BA%C3%83%C2%A3 %C2%A1&submit=Submit------------English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (여보세요 세계 !)ChineseUtf8 = (你好世界!)ChineseGb2312 = (????!)submit = (Submit)

Again, the result matches the rules listed earlier in this chapter. Input strings are recorded as UTF-8 byte sequences when entered on the page. Then each byte is URL encoded as %xx when sending to the server. When input strings are parsed into $_REQUEST, they are decoded back to UTF-8 byte sequences.

One surprise to me is that the GB2312 characters are also recorded as UTF-8 byte sequences.

Decoding HTML Entities

This section provides a tutorial example on how decode HTML entities received from HTML forms with iso-8859-1 encoding for non-ASCII characters.

As you see earlier in this chapter, if page has "charset=iso-8859-1", Unicode characters will be received as HTML entities in $_REQUEST. How can we convert them back to Unicode characters?

154 Naresh i Technologies

Page 155: Hypertext Preprocessor Demystified

PHP Course Material

I have tried with "urldecode()" and "rawurldecode()". They work fine on single-byte characters. But they do not work with multi-byte characters.

PHP has a special function "html_entity_decode()" to decode HTML entities with multi-byte characters. Here is the syntax of html_entity_decode():

html_entity_decode(string[, quote_style[, charset]])

where "string" is the HTML entity encoded string; "quote_style" specifies how quotes should be handled; and "charset" specifies which character set to use. Supported character sets include: ISO-8859-1, UTF-8, cp1251, GB2312, and Shift_JIS.

To show you how to use html_entity_decode(), I modified InputIsoGet.php to InputIsoGetDecoded.php:

<?php # InputIsoGetDecoded.php# #- Promoting CGI values to local variables global $r_English, $r_Spanish, $r_Korean, $r_ChineseUtf8; global $r_ChineseGb2312; import_request_variables("GPC","r_");

#- Generating HTML document print("<html>"); print('<meta http-equiv="Content-Type"' .' content="text/html; charset=utf-8"/>'); print("<body>\n"); print("<form action=InputIsoGetDecoded.php method=get>"); print("English ASCII: <input name=English" ." value='$r_English' size=16><br>\n"); print("Spanish UTF-8: <input name=Spanish" ." value='$r_Spanish' size=16><br>\n"); print("Korean UTF-8: <input name=Korean" ." value='$r_Korean' size=16><br>\n"); print("Chinese UTF-8: <input name=ChineseUtf8" ." value='$r_ChineseUtf8' size=16><br>\n"); print("Chinese GB2312: <input name=ChineseGb2312" ." value='$r_ChineseGb2312' size=16><br>\n"); print("<input type=submit name=submit value=Submit>\n"); print("</form>\n");

#- Outputing input strings back to HTML document print("<hr>"); print("<pre>"); print("Input strings before decoding:\n"); foreach ($_GET as $k => $v) { print "$k = ($v)\n"; } print("</pre>");

#- Outputing input strings back to HTML document - decoded print("<hr>"); print("<pre>"); print("Input strings after decoding:\n"); foreach ($_GET as $k => $v) {

155 Naresh i Technologies

Page 156: Hypertext Preprocessor Demystified

PHP Course Material print("$k = (".html_entity_decode($v,ENT_COMPAT,"UTF-8").")\n"); } print("</pre>"); print("</body>"); print("</html>");

#- Dumping input strings to a file $file = fopen("\\temp\\InputIsoGet.txt", 'ab'); $str = "------\n"; fwrite($file, $str, strlen($str)); if (array_key_exists('QUERY_STRING',$_SERVER)) { $str = $_SERVER['QUERY_STRING']; } else { $str = NULL; } fwrite($file, $str, strlen($str));

$str = "------\n"; fwrite($file, $str, strlen($str)); foreach ($_REQUEST as $k => $v) { $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); } fclose($file);?>

Now enter the following input strings on InputIsoGetDecoded.php to see what happens:

English ASCII: Hello world!Spanish UTF-8: ¡Hola mundo!Korean UTF-8: ???? ?? !Chinese UTF-8: ????!Chinese GB2312: ˀ½腣 ºã¡

If you click the submit button, you will get:

Input strings before decoding:English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (???? ?? !)ChineseUtf8 = (????!)ChineseGb2312 = (ˀ½腣 ºã¡)submit = (Submit)------Input strings after decoding:English = (Hello world!)Spanish = (¡Hola mundo!)Korean = (여보세요 세계 !)ChineseUtf8 = (仠好世界!)ChineseGb2312 = (ˀ½腣 ºã¡)submit = (Submit)

The first section shows you input strings as they are received in HTML entity encoding. The second section shows you input strings as they are decoded from HTML entity encoding to UTF-8 encoding.

156 Naresh i Technologies

Page 157: Hypertext Preprocessor Demystified

PHP Course Material

"mbstring" Extension and Non-ASCII Encoding Management

This chapter provides tutorial examples and notes about mbstring extension library and encoding management. Topics include introduction of mbstring extension library; tutorial example of using mbstring functions; using mb_convert_encoding() function; the best way to manage HTTP input and output encoding.

"mbstring" - Multi-Byte String Extension

mb_convert_encoding() and Other mbstring Functions

Examples of Using "mbstring" Functions

Managing HTTP Input and Output Encoding

Conclusion:

"mbstring" is a very useful extension for to handle multi-byte character strings. "mbstring" is also useful to convert strings to different encodings.

The best way to manage Web application encoding is to use UTF-8 for both page content encoding and PHP script internal encoding.

"mbstring" - Multi-Byte String Extension

This section describes the mbstring (multi-byte string) extension library designed to help you manipulate non-ASCII character strings encoded in various encoding schemas like Unicode UTF-8.

PHP offers a nice extension called "mbstring (multi-byte string)" to help you manage non-ASCII strings. Here are the features of "mbstring":

Provides multibyte specific string functions that properly detect the beginning or ending of a multibyte character. For example, mb_strlen() and mb_split().

Handles character encoding conversion between the possible encoding pairs.

Offers automatic encoding conversion for HTTP input and output.

Supports 'function overloading' feature which enables you to add multibyte awareness to regular string functions. For example, you can overload substr() with mb_substr(), so that calling substr() is really calling mb_substr().

"mbstring" extension needs to installed and configured by updating the php.ini file. To get started with "mbstring" features, I modified my php.ini as:

extension=php_mbstring.dll...mbstring.language = Neutralmbstring.internal_encoding = UTF-8mbstring.http_input = pass

157 Naresh i Technologies

Page 158: Hypertext Preprocessor Demystified

PHP Course Materialmbstring.http_output = passmbstring.encoding_translation = Offmbstring.detect_order = auto

Note that:

"mbstring.language = Neutral" is really setting the language to UTF-8. I like to work with Unicode UTF-8 encoding.

"mbstring.http_input = pass" means no decoding when receiving HTTP input. I like to manage the decoding myself inside my PHP script.

"mbstring.http_output = pass" means no encoding when generating HTTP output. I like to manage the encoding myself inside my PHP script.

mb_convert_encoding() and Other mbstring Functions

This section describes some basic functions provided in the mbstring extension library. mb_strlen() returns the number of characters. mb_convert_encoding() converts a string to a new encoding schema.

Let's first look at some of the basic "mbstring" functions offered in the "mbstring" extension library:

mb_get_info ( ) - Returns the current settings of "mbstring" extension.

mb_internal_encoding ( [string encoding] ) - Sets the current internal encoding with the specified encoding name. If no encoding is specified, it returns the current internal encoding.

string mb_strlen ( string str [, string encoding] ) - Returns the number of characters in the specified string based on the specified encoding name. If no encoding is specified, it uses the current internal encoding.

string mb_convert_encoding ( string str, string to_encoding [, mixed from_encoding] ) - Converts the specified string to a new encoding from an old encoding and returns the converted string. If no old encoding is specified, it uses the current internal encoding.

mb_detect_encoding ( string str ) - Detects and returns the encoding name of the specified string.

mb_http_input ( string type ) - Detects and returns the encoding name of the specified HTTP input type: "G" for GET, "P" for POST, "C" for COOKIE.

mb_http_output ( [string encoding] ) - Sets or returns the current HTTP output encoding.

mb_output_handler ( string contents, int status ) - Call back function for output buffer. When used as ob_start("mb_output_handler"), all strings going to the output buffer will be converted from the internal encoding to the HTTP output encoding.

158 Naresh i Technologies

Page 159: Hypertext Preprocessor Demystified

PHP Course Material

mb_parse_str ( string encoded_string [, array &result] ) - Parses URL encoded strings, like the query string received with GET method. Resulting variables will be stored in the specified array. If no array is specified, resulting variables will be promoted into global variables.

Examples of Using "mbstring" Functions

This section provides a tutorial example of using mbstring functions, mb_get_info(), mb_detect_encoding(), mb_strlen(), mb_convert_encoding(), etc.

I wrote the following script to test some of "mbstring" basic functions, MbStringBasic.php:

<?php # MbStringBasic.php# print("\nCurrent settings:\n"); $settings = mb_get_info(); foreach ($settings as $k => $v) { print " $k = ($v)\n"; }

print("\nEncoding detection:\n"); $str = "Hello!"; $coding = mb_detect_encoding($str); print("1. ".$coding." for (\x".bin2hex($str).")\n");

$str = "\x00H\x00e\x00l\x00l\x00o\x00!"; $coding = mb_detect_encoding($str); print("2. ".$coding." for (\x".bin2hex($str).")\n");

$str = "\xC2\xA1Hola!"; $coding = mb_detect_encoding($str); print("3. ".$coding." for (\x".bin2hex($str).")\n");

$str = "\xE4\xBD\xA0\xE5\xA5\xBD!"; $coding = mb_detect_encoding($str); print("4. ".$coding." for (\x".bin2hex($str).")\n");

$str = "\xC4\xE3\xBA\xC3\xA3\xA1"; $coding = mb_detect_encoding($str); print("5. ".$coding." for (\x".bin2hex($str).")\n");

print("\nString length:\n"); $str = "Hello!"; $length = mb_strlen($str, "ASCII"); print("1. ".$length." for (\x".bin2hex($str).")\n");

$str = "\x00H\x00e\x00l\x00l\x00o\x00!"; $length = mb_strlen($str, "UTF-16"); print("2. ".$length." for (\x".bin2hex($str).")\n");

$str = "\xC2\xA1Hola!"; $length = mb_strlen($str, "UTF-8"); print("3. ".$length." for (\x".bin2hex($str).")\n");

$str = "\xE4\xBD\xA0\xE5\xA5\xBD!"; $length = mb_strlen($str, "UTF-8"); print("4. ".$length." for (\x".bin2hex($str).")\n");

159 Naresh i Technologies

Page 160: Hypertext Preprocessor Demystified

PHP Course Material

$str = "\xC4\xE3\xBA\xC3\xA3\xA1"; $length = mb_strlen($str, "GB2312"); print("5. ".$length." for (\x".bin2hex($str).")\n");

print("\nString conversion - ASCII <--> UTF-16:\n"); $str = "Hello!"; print(" String in ASCII = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "UTF-16", "ASCII"); print(" Converted to UTF-16 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "ASCII", "UTF-16"); print(" Converted to ASCII = (\x".bin2hex($str).")\n");

print("\nString conversion - UTF-8 <--> UTF-16:\n"); $str = "\xC2\xA1Hola!"; print(" String in UTF-8 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "UTF-16", "UTF-8"); print(" Converted to UTF-16 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "UTF-8", "UTF-16"); print(" Converted to UTF-8 = (\x".bin2hex($str).")\n");

print("\nString conversion - UTF-8 <--> GB2312:\n"); $str = "\xE4\xBD\xA0\xE5\xA5\xBD!"; print(" String in UTF-8 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "GB2312", "UTF-8"); print(" Converted to GB2312 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "UTF-8", "GB2312"); print(" Converted to UTF-8 = (\x".bin2hex($str).")\n");

print("\nString conversion - GB2312 <--> UTF-16:\n"); $str = "\xC4\xE3\xBA\xC3\xA3\xA1"; print(" String in GB2312 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "UTF-16", "GB2312"); print(" Converted to UTF-16 = (\x".bin2hex($str).")\n"); $str = mb_convert_encoding($str, "GB2312", "UTF-16"); print(" Converted to GB2312 = (\x".bin2hex($str).")\n");?>

I you run it directly, you will get:

Current settings: internal_encoding = (UTF-8) http_input = () http_output = (pass) func_overload = (pass)

Encoding detection:1. ASCII for (\x48656c6c6f21)2. ASCII for (\x00480065006c006c006f0021)3. UTF-8 for (\xc2a1486f6c6121)4. UTF-8 for (\xe4bda0e5a5bd21)5. UTF-8 for (\xc4e3bac3a3a1)

String length:1. 6 for (\x48656c6c6f21)2. 6 for (\x00480065006c006c006f0021)3. 6 for (\xc2a1486f6c6121)4. 3 for (\xe4bda0e5a5bd21)

160 Naresh i Technologies

Page 161: Hypertext Preprocessor Demystified

PHP Course Material5. 3 for (\xc4e3bac3a3a1)

String conversion - ASCII <--> UTF-16: String in ASCII = (\x48656c6c6f21) Converted to UTF-16 = (\x00480065006c006c006f0021) Converted to ASCII = (\x48656c6c6f21)

String conversion - UTF-8 <--> UTF-16: String in UTF-8 = (\xc2a1486f6c6121) Converted to UTF-16 = (\x00a10048006f006c00610021) Converted to UTF-8 = (\xc2a1486f6c6121)

String conversion - UTF-8 <--> GB2312: String in UTF-8 = (\xe4bda0e5a5bd21) Converted to GB2312 = (\xc4e3bac321) Converted to UTF-8 = (\xe4bda0e5a5bd21)

String conversion - GB2312 <--> UTF-16: String in GB2312 = (\xc4e3bac3a3a1) Converted to UTF-16 = (\x4f60597dff01) Converted to GB2312 = (\xc4e3bac3a3a1)

Some interesting notes about this test:

I did set "mbstring.http_input = pass", but "mb_get_info()" reported no setting. I don't know why.

Encoding detection #2 did not recognize the string "\x00480065006c006c006f0021" as UTF-16 encoding.

Encoding detection #3 did not recognize the string "\xc4e3bac3a3a1" as GB2312.

By telling "mbstring" the correct encoding name, mb_strlen() worked perfectly.

Encoding conversion worked nicely too. I am actually surprised to see UTF-8 and GB2312 conversion working correctly.

Managing HTTP Input and Output Encoding

This section provides a tutorial example on how to manage HTTP input and output encoding in 3 different ways, using the same encoding input, output and internal storage, using different encodings and managing conversion manually, or using different encodings and managing conversion automatically.

There are 3 approaches on how to manage HTTP input and output encodings:

1. Set HTTP input encoding, HTTP output encoding and PHP script internal encoding to be exactly the same, like UTF-8 or GB2312. I am strongly recommending this approach, since it avoids the need for conversion when receiving HTTP input and generating HTTP output.

2. Set HTTP input encoding and HTTP output encoding to be the same, and PHP script internal encoding to be a different one. But do not let the PHP engine to do automated conversion on HTTP input and output. Let your PHP script manage it explicitly.

161 Naresh i Technologies

Page 162: Hypertext Preprocessor Demystified

PHP Course Material

3. Set HTTP input encoding and HTTP output encoding to be the same, and PHP script internal encoding to be a different one. But let the PHP engine do automated conversion on HTTP input and output.

For approach #1, you need turn off HTTP input and output encoding conversion by these php.ini settings:

mbstring.language = Neutralmbstring.internal_encoding = UTF-8mbstring.http_input = passmbstring.http_output = passmbstring.encoding_translation = Off

While writing your script, you must always remember that you are dealing with UTF-8 encoded strings.

Approach #2 is useful, if you want your Web page to be GB2312 encoded while using UTF-8 as your script internal encoding, and you want your script to control the HTTP input and output conversion process. Here are the php.ini settings:

mbstring.language = Neutralmbstring.internal_encoding = UTF-8mbstring.http_input = passmbstring.http_output = passmbstring.encoding_translation = Off

Approach #3 is useful, if you want your Web page to be UTF-8 encoded while using UTF-16 as your script internal encoding, and you trust the PHP engine to do HTTP input and output encoding conversion. Here are the php.ini settings:

mbstring.language = Neutralmbstring.internal_encoding = UTF-8mbstring.http_input = GB2312mbstring.http_output = GB2312mbstring.encoding_translation = On

Since approach #2 is more challenging than the others, I wrote the following script to give you some ideas:

<?php # MbStringHttp.php# mb_internal_encoding("UTF-8");

#- Taking care of HTTP input conversion $myRequest['English'] = ""; $myRequest['ChineseUtf8'] = ""; $myRequest['ChineseGb2312'] = ""; foreach ($_REQUEST as $k => $v) { $myRequest[$k] = mb_convert_encoding($v,"UTF-8", "GB2312"); } $r_English = $myRequest['English']; $r_ChineseUtf8 = $myRequest['ChineseUtf8']; $r_ChineseGb2312 = $myRequest['ChineseGb2312'];

162 Naresh i Technologies

Page 163: Hypertext Preprocessor Demystified

PHP Course Material

#- Taking care of HTTP output conversion mb_http_output("GB2312"); ob_start("mb_output_handler");

#- Generating HTML document print("<html>"); print('<meta http-equiv="Content-Type"' .' content="text/html; charset=gb2312"/>'); print("<body>\n"); print("<form action=MbStringHttp.php method=get>"); print("English ASCII: <input name=English" ." value='$r_English' size=16><br>\n"); print("Chinese UTF-8: <input name=ChineseUtf8" ." value='$r_ChineseUtf8' size=16><br>\n"); print("Chinese GB2312: <input name=ChineseGb2312" ." value='$r_ChineseGb2312' size=16><br>\n"); print("<input type=submit name=submit value=Submit>\n"); print("</form>\n");

#- Outputing input strings back to HTML document print("<hr>"); print("<pre>"); print("{$myRequest['English']}\n"); print("{$myRequest['ChineseUtf8']}\n"); print("{$myRequest['ChineseGb2312']}\n"); print("</pre>"); print("</body>"); print("</html>");

#- Dumping input strings to a file $file = fopen("\\temp\\MbStringHttp.txt", 'ab'); $str = "--- Query String ---\n"; fwrite($file, $str, strlen($str)); if (array_key_exists('QUERY_STRING',$_SERVER)) { $str = $_SERVER['QUERY_STRING']; } else { $str = NULL; } fwrite($file, $str, strlen($str));

$str = "--- Raw reqeust input ---\n"; fwrite($file, $str, strlen($str)); foreach ($_REQUEST as $k => $v) { $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); }

$str = "--- Converted reqeust input ---\n"; fwrite($file, $str, strlen($str)); foreach ($myRequest as $k => $v) { $str = "$k = ($v)\n"; fwrite($file, $str, strlen($str)); } fclose($file);?>

I tested this script with IE, and entered the following strings:

163 Naresh i Technologies

Page 164: Hypertext Preprocessor Demystified

PHP Course MaterialEnglish ASCII: Hello world!Spanish UTF-8: ¡Hola mundo!Korean UTF-8: 여보세요 세계 !Chinese UTF-8: 你好世界!Chinese GB2312: ????¡

The returning page showed input strings correctly. But the source code was very interesting:

<html><meta http-equiv="Content-Type" content="text/html; charset=gb2312"/><body><form action=MbStringHttp.php method=get>English ASCII: <input name=English value='Hello world!' size=16><br>Spanish UTF-8: <input name=Spanish value='&iexcl;Hola mundo!' size=16><br>Korean UTF-8: <input name=Korean value='&#50668;&#48372;&#49464; &#50836; &#49464;&#44228; !' size=16><br>Chinese UTF-8: <input name=ChineseUtf8 value='ÄãºÃÊÀ½ç!' size=16><br>Chinese GB2312: <input name=ChineseGb2312 value='&Ecirc;&Agrave; &frac12;&ccedil;&Auml;&atilde;&ordm;&Atilde;&pound;&iexcl;' size=16><br><input type=submit name=submit value=Submit></form><hr><pre>Hello world!&iexcl;Hola mundo!&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !ÄãºÃÊÀ½ç!&Ecirc;&Agrave;&frac12;&ccedil;&Auml;&atilde;&ordm;&Atilde; &pound;&iexcl;</pre></body></html>

When the Web page has "charset=gb2312", some Unicode characters are recorded as HTML named entities, like "&iexcl;", and "&Ecirc;". Some Unicode characters are recorded as HTML numeric entities, like "&#50668;" and "&#48372;".

When Chinese characters in UTF-8 encoding are copied into the form, they are recorded as GB2312 encoding.

When Chinese characters in GB2312 encoding are copied into the form, they are recorded as HTML named entities. I don't know why.

I looked at the dump file, \temp\MbStringHttp.txt:

--- Query String ---English=Hello+world%21&Spanish=%26iexcl%3BHola+mundo%21&Korean=%26%2350668%3B%26%2348372%3B%26%2349464%3B%26%2350836%3B+ %26%2349464%3B%26%2344228%3B+%21&ChineseUtf8=%C4%E3%BA%C3%CA%C0%BD%E7%21&ChineseGb2312=%26Ecirc%3B%26Agrave%3B%26frac12%3B%26ccedil%3B %26Auml%3B%26atilde%3B%26ordm%3B%26Atilde%3B%26pound%3B%26iexcl%3B&submit=Submit--- Raw reqeust input ---English = (Hello world!)Spanish = (&iexcl;Hola mundo!)Korean = (&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !)ChineseUtf8 = (ÄãºÃÊÀ½ç!)ChineseGb2312 = (&Ecirc;&Agrave;&frac12;&ccedil;&Auml;&atilde;&ordm;

164 Naresh i Technologies

Page 165: Hypertext Preprocessor Demystified

PHP Course Material &Atilde;&pound;&iexcl;)submit = (Submit)--- Converted reqeust input ---English = (Hello world!)Spanish = (&iexcl;Hola mundo!)Korean = (&#50668;&#48372;&#49464;&#50836; &#49464;&#44228; !)ChineseUtf8 = (你好世界!)ChineseGb2312 = (&Ecirc;&Agrave;&frac12;&ccedil;&Auml;&atilde;&ordm; &Atilde;&pound;&iexcl;)submit = (Submit)

My script handled HTTP input and output encoding correctly, if the input strings are recorded in GB2312 by the Web browser. For other characters recorded as HTML entities, you need to avoid them by telling your users to enter data correctly.

Managing Non-ASCII Character Strings with MySQL Servers

This free PHP tutorial book is a collection of notes and sample codes written by the author while he was learning PHP himself. It can be used as a tutorial guide for beginners or a reference book for experienced developers. Topics include PHP, array, CGI, CLI, session, cookie, database, directory, file, HTTP, header lines, IIS, image, mail, MySQL, redirect, request, response, SMTP, SOAP, SOAP Extension, SQL, Unicode, WSDL.

Storing Non-ASCII Characters in Database

Transmitting Non-ASCII Characters with Database

MySqlUnicode.php - MySQL Unicode UTF-8 Encoding Example

Conclusion:

MySQL provides a good support on non-ASCII characters. If offers a number of encodings (character sets).

MySQL allows us to specify encodings at database, table or column level.

MySQL allows us to control encoding conversions on receiving SQL statements and returning query results.

My recommendation is to use UTF-8 to all text information, turn off MySQL encoding conversion on receiving SQL statements and returning query results, and let your PHP script to handle UTF-8 strings.

Storing Non-ASCII Characters in Database

This section describes how to store non-ASCII characters in MySQL database using different character set settings set column, table or database level.

MySQL can store non-ASCII characters in database in a number of encodings, MySQL call them character sets:

+----------+-----------------------------+

165 Naresh i Technologies

Page 166: Hypertext Preprocessor Demystified

PHP Course Material| Charset | Description |+----------+-----------------------------+| big5 | Big5 Traditional Chinese || dec8 | DEC West European || cp850 | DOS West European || hp8 | HP West European || koi8r | KOI8-R Relcom Russian || latin1 | ISO 8859-1 West European || latin2 | ISO 8859-2 Central European || swe7 | 7bit Swedish || ascii | US ASCII || ujis | EUC-JP Japanese || sjis | Shift-JIS Japanese || cp1251 | Windows Cyrillic || hebrew | ISO 8859-8 Hebrew || tis620 | TIS620 Thai || euckr | EUC-KR Korean || koi8u | KOI8-U Ukrainian || gb2312 | GB2312 Simplified Chinese || greek | ISO 8859-7 Greek || cp1250 | Windows Central European || gbk | GBK Simplified Chinese || latin5 | ISO 8859-9 Turkish || armscii8 | ARMSCII-8 Armenian || utf8 | UTF-8 Unicode || ucs2 | UCS-2 Unicode || cp866 | DOS Russian || keybcs2 | DOS Kamenicky Czech-Slovak || macce | Mac Central European || macroman | Mac West European || cp852 | DOS Central European || latin7 | ISO 8859-13 Baltic || cp1256 | Windows Arabic || cp1257 | Windows Baltic || binary | Binary pseudo charset || geostd8 | GEOSTD8 Georgian |+----------+-----------------------------+

To store non-ASCII characters in a database column, you need to define that column with a specific character set. You can specify a character set at 3 levels: database, table, and column. For example:

CREATE DATABASE db_name CHARACTER SET utf8 CREATE TABLE tbl_name (...) CHARACTER SET utf8 CREATE TABLE tbl_name (col_name CHAR(80) CHARACTER SET utf8, ...)

If a character set is specified at the database level, it is applied to all CHAR, VARCHAR, and TEXT columns of all tables in this database.

If a character set is specified at the table level, it is applied to all CHAR, VARCHAR, and TEXT columns in this table.

If a character set is specified at the column level, it is applied to this column only.

The column length specified in the table creation statement is counted at the character level, not at the encoding byte level.

If "utf8" is used on a CHAR(n) column, this column will require 3*n bytes of storage.

166 Naresh i Technologies

Page 167: Hypertext Preprocessor Demystified

PHP Course Material

Transmitting Non-ASCII Characters with Database

This section describes some basic settings and rules on how to transmit non-ASCII characters from PHP scripts to MySQL database server, and from MySQL database server back to PHP scripts.

Handling non ASCII characters with MySQL not only requires us setting up the table columns with the correct encoding (character set), but also requires us setting up the correct encoding for transmitting characters to and from the database.

MySQL offers the following global variables to control the encodings used to transmit characters between the client (PHP script) and the server (MySQL database):

character_set_server - Character set used for all databases on the server. character_set_database - Character set used for the default databases on the server.

character_set_client - Character set used by the client for all SQL statements.

character_set_connection - Character set that all SQL statements should be converted to by the server before executing them.

character_set_results - Character set that all returning result should be converted to by the server before sending it back to the client.

In most cases, you should make the client (PHP script) to use the same encoding (character set) as the server (MySQL server), so that there is no need to convert when transmitting characters between them.

Some times, you may need to use different encodings. For example, you want to use UTF-8 for your PHP scripts, while using GB2312 for your MySQL tables.

You can use two special SET commands to change those variables:

1. "SET NAMES 'x'" is equivalent to these three statements:

SET character_set_client = x; SET character_set_results = x; SET character_set_connection = x;

2. "SET CHARACTER SET x" is equivalent to these three statements:

SET character_set_client = x; SET character_set_results = x; SET collation_connection = @@collation_database;

You can always use the SHOW VARIABLES LIKE 'variable_name' to view the current value of the given variable.

MySqlUnicode.php - MySQL Unicode UTF-8 Encoding Example

167 Naresh i Technologies

Page 168: Hypertext Preprocessor Demystified

PHP Course Material

This section provides a tutorial example on how to send and receive non-ASCII character strings in Unicode UTF-8 encoding to and from a MySQL database server.

My is my sample script to show you how to send UTF-8 strings to a MySQL server and store them in UTF-8 encoding, MySqlUnicode.php:

<?php # MySqlUnicode.php# $con = mysql_connect('localhost'); print "\nDefault settings...\n"; $rs = mysql_query("SHOW VARIABLES LIKE 'character_set_%'"); while ($row = mysql_fetch_array($rs)) { print " ".$row[0].' '.$row[1]."\n"; }

print "\nUpdated settings...\n"; $rs = mysql_query("SET NAMES 'utf8'"); $rs = mysql_query("SHOW VARIABLES LIKE 'character_set_%'"); while ($row = mysql_fetch_array($rs)) { print " ".$row[0].' '.$row[1]."\n"; }

print "\nCreating a table in UTF-8...\n"; $rs = mysql_query('DROP DATABASE MyBase'); $rs = mysql_query('CREATE DATABASE MyBase CHARACTER SET utf8'); $rs = mysql_query('USE MyBase'); $rs = mysql_query('CREATE TABLE MyTable (ID INTEGER,' .' Message VARCHAR(80))');

print "\nInserting some rows to the table...\n"; $str = "Hello!"; $rs = mysql_query("INSERT INTO MyTable VALUES ( 1, '$str')"); $str = "\xC2\xA1Hola!"; $rs = mysql_query("INSERT INTO MyTable VALUES ( 2, '$str')"); $str = "\xE4\xBD\xA0\xE5\xA5\xBD!"; $rs = mysql_query("INSERT INTO MyTable VALUES ( 3, '$str')"); print "\nQuery some rows from the table...\n"; $rs = mysql_query('SELECT * FROM MyTable WHERE ID < 10'); print " ".mysql_field_name($rs,0)." " .mysql_field_name($rs,1)."\n"; while ($row = mysql_fetch_array($rs)) { print " ".$row[0].' '.$row[1]."=(\x".bin2hex($row[1]).")\n"; } mysql_free_result($rs); mysql_close($con);?>

If you run it, you will get:

Default settings... character_set_client latin1 character_set_connection latin1 character_set_database latin1 character_set_results latin1 character_set_server latin1

168 Naresh i Technologies

Page 169: Hypertext Preprocessor Demystified

PHP Course Material character_set_system utf8 character_sets_dir C:\local\MySQL\share\charsets/

Updated settings... character_set_client utf8 character_set_connection utf8 character_set_database latin1 character_set_results utf8 character_set_server latin1 character_set_system utf8 character_sets_dir C:\local\MySQL\share\charsets/

Creating a table in UTF-8...

Inserting some rows to the table...

Query some rows from the table... ID Message 1 Hello!=(\x48656c6c6f21) 2 -íHola!=(\xc2a1486f6c6121) 3 S+ásÑ+!=(\xe4bda0e5a5bd21)

MySQL works as expected, no conversion on the SQL statements, storing strings in UTF-8, and no conversion on query result.

Choosing a PHP Framework: A Comparison of CakePHP and the Zend FrameworkAre you considering using a PHP framework for your next project? If so, this article's for you. I've narrowed down my choices to CakePHP and the Zend Framework and have documented my findings here.

Four or five years ago I began researching PHP application frameworks. At the time, the pickings were very slim, especially when compared to those available to Java developers. On the advice of an ex-Coldfusion developer, I settled on the PHP port of Fusebox, the de facto Coldfusion framework. Fusebox 3 provided a convenient set of loose conventions for structuring applications, organizing code, naming files, and controlling flow. It served my development team well and applications we built with it are still up and running.

I took a two-year "break" from development and upon my return I found more PHP frameworks than you can shake a stick at. Now I need to find a solid MVC-based framework and after reading dozens of articles and completing a few tutorials, I've narrowed my focus to CakePHP and the Zend Framework.

Before going further, let it be known that my point of view is that of someone with plenty of application development experience but without a formal IT or CS degree. I can't go on about the merits of one design pattern vs. another. I do, however, understand the need for convention, the advantages of modularity, and the efficiency of easily repeatable processes.

169 Naresh i Technologies

Page 170: Hypertext Preprocessor Demystified

PHP Course Material

Please note that symfony, Prado, Code Ignitor, and many of the other PHP frameworks all look quite capable of meeting most project needs. If you're a fanboy of another framework, please don't espouse it's merits here. I am, however, interested in hearing about your general experience in learning a framework, particularly in the context of your professional background.

Here's a comparison and a few conclusions after spending a bit of time with both CakePHP and the Zend Framework. Please note that my quality scale range is: poor, fair, good, excellent.

Feature Comparison of CakePHP and the Zend Framework

Feature CakePHPZend

FrameworkNotes

License MIT BSD

Each of these licenses is fairly flexible. Carefully consider how your application will be used and distributed. It's also important to consider compatability with 3rd-party extensions included in your application.

Compatability 4 and 5 5.1.4 or

later

I'm curious to know what CakePHP's PHP 4 support plans are. I would wager that Zend's focus on PHP 5 provides it with performance advantages.

Documentation good excellent CakePHP's documentation is good but Zend's API documentation is more thorough.

Community

Google group,

IRC, Articles

Wiki, Lists, Chat

Both frameworks have active user communities. In addition to official channels, there are also several 3rd-party community sites easily found through Google. CakePHP has done an excellent job of marketing their framework considering that they don't have the corporate backing that ZF has.

Tutorial/Sample Availability

excellent fair

CakePHP's Bakery provides an extensive collection of user-submitted applications and code samples. The IBM developerWorks CakePHP tutorials and aritcles are excellent. The Zend tutorials I've reviewed are good but require a siginifcant amount of MVC design experience. The ZF beginner's videos, however, are very helpful. CakePHP provides screencasts too.

170 Naresh i Technologies

Page 171: Hypertext Preprocessor Demystified

PHP Course Material

MVC strict optional These points are the biggest distinctions between these frameworks and probably the most important factors when choosing one over the other. CakePHP has very strict naming and code organization conventions while Zend only enforces conventions when employing its MVC capabilities.

Conventions strict flexible

Configuration PHP file PHP Array,

XML, or INI files

This difference doesn't seem like a sticking point to me. If you're a fan of build tools like ANT, you might prefer Zend's choice of XML.

Database Abstraction

PHP, PEAR,

ADODB PHP, PDO

I may be wrong, but I get the impression that PDO is gaining favor in the PHP community.

Security ACL-based ACL-based

Both frameworks take security very seriously and provide authentication and ACL-based authorization. Both approach ACLs in a similar fashion and both provide a high degree of flexibility in creating and applying ACLs.

Data Handling

good excellent

Out of the box, both frameworks provide data validation and sanitization mechanisms. Zend provides more validation options, but CakePHP's validation is easily extended via PCRE. CakePHP provides a single data sanitization mechanism where Zend provides various filters to run data through.

Caching good excellent Both provide file-based caching of pages. Zend supports several cache backends, including APC, SqlLite, and of course, the Zend Platform.

Sessions excellent excellent Both provide robust session handling.

Logging/Debugging

good excellent Both provide application logging. IMHO, the Zend_Debug class gives ZF the edge in this category.

Templating PHP-based

PHP-based Coming from a UI design background, templating is of particular interest to me. If you've developed templates for WordPress or Drupal, you'll feel right at home with

171 Naresh i Technologies

Page 172: Hypertext Preprocessor Demystified

PHP Course Material

CakePHP. The Zend Framework requires a bit more work to get templating up and running (see Zend_View and Zend_Layout). It's possible to integrate 3rd party templating engines, like Smarty, with each framework.

Helpers good excellent Both frameworks provide basic helpers to handle AJAX, forms, and time conversions. CakePHP provides a nice HTML helper which is absent in ZF but ZF provides a wider range of helper classes.

JavaScript/Ajax good fair

CakePHP comes with built-in support for Prototype and script.aculo.us while the current stable release of the ZF doesn't support any specific JavaScript framework. ZF does provide JSON support and the 1.5 release adds AJAX form featues. I'd like to see both provide a wider range of support for 3rd party JavaScript Frameworks, particularly Jquery and YUI.

Web Services good excellent

Both provide support for REST and XML-RPC as well as basic XML feed parsing. Zend Framework also provides support for several popular web services including OpenID, Reflection, Akismet, Amazon, Audioscrobbler, Delicious, Flickr, Simpy, StrikeIron, Technorati, and Yahoo.

Localization good excellent

Both support localization through stadard means (i18n, l10n). CakePHP is adding/improving support in their upcoming 1.2 release. Zend appears to have better support for localization and translation.

Unit Testing yes yes Both frameworks provide support for this feature that far too many of us avoid ;) I have yet to evaluate unit testing support.

Conclusions and Recommendations

I hope to use both of these frameworks soon, but in the short term I'll most likely base an upcoming CMS project on CakePHP. I do plan on using the Zend Framework, if for nothing other than expanding my application design skills, PHP 5 OO knowledge, and understanding of MVC.

172 Naresh i Technologies

Page 173: Hypertext Preprocessor Demystified

PHP Course Material

CakePHP: Hit the Ground Running Fast

If you are new to MVC, require PHP 4 support, want stricter conventions, or want powerful code generation tools, CakePHP is the choice for you. CakePHP's Scaffolding, Bake, and ACL scripts provide definite advantages when the need to quickly build an application arise.

The Zend Framework: A Model of Flexibility

If you know MVC, need more control over application design, or want built-in support for popular Web services, the Zend Framework is choice for you. The Zend Framework provides a greater degree of flexibility in designing applications that scale effectively in high-performance environments.

The bottom line is that both frameworks are rapidly evolving in response to user demands. Gaps in each are being filled and there seems to be no lack of demand for developers with skills in each framework.

Migrating from PHP 5.0.x to PHP 5.1.xTable of Contents

Key PHP 5.1.x features Changes in reference handling

Reading []

Integer values in function parameters

Class and object changes

Extensions

Date/time support

Changes in database support

Checking for E_STRIC

Key PHP 5.1.x features

Some of the key features of PHP 5.1.x include:

A complete rewrite of date handling code, with improved timezone support. Significant performance improvements compared to PHP 5.0.X.

PDO extension is now enabled by default.

Over 30 new functions in various extensions and built-in functionality.

173 Naresh i Technologies

Page 174: Hypertext Preprocessor Demystified

PHP Course Material

Over 400 various bug fixes.

Changes in reference handling

Overview Code that worked under PHP 4.3.x, but now fails

Code that worked under PHP 4.3.x, but now throws an error

Code that failed under PHP 4.3.x, but now works

Code that should have worked under PHP 5.0.x

Warnings that came and went

Reading []<?phpclass XmlTest {

    function test_ref(&$test) {        $test = "ok";    }

    function test($test) { }

    function run() {        $ar = array();        $this->test_ref($ar[]);        var_dump($ar);        $this->test($ar[]);    }}

$o = new XmlTest();$o->run();?>

This should always have thrown a fatal E_ERROR, because [] cannot be used for reading in PHP. It is invalid code in PHP 4.4.2 and PHP 5.0.5 upward.

Integer values in function parameters

With the advent of PHP 5.0.x, a new parameter parsing API was introduced which is used by a large number of PHP functions. In all versions of PHP between 5.0.x and 5.1.x, the handling of integer values was very strict and would reject non-well formed numeric values when a PHP function expected an integer. These checks have now been relaxed to support non-well formed numeric strings such as " 123" and "123 ", and will no longer fail as they did under PHP 5.0.x.

174 Naresh i Technologies

Page 175: Hypertext Preprocessor Demystified

PHP Course Material

However, to promote code safety and input validation, PHP functions will now emit an E_NOTICE when such strings are passed as integers.

Class and object changes

instanceof , is_a() , is_subclass_of() and catch Abstract private methods

Access modifiers in interfaces

Changes in inheritance rules

Class constants

instanceof, is_a(), is_subclass_of() and catch

In PHP 5.0, is_a() was deprecated and replaced by the instanceof operator. There were some issues with the initial implementation of instanceof, which relied on __autoload() to search for missing classes. If the class was not present, instanceof would throw a fatal E_ERROR due to the failure of __autoload() to discover that class. The same behaviour occurred in the catch operator and the is_subclass_of() function, for the same reason.

None of these functions or operators call __autoload() in PHP 5.1.x, and the class_exists() workarounds used in code written for PHP 5.0.x, while not problematic in any way, are no longer necessary.

Abstract private methods

Abstract private methods were supported between PHP 5.0.0 and PHP 5.0.4, but were then disallowed on the grounds that the behaviours of private and abstract are mutually exclusive.

Access modifiers in interfaces

Under PHP 5.0, function declarations in interfaces were treated in exactly the same way as function declarations in classes. This has not been the case since October 2004, at which point only the public access modifier was allowed in interface function declarations. Since April 2005 - which pre-dates the PHP 5.0b1 release - the static modifier has also been allowed. However, the protected and private modifiers will now throw an E_ERROR, as will abstract. Note that this change should not affect your existing code, as none of these modifiers makes sense in the context of interfaces anyway.

Changes in inheritance rules

Under PHP 5.0, it was possible to have a function declaration in a derived class that did not match the declaration of the same function in the base class, e.g.

175 Naresh i Technologies

Page 176: Hypertext Preprocessor Demystified

PHP Course Material

This code will cause an E_STRICT error to be emitted under PHP 5.1.x.

<?phpclass Base {    function &return_by_ref() {        $r = 1;        return $r;    }}

class Derived extends Base {    function return_by_ref() {        return 1;    }}?>

Class constants

Under PHP 5.0.x, the following code was valid:

Under PHP 5.1.x, redefinition of a class constant will throw a fatal E_ERROR.

<?phpclass test {    const foobar = 'foo';    const foobar = 'bar';}

?>

Extensions

Extensions that are gone from the PHP core

Class constants in new PHP 5.1.x extensions

Extensions that are gone from the PHP core

One of the first things you're likely to notice when you download PHP 5.1.x is that several of the older extensions have disappeared. Those extensions that are still actively maintained are available in the PHP Extension Community Library (PECL), at » http://pecl.php.net/.

Removed extensions

Extension Alternative/Status

ext/cpdf pecl/pdflib

176 Naresh i Technologies

Page 177: Hypertext Preprocessor Demystified

PHP Course Material

Removed extensions

Extension Alternative/Status

ext/dbx pecl/dbx

ext/dio pecl/dio

ext/fam Not actively maintained

ext/ingres_ii pecl/ingres

ext/ircg Not actively maintained

ext/mcve pecl/mcve

ext/mnogosearch Not actively maintained

ext/oracle ext/oci8 or ext/pdo_oci

ext/ovrimos Not actively maintained

ext/pfpro Not actively maintained

ext/w32api » pecl/ffi

ext/yp Not actively maintained

ext/activescript » pecl/activescript

Modules in PECL that are not actively maintained (i.e. have not been supported for some time, have no active maintainer working on them currently, and do not have any PECL package releases), are still available in CVS at » http://cvs.php.net/pecl. However, unreleased PHP modules are by their nature unsupported, and your mileage may vary when attempting to install or use them.

Class constants in new PHP 5.1.x extensions

The Zend Engine 2.1 API allows extension developers to declare class constants in object oriented extensions. New extensions written for PHP 5.1.x, including SPL, PDO, XMLReader and date, have their constants in the format PDO::CLASS_CONSTANT rather than in the C format PDO_CLASS_CONSTANT in order to minimise pollution of the global namespace in PHP.

Date/time support

Date/time support has been fully rewritten in PHP 5.1.x, and no longer uses the system settings to 'know' the timezone in operation. It will instead utilize, in the following order:

177 Naresh i Technologies

Page 178: Hypertext Preprocessor Demystified

PHP Course Material

The timezone set using the date_default_timezone_set() function (if any) The TZ environment variable (if non empty)

"magical" guess (if the operating system supports it)

If none of the above options succeeds, UTC

To ensure accuracy (and avoid an E_STRICT warning), you will need to define your timezone in your php.ini using the following format:

date.timezone = Europe/London

The supported timezones are listed, in this format, in the timezones appendix.

Also note that strtotime() now returns FALSE on failure, instead of -1.

Changes in database support

PDO overview Changes in MySQL support

Changes in SQLite support

PDO overview

PHP Data Objects (PDO) were introduced as a PECL extension under PHP 5.0, and became part of the core PHP distribution in PHP 5.1.x. The PDO extension provides a consistent interface for database access, and is used alongside database-specific PDO drivers. Each driver may also have database-specific functions of its own, but basic data access functionality such as issuing queries and fetching data is covered by PDO functions, using the driver named in PDO::__construct().

Note that the PDO extension, and its drivers, are intended to be built as shared extensions. This will enable straightforward driver upgrades from PECL, without forcing you to rebuild all of PHP.

At the point of the PHP 5.1.x release, PDO is more than ready for widespread testing and could be adopted in most situations. However, it is important to understand that PDO and its drivers are comparatively young and may be missing certain database-specific features; evaluate PDO carefully before you use it in new projects.

Legacy code will generally rely on the pre-existing database extensions, which are still maintained.

Changes in MySQL support

In PHP 4, MySQL 3 support was built-in. With the release of PHP 5.0 there were two MySQL extensions, named 'mysql' and 'mysqli', which were designed to support MySQL < 4.1 and

178 Naresh i Technologies

Page 179: Hypertext Preprocessor Demystified

PHP Course Material

MySQL 4.1 and up, respectively. With the introduction of PDO, which provides a very fast interface to all the database APIs supported by PHP, the PDO_MYSQL driver can support any of the current versions (MySQL 3, 4 or 5) in PHP code written for PDO, depending on the MySQL library version used during compilation. The older MySQL extensions remain in place for reasons of back compatibility, but are not enabled by default.

Changes in SQLite support

In PHP 5.0.x, SQLite 2 support was provided by the built-in sqlite extension, which was also available as a PECL extension in PHP 4.3 and PHP 4.4. With the introduction of PDO, the sqlite extension doubles up to act as a 'sqlite2' driver for PDO; it is due to this that the sqlite extension in PHP 5.1.x has a dependency upon the PDO extension.

PHP 5.1.x ships with a number of alternative interfaces to sqlite:

The sqlite extension provides the "classic" sqlite procedural/OO API that you may have used in prior versions of PHP. It also provides the PDO 'sqlite2' driver, which allows you to access legacy SQLite 2 databases using the PDO API.

PDO_SQLITE provides the 'sqlite' version 3 driver. SQLite version 3 is vastly superior to SQLite version 2, but the file formats of the two versions are not compatible.

If your SQLite-based project is already written and working against earlier PHP versions, then you can continue to use ext/sqlite without problems, but will need to explicitly enable both PDO and sqlite. New projects should use PDO and the 'sqlite' (version 3) driver, as this is faster than SQLite 2, has improved locking concurrency, and supports both prepared statements and binary columns natively.

You must enable PDO to use the SQLite extension. If you want to build the PDO extension as a shared extension, then the SQLite extension must also be built shared. The same holds true for any extension that provides a PDO driver

Checking for E_STRICT

If you only have a single script to check, you can pick up E_STRICT errors using PHP's commandline lint facility:

php -d error_reporting=4095 -l script_to_check.php

For larger projects, the shell script below will achieve the same task:

#!/bin/sh

directory=$1

shift

179 Naresh i Technologies

Page 180: Hypertext Preprocessor Demystified

PHP Course Material# These extensions are checkedextensions="php inc"

check_file (){ echo -ne "Doing PHP syntax check on $1 ..."

# Options: ERRORS=`/www/php/bin/php -d display_errors=1 -d html_errors=0 -d error_prepend_string=" " -d error_append_string=" " -d error_reporting=4095 -l $1 | grep -v "No syntax errors detected"`

if test -z "$ERRORS"; then echo -ne "OK." else echo -e "Errors found!\n$ERRORS" fi

echo}

# loop over remaining file argsfor FILE in "$@" ; do for ext in $extensions; do if echo $FILE | grep "\.$ext$" > /dev/null; then if test -f $FILE; then check_file "$FILE" fi fi donedone

add a note User Contributed Notes

Checking for E_STRICT designteam at casemumbai dot com26-Nov-2008 06:39

Example usage:

<?php//Errors will be printed on the screen with the following lineerror_reporting(E_STRICT);

function change (&$var) {  $var += 10;}

$var = 1;change(++$var);echo "var=$var";change($var = 5);echo "var=$var";

180 Naresh i Technologies

Page 181: Hypertext Preprocessor Demystified

PHP Course Material?>

181 Naresh i Technologies