Programming PHPProgramming PHPSearch this book

15.2. Writing Portable Code for Windows and Unix

One of the main reasons for running PHP on Windows is to develop locally before deploying in a production environment. As most production servers are Unix-based, it is important to consider porting[10] as part of the development process and plan accordingly.

[10]For an excellent article on porting between Windows and Linux for many of today's scripting languages, see "Linux to Windows 2000 Scripting Portability," available on the Microsoft developer's web site at http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/iis/deploy/depovg/lintowin.asp. Much of this discussion was abstracted from that paper.

Potential problem areas include applications that rely on external libraries, use native file I/O and security features, access system devices, fork or spawn threads, communicate via sockets, use signals, spawn external executables, or generate platform-specific graphical user interfaces.

The good news is that cross-platform development has been a major goal in the development of PHP. For the most part, PHP scripts should be easily ported from Windows to Unix with few problems. However, there are several instances where you can run into trouble when porting your scripts. For instance, some functions that were implemented very early in the life of PHP had to be mimicked for use under Windows. Other functions may be specific to the web server under which PHP is running.

15.2.1. Determining the Platform

To design with portability in mind, you may want to first test for the platform on which the script is running. PHP defines the constant PHP_OS, which contains the name of the operating system on which the PHP parser is executing. Possible values for the PHP_OS constant include "AIX", "Darwin" (MacOS), "Linux", "SunOS", "WIN32", and "WINNT".

The following code shows how to test for a Windows platform prior to setting an include path:

<?php
 if (PHP_OS == "WIN32" || PHP_OS == "WINNT") {
   define("INCLUDE_DIR","c:\\myapps");
 } else {
   // some other platform
   define("INCLUDE_DIR", "/include");
 }
?>

15.2.2. Handling Paths Across Platforms

PHP understands the use of either backward or forward slashes on Windows platforms, and can even handle paths that mix the use of the two slashes. As of Version 4.0.7, PHP will also recognize the forward slash when accessing Windows UNC paths (i.e., //machine_name/path/to/file). For example, these two lines are equivalent:

$fh = fopen('c:/tom/schedule.txt', 'r');
$fh = fopen('c:\\tom\\schedule.txt', 'r');

15.2.3. The Environment

PHP defines the constant array $HTTP_ENV_VARS, which contains the HTTP environment information. Additionally, PHP provides the getenv( ) function to obtain the same information. For example:

<?php
 echo "Windows Directory is ".$HTTP_ENV_VARS["windir"]."\r\n");
 echo "Windows Directory is ".getenv("windir")."\r\n");
?>
Windows Directory is C:\WINNT
Windows Directory is C:\WINNT

15.2.4. Sending Mail

On Unix systems, you can configure the mail( ) function to use sendmail or Qmail to send messages. You can also do this on Windows systems, as long as you define sendmail_path in php.ini and install sendmail for Windows. More convenient is to simply point the Windows version of PHP to an SMTP server:

[mail function]
SMTP = mail.example.com
sendmail_from = gnat@frii.com

15.2.5. Server-Specific Functions

If compiled as a plug-in for Apache, PHP includes several functions that are specific to the Apache web server. If you use these functions, and are porting your scripts to run under IIS, you will need to reimplement that functionality. Following are the Apache-specific functions and some solutions for replacing them:

getallheaders( )
Fetch all HTTP request headers. You can access the HTTP request headers via the predefined variable $HTTP_ENV_VARS instead of using this function for any web server, including Apache.

virtual( )
Perform an Apache subrequest. This function allows you to include a URI from the local web server in the PHP script. If the retrieved text includes a PHP script, that script will become part of your current script.

apache_lookup_uri( )
Perform a partial request for the specified URI and return all information about it. This function requests Apache to provide information about a URI. No conversion is available for IIS.

apache_note( )
Get and set Apache request notes. This function is used for communication between Apache plug-ins. No conversion is available for IIS.

ascii2ebcdic( ) and ebcdic2ascii( )
These functions translate strings to and from ASCII and EBCDIC. Apache must be compiled with EBCDIC support for these functions to work. PHP provides no other means of converting EBCDIC strings. Microsoft provides a C-based API to handle EBCDIC translations.

There is also a set of IIS-specific functions, though its purpose is primarily for management of IIS.

15.2.6. Remote Files

Under Unix, PHP is able to retrieve remote files via HTTP or FTP for inclusion in your script via the require( ) and include( ) functions. These functions are not available under Windows. Instead, you must write your own subroutine to fetch the remote file, save it to a temporary local file, and then include that file, as shown in Example 15-1.

Example 15-1. Including a remote file with PHP on Windows

<?php
 function include_remote($filename) { 
   $data = implode("\n", file($filename));
   
   if ($data) {
     $tempfile = tempnam(getenv("TEMP"),"inc");
     $fp = fopen( $tempfile,"w"); 
     fwrite( $fp, "$data"); 
     fclose( $fp ); 
  
     include($tempfile); 
     unlink($tempfile);
   }
  
   echo "<b>ERROR: Unable to include ".$filename."</b><br>\n";
   return FALSE;
 }
  
 // sample usage
 include_remote("http://www.example.com/stuff.inc");
?>

15.2.7. End-of-Line Handling

Windows text files have lines that end in "\r\n", whereas Unix text files have lines that end in "\n". PHP processes files in binary mode, so no automatic conversion from Windows line terminators to the Unix equivalent is performed.

PHP on Windows sets the standard output, standard input, and standard error file handles to binary mode and thus does not do any translations for you. This is important for handling the binary input often associated with POST messages from web servers.

Your program's output goes to standard output, and you will have to specifically place Windows line terminators in the output stream if you want them there. One way to handle this is to define an end-of-line constant and output functions that use it:

<?php
 if (PHP_OS == "WIN32" || PHP_OS == "WINNT") {
   define("EOL","\r\n");
 } else if (PHP_OS == "Linux") {
   define("EOL","\n");
 } else {
   define("EOL","\n");
 }
  
 function echo_ln($out) {
   echo $out.EOL;
 }
  
 echo_ln("this line will have the platforms EOL character");
?>

15.2.8. End-of-File Handling

Windows text files end in a Control-Z ("\x1A"), whereas Unix stores file-length information separately from the file's data. PHP recognizes the EOF character of the platform on which it is running. The function feof( ) thus works when reading Windows text files.

15.2.9. External Commands

PHP uses the default command shell of Windows for process manipulation. Only rudimentary Unix shell redirections and pipes are available under Windows (e.g., separate redirection of standard output and standard error is not possible), and the quoting rules are entirely different. The Windows shell does not glob (i.e., replace wildcarded arguments with the list of files that match the wildcards). Whereas on Unix you can say system("someprog php*.inc"), on Windows you must build the list of filenames yourself using opendir( ) and readdir( ).

15.2.10. Common Platform-Specific Extensions

There are currently over 80 extensions for PHP, covering a wide range of services and functionality. Only about half of these are available for both Windows and Unix platforms. Only a handful of extensions, such as the COM, .NET, and IIS extensions, are specific to Windows. If an extension you use in your scripts is not currently available under Windows, you need to either port that extension or convert your scripts to use an extension that is available under Windows.

If you use PHP as a web server plug-in (SAPI), the extensions must be thread-safe. Some extensions depend on third-party libraries that may not be thread-safe, rendering them incompatible with the SAPI plug-in.

Unfortunately, the level of thread safety in PHP extensions is poorly documented, and it will require testing on your part to discover where you may run into difficulty. Fortunately, the more popular an extension is, the greater chance there is of that extension being available on Windows.

In some cases, some functions are not available under Windows even though the module as a whole is. checkdnsrr( ), in the Networking module, is just one example of this problem.

Windows PHP does not support signal handling, forking, or multithreaded scripts. A Unix PHP script that uses these features cannot be ported to Windows. Instead, you should rewrite the script to not take advantage of those features.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.