INTRODUKTION AND INSTALLATION OF PHP This chapter describes: What is PHP. Download PHP binary version for Windows. Writing the first PHP script. Installing PHP on IIS as CGI. 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 very popular. Here is a comparison of number of matches on Google: Key words Number of matches PHP script 13,600,000 Perl script 11,900,000 ASP script 8,650,000 Downloading PHP 5.0.4 for Windows 1. Go to http://www.php.net, and download PHP 5.0.4 binary for Windows. You will get a file called php-5.0.4-Win32.zip of 7488 KB. 2. Unzip php-5.0.4-Win32.zip to \php directory. 3. Open a command window, and try the following commands: >\php\php -v PHP 5.0.4 (cli) (built: Mar 31 2005 02:45:48) Copyright (c) 1997-2004 The PHP Group Zend Engine v2.0.4-dev, Copyright (c) 1998-2004 Zend Technologies >\php\php-cgi -v PHP 5.0.4 (cgi-fcgi) (built: Mar 31 2005 02:45:43) Copyright (c) 1997-2004 The PHP Group Zend Engine v2.0.4-dev, Copyright (c) 1998-2004 Zend Technologies Cool, both Command Line Interface (CLI) and Common Gateway Interface (CGI) are working! My First PHP Script - Hello.php Use any text editor, and enter the first PHP script, Hello.php: Hello Let's run it PHP CLI first: >\php\php Hello.php Hello world! Now run it PHP CGI: >\php\php-cgi Hello.php Content-type: text/html X-Powered-By: PHP/5.0.4 Hello world! As expected, PHP CGI did generate the HTTP response header for me. 1 Installing PHP with IIS as CGI 1. Add \php to the PATH environment variable. I assume you know how to do this. 2. Set up PHP configuration file. First rename \php\php.ini-recommended to \php\php.ini. Then edit \php\php.ini to set the following values: cgi.force_redirect = 0 doc_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. Run Control Panel, Internet Information Service, 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. 6. Copy Hello.php to \inetpub\wwwroot. 7. Run Internet Explorer (IE) with http://localhost/Hello.php. You should see: Hello world! Congratulation, you have installed PHP with IIS as CGI correctly! Conclusion Installation PHP on Windows IIS as CGI seems to be simple. Of course, you can also install PHP with IIS as a server module, using php5isapi.dll. For additional installation instructions, please read \php\install.txt. PHP SYNTAX This chapter describes: How to begin and end a PHP code block. How a PHP input file will be processed. How to enter comments in a PHP code block. PHP Code Blocks Like any other scripting language, PHP is used to transform text information from an input to an output by mixing PHP code segments in the input text. Here is how a PHP input file should look like: text PHP_code text PHP_code text PHP_code ... There are 3 basic ways to mark the beginning and ending of a PHP code segments: 1. HTML "script" tag: <script language="php">PHP_code</script> 2. XML processing instruction: <?php PHP_code ?> 3. Short XML processing instruction: <? PHP_code ?> PHP Processing Behavior As I mentioned previously, a PHP input is a sequence text blocks and PHP code blocks. The PHP engine will process the sequence as if it was a single PHP code block by: 2 First converting each text block into a PHP statement of print "text". Then joining code blocks with the converted print statements to form a single PHP code block. PHP's processing behavior is very similar to Active Server Page (ASP)'s processing behavior. Now let's see an example PHP input file: <?php /* HeadOrTail.php * Copyright (c) 2002 by Dr. Herong Yang */ ?> I am tossing a coin now. Guess what the result will be? <?php $coin = rand(0,1); ?> <?php if ($coin==1) { ?> Head <?php } else { ?> Tail <?php } ?> If you run this file, you may get: I am tossing a coin now. Guess what the result will be? Tail Of course, we could rewrite HeadOrTail.php as HeadOrTailModified.php: <?php /* HeadOrTailModified.php * Copyright (c) 2002 by Dr. Herong Yang */ ?> I am tossing a coin now. Guess what the result will be? <?php $coin = rand(0,1); if ($coin==1) { print " Head"; } else { print " Tail"; } ?> PHP Comments and Statement Delimiter There are 3 ways to enter comments in a PHP code block: Perl style: Using "#" Java style: Using "//" C style: Using "/*" and "*/" PHP uses semicolon ";" as the statement delimiter. DATA TYPES AND VARIABLES This chapter describes: What are PHP data types. How to define variables, references, and variable variable names. How to define and use constants. Data Types PHP supports 8 data types: boolean: It has only two literal values: 'true' and 'false'. integer: It is stored as signed integers with 32 bits. Integer literals have 3 forms: decimal, octal (prefixed with '0'), and hexadecimal (prefixed with '0x'). float: It is stored as IEEE double floating point numbers with 64 bits. Float literals have the standard floating point number forms. 3 string: It is a sequence of 8-bit characters. String literals have 3 forms: single quoted, double quoted, and heredoc syntax. These forms are very similar to Perl. array: It stores an ordered map of pairs of keys and values. This is quite different than the array type used in other languages. object: It stores an instance of a class. resource: It represents an external resource like a file, or a database connection. null: It represents a status of a variable in which no value is assigned the variable. Null type has only one literal value: 'null'. Variables Like Perl, a PHP variable name must be prefixed with a "$" sign. PHP variables do not need declaration. Variable can be assigned with one type of data, then reassigned with another type of data. Reference: PHP supports a reference concept, where a reference of a variable can be expressed with the reference operator '&', and assigned to a new variable. Once assigned with a reference, the new variable and the old variable become aliases to each other. They are sharing the storage location in memory. Variable Variable Name: PHP supports a dynamic variable name concept, where a variable name can be expressed as a string expression in the form of ${string_expression}. If the string expression is only a single variable, it can also be written as $$variable. To show you some of the variable features, I wrote the following PHP script, VariableTest.php: <?php # VariableTest.php # Copyright (c) 2002 by Dr. Herong Yang # print "\nSimple assignments:\n"; $a = 777; # Assigning an integer print " a = $a\n"; $b = 3.14; # Assigning a float print " b = $b\n"; $c = "Hello"; # Assigning a string print " c = $c\n"; $d = true; print " d = $d\n"; # print "\nSpecial assignments:\n"; $a = "Test"; # Re-assigning a string print " a = $a\n"; $a = null; # Assigning no-value print " a = $a\n"; $x = &$a; # Assigning a reference $x = 888; # Assigning an integer to an alias. print " a = $a\n"; # print "\nVariable variable names:\n"; ${'a'} = 999; # Variable variable name as a string literal print " a = $a\n"; $y = 'a'; ${$y} = 888; # Variable variable name as a string variable print " a = $a\n"; $$y = 777; print " a = $a\n"; ?> Here is the output: Simple assignments: 4 a = 777 b = 3.14 c = Hello d=1 Special assignments: a = Test a= a = 888 Variable variable names: a = 999 a = 888 a = 777 As you can see from the output, the print statement seems to behave differently than other languages: The print statement prints boolean true as 1. The print statement prints null as nothing. Constants PHP supports constants with the following rules: Constants can be defined with the define("constant_name", value) function. Constant names can not be redefined. Constant values can be referred by constant names. OPERATIONS AND EXPRESSIONS This chapter describes: What are PHP operations. How expression works in PHP. Operations PHP supports most types of operations used in other languages: Bitwise Operations: and, or, xor, not, shift left, and shift right. Incrementing/Decrementing Operations: pre-inrement, post-increment, pre-decrement, and post-decrement. Arithmetic Operations: negation, addition, subtraction, multiplication, division, and modulus. Comparison Operations: equal, identical, not equal, not identical, less than, greater than, less than or equal, and greater than or equal to. Logical Operations: and, or, xor, and not. String Operations: concatenation. Note that "identical" and "not identical" operations are not commonly used in other languages. Expressions PHP supports most common rules on building expressions in other languages. It also supports some special rules: The data type of the resulting value of an expression does not match the data type required by the evaluation context, the resulting value will be automatically converted the required data type. 5 Like Perl, 0 and no-value will be converted to false in a boolean context. Other values will be converted to true in a boolean context. Assignment is also an expression. The resulting value of an assignment is the value used in the assignment. To show you some of the features, I wrote the following sample PHP script, ExpressTest.php: <?php # ExpressionTest.php # Copyright (c) 2002 by Dr. Herong Yang # print "\nSimple expressions:\n"; $a = 1 + 2 * 3 / 4; # Expression with arithmetic operations print " a = $a\n"; $b = 'A' + 1; # Context requires 'A' to be evaluated to a float print " b = $b\n"; $c = 'A' . 1; # Context requires 1 to be evaluated to a string print " c = $c\n"; $d = true && 9; # Context requires 9 to be evaluated to true print " d = $d\n"; # print "\nSpecial expressions:\n"; $a = $b = "Apple"; # Using assignement as an expression print " a = $a\n"; $x = $a === $b; print " x = $x\n"; ?> Here is the output: Simple expressions: a = 2.5 b=1 c = A1 d=1 Special expressions: a = Apple x=1 FLOW CONTROL STATEMENTS This chapter describes: What are conditional statements. What are loop statements. Conditional Statements PHP supports most types of conditional statements used in other languages: "if ... elseif ... else" statements. "switch ... case ... default" statements. Like other languages, "break" statements can be used in the "case" clauses to break out the "switch" statements. Here is my standard test program for flow control statements, LibraryHours.php: <?php # LibraryHours.php # Copyright (c) 2002 by Dr. Herong Yang # 6 $dateInfo = getdate(); $wDay = $dateInfo["wday"]; $weekDay = $dateInfo["weekday"]; $openHours = "open"; # print "\nLibrary Hours with \"if\" statements:\n"; print " Today is: $weekDay\n"; 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 " The library is $openHours\n"; # 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"; ?> Output of the program: C:\herong\php_20050402\src>php LibraryHours.php Library Hours with "if" statements: Today is: Saturday The library is open from 9:00am to 5:00pm Library Hours with "switch" statements: Today is: Saturday The library is open from 9:00am to 5:00pm Loop Statements PHP supports most types of loop statements used in other languages: "while" statements. "for" statements. 7 "foreach" statements. "do ... while" statements. Here is my standard test program for loop statements, PrimeNumbers.php: <?php # PrimeNumbers.php # Copyright (c) 2002 by Dr. Herong Yang # $upperLimit = 20; # print "\nCalculating prime numbers with \"for\" statements:\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 "\nCalculating prime numbers with \"while\" statements:\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++; } ?> Output of the program: Calculating prime numbers with "for" statements: 3 is a prime number. 4 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. Calculating prime numbers with "while" statements: 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. 8 FUNCTIONS This chapter describes: How to define functions. How to pass references to and returning a reference from functions. User Defined Functions PHP supports user defined functions like in other languages, with some special features: By default, arguments are passed by value. But arguments can also be passed as references. Arguments can be assigned with default values. Functions can return values or references. Function names can also be string expressions. This is called variable functions. Functions can be defined inside another code block, or function. Passing and Returning References The following sample script shows how references can be passed to and returned from a function, FunctionTest.php: <?php # FunctionTest.php # Copyright (c) 2002 by Dr. Herong Yang # print "\nPassing arguments as references:\n"; $x = "Apple"; $y = "Orange"; swap($x,$y); print " x = $x\n"; print " y = $y\n"; # print "\nReturning a reference:\n"; $x = 10; $y = &ref($x); $x = 20; print " y = $y\n"; # function swap(&$a, &$b) { $c = $b; $b = $a; $a = $c; } function &ref(&$a) { return $a; } ?> Here is the output of the program: Passing arguments as references: x = Orange y = Apple Returning a reference: y = 20 I am sure you know why we getting this output. 9 ARRAYS This chapter describes: What is an array in PHP. Array related functions. What Is an Array in PHP? Array: In PHP, an array represents an ordered map of pairs of keys and values. This is different than most of other languages. Basic rules for PHP's array 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: $myArray[kx] = vx 5. A new pair of key and value can be added to an array by an assignment statement, like: $myArray[kx] = vx 6. If a string key represents an integer, it will be used as an integer key. So $myArray['7'] is the same as $myArray[7]. 7. 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. 8. An empty string is also a valid string key, like: $myArray[''] = vy; 9. A pair of key and value can be removed by using the unset() function, like: unset($myArray[kn]); 10. Pairs of keys and values are ordered in an array like a queue. New pairs are always added at the end of the array. unset($myArray[kn]); Here is a simple script to show you some of these rules: <?php # ArrayTest.php # Copyright (c) 2003 by Dr. Herong Yang # 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'; 10 $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]); $fruits[1] = 'Orange'; print_r($fruits); ?> Here is the output: 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. 11 Array Related Built-in Functions 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. 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. 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 # Copyright (c) 2003 by Dr. Herong Yang # 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 Conclusion PHP's array is easy to use. But mixing integer indexed array with associate map is kind of confusing. SENDING EMAILS This chapter describes: How to check the mail server on your local Windows system. How to send an email through PHP. Using Local Windows System as a Mail Server If you are running your Web server on a local system and not connected to the Internet, you need to set up your local system as a mail server to test the email function in PHP. If you are running a Linux/Unix system, setting up a mail server is easy. Just run sendmail as daemon. 12 If you are running a Windows system, setting up a mail server is a little bit harder. But most of the time, your local Windows system is probably already running a mail server. Here is how you can check this: 1. Go to Control Panel / Services, and make sure Simple Mail Transfer Protocol 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... help 214-This server supports the following commands: 214 HELO EHLO STARTTLS RCPT DATA RSET MAIL QUIT HELP AUTH BDAT VRFY quit 221 2.0.0 localhost Service closing transmission channel If you got similar outputs as above, your mail server is running ok. Sending an Email with PHP First you need to verify \php\php.ini to make sure the following settings: SMTP = localhost smtp_port = 25 Now run the following PHP script, MailTest.php: <?php # MailTest.php # Copyright (c) 2002 by Dr. Herong Yang # mail("nobody","Testing","This is a test.","From: herong@localhost"); ?> Then 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@localhost x-receiver: nobody@localhost Received: from localhost ([127.0.0.1]) by localhost with Microsoft... Subject: Testing To: nobody From: herong@localhost Return-Path: herong@localhost ...... This is a test. If you can follow me to here, you have successfully configured your local system to send emails with PHP. HTTP REQUEST VARIABLES This chapter describes: What are the predefined variables that store information from the HTTP request. A sample script to test request variables. How to promote request variables to stand alone variables. 13 Predefined Variables Related to HTTP Request When PHP is used on a Web server to handle a HTTP request, it converts information submitted in the HTTP request as predefined variables: $_GET - Associate array of variables submitted with GET method. $_POST - Associate array of variables submitted with POST method. $_COOKIE - Associate array of variables submitted as cookies. $_REQUEST - Associate array of variables from $_GET, $_POST, and $_COOKIE. $_SERVER - Associate array of all information from the server and the HTTP request. Variables in those arrays can also be promoted (registered) as stand alone global variables using one of the following two ways: Change "register_globals = on" in php.ini to register HTTP request variables on the entire server. Call import_request_variables() to register HTTP request variables in one script only. Here is my standard test program for HTTP request variables: <?php # HttpRequestDetails.php # Copyright (c) 2002 by Dr. Herong Yang # 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"; ?> Run HttpRequestDetails.php at the command line, you will get: <pre> Contents of $_GET: Contents of $_POST: 14 Contents of $_COOKIE: Contents of $_REQUEST: Contents of $_SERVER: CLIENTNAME = Console ComSpec = C:\WINDOWS\system32\cmd.exe HOMEDRIVE = C: PHPRC = c:\local\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 ...... </pre> Not very interesting, right? $_GET, $_POST, $_COOKIE, and $_REQUEST are all empty. Testing Request Variables - HttpRequestDetails.php Now, let's run HttpRequestDetails.php on the local 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 15 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 ...... $_GET is still empty, because nothing is submitted in the HTTP request. 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 ...... Registering HTTP Request Variables as Global Variables As I mentioned in the first section, there are two ways to promote variables stored in the request as stand alone global variables: To promote request variables for the entire server, edit \php\php.ini and set: register_globals = on To promote request variables for one script only, use the following function: import_request_variables("GPC",$prefix); where "GPC" indicates that all variables from GET, POST and COOKIE are prompted. $prefix defines a prefix string that are to be added to the variable names. Here is a sample script, RequestVariables.php <?php # RequestVariables.php # Copyright (c) 2002 by Dr. Herong Yang # print "<pre>\n"; print "\nContents of \$_REQUEST:\n"; foreach ($_REQUEST as $k => $v) { print " $k = $v\n"; } # print "\nLocl 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"; 16 print " \$lang = $lang\n"; print " \$search = $search\n"; print "</pre>\n"; ?> Try the script with http://localhost/RequestVariables.php?lang=PHP&search, you will get: Contents of $_REQUEST: lang = PHP search = Locl imported variables from the request: $r_lang = PHP $r_search = Globaly imported variables from the request: $lang = PHP $search = Conclusion $_GET in PHP is similar to the request.QueryString object in ASP. $_POST in PHP is similar to the request.Form object in ASP. Promoting variables in the request to be stand alone variable makes it easy to use them. But it also increases the risk of colliding them with other variables used in the script. SESSIONS This chapter describes: What is a session. How use session in a PHP script. A session test with 3 scripts. How session ID can be managed without cookies. Where is session data stored. What is a Session? Session: An abstract concept to represent a series of HTTP requests and responses exchanged between a specific Web browser and a specific Web server. 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 way to support session concept. The key design element of session support is about how to identify a session and how to maintain the session ID (identification). One common way to maintain the session ID is use the cookie technology. The following diagram shows you how to do this: Server Browser ID 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 --> | | ...... | 17 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 send back to the same browser as a cookie. The browser will remember this ID, and send the ID back to the server in the subsequent requests. When the server receives a request with a session ID in them, it knows this 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. 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 associated session ID, the server should give an invalid session error. PHP's Session Support Like JavsServer Page (JSP), PHP manages the session ID with as a cookie, a GET variable, or a POST variable. It offer a built-in array as the session object, and a number of built-in functions to allow the PHP script to interact with the session: $_SESSION - A built-in array to store and share variables for the session. session_start() - A built-in function to create a new session or resume an existing session based on the current session id that's being passed via a request, such as GET, POST, or a cookie. session_name() - A built-in function to set and get the session name. session_id() - A built-in function to set and get the session ID. session_destroy() - A built-in function to destroy all variables stored in $_SESSION. Session Test Scripts - SessionPageN.php To help testing the session concept, I wrote 3 PHP scripts. SessionPage1.php: <?php # SessionPage1.php # Copyright (c) 2002 by Dr. Herong Yang # 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"; } 18 # 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"; ?> <?php # SessionPage2.php # Copyright (c) 2002 by Dr. Herong Yang # session_start(); $quantity = $_SESSION['quantity']; $price = 9.99; $_SESSION['price'] = $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 "\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"; ?> SessionPage3.php: <?php # SessionPage3.php # Copyright (c) 2002 by Dr. Herong Yang # session_start(); $quantity = $_SESSION['quantity']; $price = $_SESSION['price']; 19 $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) { print " $k = $v\n"; } # print "\nContents of \$_COOKIE:\n"; foreach ($_COOKIE as $k => $v) { print " $k = $v\n"; } print "</pre>\n"; ?> If you run http://localhost/SessionPage1.php, you will get: I am buying 3 PHP books. Next Counter = 1 Session name = PHPSESSID Session id = o9oipjgc4r3fqmfk8mlldl5sl5 Contents of $_GET: Contents of $_POST: Contents of $_COOKIE: If click "Next" on the first page, you will be running http://localhost/SessionPage2.php, and you will get: I am buying 3 PHP books. The unit price is 9.99 per book. Next Prev Counter = 2 Session name = PHPSESSID Session id = o9oipjgc4r3fqmfk8mlldl5sl5 Contents of $_GET: 20 Contents of $_POST: Contents of $_COOKIE: PHPSESSID = o9oipjgc4r3fqmfk8mlldl5sl5 If click "Next" on the second page, you will be running http://localhost/SessionPage3.php, and you will get: I am buying 3 PHP books. The unit price is 9.99 per book. The total price is 29.97. Prev Counter = 3 Session name = PHPSESSID Session 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 something called application object provided in Active Server Page (ASP). Managing Session ID without Cookie PHP can also manage session IDs without using the cookie technology. To do this, we need to modify \php\php.ini to stop using cookie and start transparent session id: session.use_cookies = 0 session.use_trans_sid = 1 Now if you re-run http://localhost/SessionPage1.php, you will get: I am buying 3 PHP books. Next Counter = 1 Session name = PHPSESSID Session id = mg04r204ctuloo2uegmih14ri5 Session module = files Contents of $_GET: Contents of $_POST: Contents of $_COOKIE: 21 If click "Next" on the first page, you will be running http://localhost/SessionPage2.php, and you will get: I am buying 3 PHP books. The unit price is 9.99 per book. Next Prev Counter = 2 Session name = PHPSESSID Session id = mg04r204ctuloo2uegmih14ri5 Contents of $_GET: PHPSESSID = mg04r204ctuloo2uegmih14ri5 Contents of $_POST: Contents of $_COOKIE: If click "Next" on the second page, you will be running http://localhost/SessionPage3.php, and you will get: I am buying 3 PHP books. The unit price is 9.99 per book. The total price is 29.97. Prev Counter = 3 Session name = PHPSESSID Session id = mg04r204ctuloo2uegmih14ri5 Contents of $_GET: PHPSESSID = mg04r204ctuloo2uegmih14ri5 Contents of $_POST: Contents of $_COOKIE: A couple of interesting things happened here: If you ask PHP to use transparent session ID management, it will modify all the links to include the session ID as part of the URL. See the source of the first page in the browser, you will see the ULR of "Next" button as href=SessionPage2.php?PHPSESSID=mg04r204ctuloo2uegmih14ri5. The outputs show that now the session ID is stored in $_GET. Since the session ID in the URL field of the browser, everyone can see it. Not so secure. Where Is Session Data Stored? Question, where does PHP store the session data? The answer is not so obvious. Since I am running PHP in CGI mode, PHP pages are running with individual instances of PHP executables. So there is no easy to store session data in memory and share it between PHP pages. If not stored in memory, the session data can be stored on hard disk and share it between PHP pages. Let's see if we can find where the session data is stored on the hard disk. First run http://localhost/SessionPage1.php again: I am buying 3 PHP books. Next 22 Counter = 1 Session name = PHPSESSID Session id = mg04r204ctuloo2uegmih14ri5 Session module = files Contents of $_GET: Contents of $_POST: Contents of $_COOKIE: Then use Windows find tool to search for file names with "mg04r204ctuloo2uegmih14ri5". No surprise, you will get \windows\temp\sess_mg04r204ctuloo2uegmih14ri5. Open this file in a text editor, you will see: quantity|i:3;count|i:1; The file format is so simple, session data is stored as clear text, with ";" as delimiters. If you want to change where the data is stored, you can modify \php\php.ini with: session.save_path = "/tmp" Conclusion PHP can manage session IDs in two ways: as a cookie and as GET variable. Managing sessions with cookies is much secure. Session data is stored on hard disk permanently. You must call session_start() at the beginning of the PHP script. Session data is shared in an array called $_SESSION. USING PHP WITH MYSQL This chapter describes: How to configure PHP with a MySQL server. What are the basic functions to use a MySQL server. A test script with a MySQL server. Configuring PHP with MySQL To use PHP with MySQL, of course you need to install MySQL server on you system first. On my local system, I have MySQL server installed in \mysql directory. If you need help on installing MySQL on your system, please read "Herong's Notes on SQL". To make sure MySQL is running on my local system, I did this in a command window: >\mysql\bin\mysqld >\mysql\bin\mysqladmin ping mysqld is alive Now edit \php\php.ini with: extension=php_mysql.dll Then add \php\ext to the PATH system environment variable. I think we are ready to test the configuration. Run this script: <?php # MySqlTest.php # Copyright (c) 2002 by Dr. Herong Yang # $con = mysql_connect('localhost'); print "MySQL server info = ".mysql_get_server_info()."\n"; 23 print "MySQL status = ".mysql_stat()."\n"; mysql_close($con); ?> You should get something like: C:\herong\php_20050403\src>php MySqlTest.php MySQL server info = 5.0.2-alpha MySQL status = Uptime: 1167 Threads: 1 Questions: 5 Slow querie... Flush tables: 1 Open tables: 0 Queries per second avg: 0.004 Cool, I can now access my MySQL server from PHP scripts. PHP's MySQL Support PHP's MySQL support comes from an extension library, php_mysql.dll, which offeres a number of functions: mysql_connect() - Connects to a MySQL server, and returns a connection resource. mysql_close() - Closes a MySQL connection resource. 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. 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. MySQL Test - MySqlLoop.php To show you some those functions should be used, I wrote this simple script, MySqlLoop.php: <?php # MySqlLoop.php # Copyright (c) 2002 by Dr. Herong Yang # $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"; } 24 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 Conclusion PHP supports MySQL through an extension library. Configuring PHP to with a MySQL server is simple. Database functions are server dependent. DIRECTORIES, FILES AND IMAGES This chapter describes: Directory functions. File system functions. Image functions. ShowPhoto.php - a sample program. Directory Functions PHP offers the following built-in functions to manage directories of file systems: chdir -- Change directory chroot -- Change the root directory dir -- Directory class closedir -- Close directory handle getcwd -- Gets the current working directory opendir -- Open directory handle readdir -- Read entry from directory handle rewinddir -- Rewind directory handle scandir -- List files and directories inside the specified path File System Functions PHP offers a lots of nice built-in functions to manage files: basename -- Returns filename component of path clearstatcache -- Clears file status cache 25 26 copy -- Copies file dirname -- Returns directory name component of path disk_free_space -- Returns available space in directory disk_total_space -- Returns the total size of a directory fclose -- Closes an open file pointer feof -- Tests for end-of-file on a file pointer fflush -- Flushes the output to a file fgetc -- Gets character from file pointer fgetcsv -- Gets line from file pointer and parse for CSV fields fgets -- Gets line from file pointer fgetss -- Gets line from file pointer and strip HTML tags file_exists -- Checks whether a file or directory exists file_get_contents -- Reads entire file into a string file_put_contents -- Write a string to a file file -- Reads entire file into an array fileatime -- Gets last access time of file filemtime -- Gets file modification time fileperms -- Gets file permissions filesize -- Gets file size filetype -- Gets file type flock -- Portable advisory file locking fnmatch -- Match filename against a pattern fopen -- Opens file or URL fpassthru -- Output all remaining data on a file pointer fputcsv -- Format line as CSV and write to file pointer fread -- Binary-safe file read fscanf -- Parses input from a file according to a format fseek -- Seeks on a file pointer fstat -- Gets information about a file using an open file pointer ftell -- Tells file pointer read/write position ftruncate -- Truncates a file to a given length fwrite -- Binary-safe file write glob -- Find pathnames matching a pattern is_dir -- Tells whether the filename is a directory is_executable -- Tells whether the filename is executable is_file -- Tells whether the filename is a regular file is_link -- Tells whether the filename is a symbolic link is_readable -- Tells whether the filename is readable is_uploaded_file -- Tells whether the file was uploaded via HTTP POST is_writable -- Tells whether the filename is writable link -- Create a hard link linkinfo -- Gets information about a link lstat -- Gives information about a file or symbolic link mkdir -- Makes directory move_uploaded_file -- Moves an uploaded file to a new location parse_ini_file -- Parse a configuration file pathinfo -- Returns information about a file path pclose -- Closes process file pointer popen -- Opens process file pointer readfile -- Outputs a file readlink -- Returns the target of a symbolic link realpath -- Returns canonicalized absolute pathname rename -- Renames a file or directory rewind -- Rewind the position of a file pointer rmdir -- Removes directory stat -- Gives information about a file symlink -- Creates a symbolic link tempnam -- Create file with unique file name tmpfile -- Creates a temporary file touch -- Sets access and modification time of file umask -- Changes the current umask unlink -- Deletes a file Image Functions With GB library installed, PHP offers a lots of nice functions to manage images: gd_info -- Retrieve information about the currently installed GD library getimagesize -- Get the size of an image image_type_to_extension -- Get file extension for image type image_type_to_mime_type -- Get Mime-Type for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype image2wbmp -- Output image to browser or file imageantialias -- Should antialias functions be used or not imagearc -- Draw a partial ellipse imagechar -- Draw a character horizontally imagecolorallocate -- Allocate a color for an image imagecolorat -- Get the index of the color of a pixel imagecolorexact -- Get the index of the specified color imagecolorsforindex -- Get the colors for an index imagecolorstotal -- Find out the number of colors in an image's palette imagecolortransparent -- Define a color as transparent imagecopy -- Copy part of an image imagecopymerge -- Copy and merge part of an image imagecopyresized -- Copy and resize part of an image imagecreatefromgif -- Create a new image from file or URL imagecreatefromjpeg -- Create a new image from file or URL imagecreatefromwbmp -- Create a new image from file or URL imagedestroy -- Destroy an image imagefill -- Flood fill imagefilledarc -- Draw a partial ellipse and fill it imagefilledrectangle -- Draw a filled rectangle imagefilltoborder -- Flood fill to specific color imagefttext -- Write text to the image using fonts using FreeType 2 imagegif -- Output image to browser or file imagejpeg -- Output image to browser or file imageline -- Draw a line imageloadfont -- Load a new font imagepolygon -- Draw a polygon imagerectangle -- Draw a rectangle imagesetpixel -- Set a single pixel imagestring -- Draw a string horizontally imagesx -- Get image width imagesy -- Get image height imagettftext -- Write text to the image using TrueType fonts imagewbmp -- Output image to browser or file jpeg2wbmp -- Convert JPEG image file to WBMP image file png2wbmp -- Convert PNG image file to WBMP image file ShowPhoto.php - Showing Images in a Directory To show you how to use functions directories, files, and images, I wrote the following sample program: <?php # PhotoShow.php # Copyright (c) 2003 by Dr. Herong Yang 27 # #- 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"; } $h = fopen("footer.html", "r"); $s = fread($h, filesize("footer.html")); fclose($h); print "$s\n"; ?> Try it out. It's very easy to use. You can easily customize it to meet your requirements. SOAP, PHP IMPLEMENTATIONS This chapter describes: 28 PHP Implementations of SOAP. Checking My PHP Installation on Windows. Installing SOAP Library on Windows. PHP Implementations of SOAP If you search the Web with the key words "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. Unfortunately, I could not find a clear feature list of the current release of PEAR::Package::SOAP. I could not find a clear feature list of the current release of NuSOAP. Checking My PHP Installation on Windows Since I have PHP installed on my Windows system, I want to see if I have SOAP implementation included or not. I used the phpinfo() function to do this: >type PhpInfo.php <?php phpinfo();?> >php PhpInfo.php > PhpInfo.txt >find /? "soap" PhpInfo.txt ---------- PHPINFO.TXT >php -v PHP 5.0.4 (cli) (built: Mar 31 2005 02:45:48) Copyright (c) 1997-2004 The PHP Group Zend Engine v2.0.4-dev, Copyright (c) 1998-2004 Zend Technologies So no SOAP is available in my installation, which is PHP 5.0.4 by The PHP Group. Installing SOAP Library on Windows Checking my PHP package to see if I have SOAP library file on my system: >dir \php\ext\php_soap.dll 03/31/2005 02:52 AM 217,146 php_soap.dll Cool. I do have the SOAP libary file. No need to download it from the Internet. The next thing I have to do is to make it available to the run time environment by editing \php\php.ini and insert the following line: extension=php_soap.dll Now check again: >php PhpInfo.php > PhpInfo.txt >find /? "soap" PhpInfo.txt ---------- PHPINFO.TXT soap Soap Client => enabled Soap Server => enabled soap.wsdl_cache_dir => /tmp => /tmp soap.wsdl_cache_enabled => 1 => 1 soap.wsdl_cache_ttl => 86400 => 86400 Ok. I think my system is ready to run SOAP functions now. 29 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.dll File Version: 5.0.4.4 Copyright (c) 1997-2004 The PHP Group So the php_soap.dll is 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 this: 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. Conclusion There seems to be 3 popular PHP implementations of SOAP: PEAR SOAP, NuSOAP, and PHP Group SOAP. But I can not find any high level specifications for any of them. The PHP Group SOAP 5.0.4 seems to be supporting SOAP 1.2. PHP, SOAP EXTENSIONS This chapter describes: What is PHP SOAP Extension? My first example with SOAP Extension. SOAP Extension functions for client applications. How to dump detailed information for debugging. A WSDL document example. How use SOAP Extension in non-WSDL mode. What Is PHP SOAP Extension? PHP SOAP Extension is one of the most popular PHP implementations of SOAP 1.1 and 1.2, developed by The PHP Group. What are the features of PHP SOAP Extension? I don't known. I tried to find the feature list on the Web, no success. How to install PHP SOAP Extension? It is included in the PHP 5.0.4 package for Windows distributed by Zend Technologies. See previous notes on details of how to install the PHP package and the PHP SOAP Extension. GetTemp.php - First Example with SOAP To show you an example of how PHP SOAP Extension can be used in a SOAP client application, here is my first SOAP PHP program, GetTemp.php <?php # GetTemp.php # Copyright (c) 2005 by Dr. Herong Yang # $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 GetTemp.php Returning value of getTemp() call: 52 30 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. PHP SOAP Extension Functions for Client Applications 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] ); 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". 31 string $s = $obj->__getLastRequestHeaders(); 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(); GetTempDump.php - Dumping Debugging Information After learning the basic functions of the SoapClient class, I rewrote the GetTemp.php client program to get more information on how SOAP Extension works, and to show you how to debug information. The new client program is called, GetTempDump.php: <?php # GetTempDump.php # Copyright (c) 2005 by Dr. Herong Yang # $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()); ?> Output of this program: Dumping client object: object(SoapClient)#1 (3) { ["trace"]=> int(1) ["_soap_version"]=> int(1) ["sdl"]=> resource(5) of type (Unknown) } Dumping client object functions: array(1) { [0]=> string(30) "float getTemp(string $zipcode)" } 32 Returning value of getTemp() call: 52 Returning value of __soapCall() call: 52 Dumping request headers: POST /soap/servlet/rpcrouter HTTP/1.1 Host: services.xmethods.net Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "" Content-Length: 510 Cookie: 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 OK Server: Enhydra-MultiServer/3.1.1b1 Status: 200 Content-Type: text/xml; charset=utf-8 Servlet-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: 470 X-Cache: MISS from www.xmethods.net Keep-Alive: timeout=15, max=99 Connection: 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 is very useful. It confirms that: 33 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? WSDL (Web Services Definition Language): 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> </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> 34 <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. Using SOAP Extension in non-WDSL Mode 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 getTemp SOAP client program, GetTempNonWsdl.php: <?php # GetTempNonWsdl.php # Copyright (c) 2005 by Dr. Herong Yang # $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)); 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()); ?> Here is output: 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.1 35 Host: services.xmethods.net Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "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 OK Date: Wed, 05 Oct 2005 02:02:46 GMT Server: Enhydra-MultiServer/3.1.1b1 Status: 200 Content-Type: text/xml; charset=utf-8 Servlet-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: 470 Set-Cookie: JSESSIONID=RTiE9NZhFiqCdnPB36zgsXMi;Path=/soap X-Cache: MISS from www.xmethods.net Keep-Alive: timeout=15, max=100 Connection: 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> Output shows that: 36 My GetTempNonWsdl.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". Conclusion SOAP Extension supports SOAP 1.1 by default. I don't know how it works with SOAP 1.2. Needs to test it out. WSDL document does help simplifying the set up process of SOAP calls. But without WSDL documents, making SOAP calls is not that hard. Exercise: Go to http://www.xmethods.net/ and play with another demonstration Web service called: Delayed Stock Quote. PHP SOAP EXTENSION – SERVER APPLICATIONS This chapter describes: PHP SOAP Extension Functions for Server Applications HelloServer.php - First SOAP Server Application HelloServer12.php - SOAP 1.2 Server Application HelloServerWsdl.php - SOAP 1.2 Server Application in WSDL Mode PHP SOAP Extension Functions for Server Applications 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. $obj->addFunction("func"); # adds one function $obj->addFunction(array("func1",...)); # adds many functions 37 $obj->addFunction(SOAP_FUNCTIONS_ALL); # adds all functions SoapServer->setClass() allows you to all 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 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 # Copyright (c) 2005 by Dr. Herong Yang # 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. The HTTP server I will be using is the MS IIS (Internet Information Services). It has already configured correctly to interface with PHP CGI. For details, see my other book: "Herong's Tutorial Notes on PHP". 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 # Copyright (c) 2005 by Dr. Herong Yang # $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()); 38 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.1 Host: localhost Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "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> Dumping response headers: HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Connection: close Content-Type: text/xml; charset=utf-8 X-Powered-By: PHP/5.0.4 Content-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: 39 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 - SOAP 1.2 Server Application 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 # Copyright (c) 2005 by Dr. Herong Yang # 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 # Copyright (c) 2005 by Dr. Herong Yang # $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()); 40 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.1 Host: localhost Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-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 OK Server: Microsoft-IIS/5.1 Connection: close Content-Type: application/soap+xml; charset=utf-8 X-Powered-By: PHP/5.0.4 Content-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> 41 </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 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 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 # Copyright (c) 2005 by Dr. Herong Yang # 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"> 42 <soap:operation soapAction=""/> <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 # Copyright (c) 2005 by Dr. Herong Yang # $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); # $return = $client->hello("world"); # echo("\nReturning value: ".$return); echo("\nDumping request headers:\n" .$client->__getLastRequestHeaders()); echo("\nDumping request:\n".$client->__getLastRequest()); 43 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.1 Host: localhost Connection: Keep-Alive User-Agent: PHP SOAP 0.1 Content-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 OK Server: Microsoft-IIS/5.1 Connection: close Content-Type: application/soap+xml; charset=utf-8 X-Powered-By: PHP/5.0.4 Content-Length: 573 Dumping response: <?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"> 44 <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. The 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. Conclusion SOAP Extension is easy to use for setting up SOAP services quickly. SOAP Extension does support SOAP 1.2 specification. WSDL document is actually easy to understand. Exercise: Write a temperature conversion SOAP service. 45 Introduktion and Installation of PHP .................................................................................................................................... 1 What Is PHP?................................................................................................................................................................. 1 Downloading PHP 5.0.4 for Windows ............................................................................................................................. 1 My First PHP Script - Hello.php ....................................................................................................................................... 1 Installing PHP with IIS as CGI ......................................................................................................................................... 2 PHP Syntax ......................................................................................................................................................................... 2 PHP Code Blocks ........................................................................................................................................................... 2 PHP Processing Behavior ............................................................................................................................................... 2 PHP Comments and Statement Delimiter ....................................................................................................................... 3 Data Types and Variables .................................................................................................................................................... 3 Data Types .................................................................................................................................................................... 3 Variables ....................................................................................................................................................................... 4 Constants ...................................................................................................................................................................... 5 Operations and Expressions ................................................................................................................................................ 5 Operations .................................................................................................................................................................... 5 Expressions ................................................................................................................................................................... 5 Flow Control Statements ..................................................................................................................................................... 6 Conditional Statements ................................................................................................................................................. 6 Loop Statements ........................................................................................................................................................... 7 Functions ........................................................................................................................................................................... 9 User Defined Functions .................................................................................................................................................. 9 Passing and Returning References ................................................................................................................................. 9 Arrays ...............................................................................................................................................................................10 What Is an Array in PHP? ..............................................................................................................................................10 Array Related Built-in Functions ...................................................................................................................................12 Conclusion ..................................................................................................................................................................12 Sending Emails ................................................................................................................................................................12 Using Local Windows System as a Mail Server ..............................................................................................................12 Sending an Email with PHP ..........................................................................................................................................13 HTTP request variables ......................................................................................................................................................13 Predefined Variables Related to HTTP Request .............................................................................................................14 Testing Request Variables - HttpRequestDetails.php ....................................................................................................15 Registering HTTP Request Variables as Global Variables ...............................................................................................16 Conclusion ..................................................................................................................................................................17 Sessions ..........................................................................................................................................................................17 What is a Session? ......................................................................................................................................................17 PHP's Session Support ................................................................................................................................................18 Session Test Scripts - SessionPageN.php .....................................................................................................................18 Managing Session ID without Cookie ...........................................................................................................................21 Where Is Session Data Stored? ....................................................................................................................................22 Conclusion ..................................................................................................................................................................23 Using PHP with MySQL ......................................................................................................................................................23 Configuring PHP with MySQL ........................................................................................................................................23 PHP's MySQL Support .................................................................................................................................................24 MySQL Test - MySqlLoop.php .......................................................................................................................................24 Conclusion ..................................................................................................................................................................25 Directories, Files and Images ............................................................................................................................................25 Directory Functions ......................................................................................................................................................25 File System Functions ..................................................................................................................................................25 Image Functions ..........................................................................................................................................................27 ShowPhoto.php - Showing Images in a Directory ..........................................................................................................27 SOAP, PHP Implementations .............................................................................................................................................28 PHP Implementations of SOAP .....................................................................................................................................29 Checking My PHP Installation on Windows ...................................................................................................................29 Installing SOAP Library on Windows .............................................................................................................................29 PHP, SOAP Extensions ......................................................................................................................................................30 What Is PHP SOAP Extension? ......................................................................................................................................30 PHP SOAP Extension Functions for Client Applications ..................................................................................................31 What Is WSDL? ............................................................................................................................................................34 Using SOAP Extension in non-WDSL Mode ....................................................................................................................35 46 PHP SOAP Extension – Server Applications ........................................................................................................................37 PHP SOAP Extension Functions for Server Applications .................................................................................................37 HelloServer.php - First SOAP Server Application ...........................................................................................................38 HelloServer12.php - SOAP 1.2 Server Application ........................................................................................................40 HelloServerWsdl.php - SOAP 1.2 Server Application in WSDL Mode ..............................................................................42 47