README for pRuby -- the PHP--Ruby extension
by Szab Pter <pts@fazekas.hu>
this program is free software released under the GNU GPL (v2 or newer)
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!

pRuby is a glue code between PHP and Ruby which lets you use Ruby as a
HTML-embedded, server side scripting language. With pRuby, you can intermix
PHP and Ruby to create dynamic web content. For example, you can call PHP's
database and image drawing functions from Ruby and vice versa. pRuby is
often compared to PHP, mod_ruby, eRuby, Erb, mod_perl and ASP. Key features:
better startup speed than CGI and PHP, better execution speed than PHP, more
powerful and less messier to program than PHP, cross-language function calls
and cross-language error handling.

This document is the README for pRuby. This is the main documentation, this
one should be read first. (Currently this is the only one :-)).

The current version of pRuby is 0.2. It is in beta and unstable state. The
final version of it should be safely usable in production even for heavily
loaded webservers.

Who is responsible for flex.rb?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
entirely Szab Pter <pts@fazekas.hu>

There is no homepage, no mailing list, no downloads, no mirrors, no CVS
repositories (yet).

You may be able to download at http://www.inf.bme.hu/~pts/pruby-latest.tar.gz

The project was in beta status at Sun Dec 17 17:08:36 CET 2000. In that time
there were no bug reports.

The README was started by pts@fazekas.hu at Mon Feb 12 19:01:59 CET 2001.
It was modified at Wed Feb 21 20:37:44 CET 2001

Feature details and comparison with related existing products
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please read this carefully even if you're familiar to both PHP and Ruby.

What is PHP?
""""""""""""
PHP is a server-side web (HTTP, Web) scripting language. See www.php.net if
you don't already know PHP. Quoting the PHP manual:

  PHP, which stands for "PHP: Hypertext Preprocessor", is an                   
  HTML-embedded scripting language. Much of its syntax is borrowed from        
  C, Java and Perl with a couple of unique PHP-specific features thrown        
  in. The goal of the language is to allow web developers to write             
  dynamically generated pages quickly.                                         

PHP means both the programming language and the `technology': the system
with the broad range of generic and web-related functions and extensions.

From now on, I'll refer PHP4 (PHP >=4.0.3) as PHP. Previous versions will be
referred as PHP3 and PHP/FI (PHP 2.0).

What is Zend?
"""""""""""""
The Zend Engine is the compiler and interpreter used in PHP4. It was
written from scratch -- no PHP3 compiler and interpreter code is used in
it. The Zend Engine is _almost_ fully compatible with PHP3. Perhaps the
most noticable difference is that it generates more warnings. (The warnings
can be switched off with the proper call to `error_reporting()'.)

pRuby uses and needs the Zend Engine, so it will not work with PHP3.

What is Ruby?
"""""""""""""
Ruby is the interpreted scripting language for quick and
easy object-oriented programming.  It has many features to
process text files and to do system management tasks (as in
Perl).  It is simple, straight-forward, and extensible.
    
* Features of Ruby
        
  + Simple Syntax
  + *Normal* Object-Oriented features(ex. class, method calls)
  + *Advanced* Object-Oriented features(ex. Mix-in, Singleton-method)
  + Operator Overloading
  + Exception Handling
  + Iterators and Closures
  + Garbage Collection
  + Dynamic Loading of Object files(on some architecture)
  + Highly Portable(works on many UNIX machines, and on DOS,
    Windows, Mac, BeOS etc.)

You can get Ruby from http://www.ruby-lang.org. If you don't already know
Ruby, go there, download it and taste it. I'm sure you'll like it.

Why PHP? Why not mod_ruby? Why not eruby?
"""""""""""""""""""""""""""""""""""""""""
eRuby, used as a CGI is slow: each time the CGI is run, a new process has to
be fork()ed.

mod_ruby works only with the Apache webserver. (Actually, the author will
only test pRuby with Apache, but it shouldn't be hard to use other SAPIs of
PHP.)

mod_ruby requires that you restart Apache each time you modify your script.

Using Ruby as a PHP extension has the following benefits:

-- good startup speed (no fork())
-- works with a couple of webservers, see dir sapi/ of PHP src
-- PHP has a lot of functions to handle HTTP and HTML (of course, there is
   cgi.rb, but -- in my opinion -- PHP is more consistent, more standard,
   more documented, has more functionality; it is used all over the world,
   so the functions are guaranteed to be the same in new versions)
-- PHP has tons of extensions, like interfaces to databases (MySQL,
   PostgreSQL etc.) and image creators (gd, ming, pdflib etc.), see dir
   ext/ of PHP src
-- PHP is classical. It is well-known, well-documented (only the functions
   available from PHP), widely available, widely used and commerically
   supported.

Why not PHP alone?
""""""""""""""""""
The programming language of PHP is not powerful enough. I call a language
powerful if (quoting Larry Wall) easy things are easy to implement and
complicated things are possible; also complicated things must not be
overcomplicated or unreadable. For scripting languages, I have the following
order of powerfulness:

	sed < Visual Basic (VBScript, ASP) < TCL < sh < bash < AWK <
	JavaScript (LiveWire) < PHP3 < PHP4 < Perl < Pike < Ruby.

My order of documentedness (not the C API!):

	Pike < Ruby < JavaScript < TCL < PHP3 < PHP4 < Perl.

My order of backwards-compatibility and ,,standardizedness'':

	Visual Basic < sed < Pike < AWK < JavaScript < TCL < PHP < Perl.
	(Ruby is somewhere between AWK and Perl.)

PHP is too slow, even PHP4 is slow, even with the ZendOptimizer, even with
pre-compilers. (Actually, Ruby is also quite slow, compared to Pike or Java,
but that is tolerable, and faster than PHP.)

Why Ruby?
"""""""""
-- Ruby is powerful
-- Ruby is a scripting language
-- Ruby is easy to embed (the C API is easy and straightforward)
-- Ruby code is reusable
-- I like Ruby syntax
-- the speed of Ruby is tolerable
-- Ruby is easy to learn
-- high abstraction is possible in Ruby with OOP and block iterators

Benefits and drawbacks
""""""""""""""""""""""
++ (you get the best of both Ruby and PHP worlds)
++ you get Ruby as a powerful scripting language (see `Why Ruby?' earlier)
++ you get PHP with tons of well-documented libraries tuned for dynamic web
   content generation (see `Why PHP?' earlier)
++ you'll get good script startup speed
++ Ruby is faster than PHP
++ Ruby code is automatically pre-compiled, so it does not need
   re-compilation each time the page is downloaded (file modification is
   auto-detected, so you don't have to restart your webserver when you
   modify an .rb script)
-- you need the full PHP source (and experience and luck) to compile pruby
-- you need the Ruby sources to compile pruby
-- somewhat awkward syntax (some Ruby code must be enclosed into single
   quotes, duplicating backslashes etc.)
-- there is probably no precompiled pruby for your favourite Linux
   distribution or UNIX system
-- maybe your ISP will refuse to install pruby (but allow pure PHP)
-- there may be unclarified securty concerns when multiple web developers
   use pruby
-- there may be bugs (especially with memory handling)

Relations
~~~~~~~~~
pRuby is a PHP extension which embeds the Ruby scripting language
interpreter. This means that PHP loads (p)Ruby (and not the other way
round). After (p)Ruby has been loaded, function calls are possible in both
directions (PHP <-> Ruby), so the two languages are almost on the same rank.
The loading hierarchy is the following:

	webserver (e.g Apache)
	  other webserver modules (e.g mod_imap.so, mod_userdir.so)
	  PHP--Zend: libphp4.so
	    other PHP modules (e.g mysql.so, ming.so, ftp.so)
	    other Zend modules (e.g ZendOptimizer.so)
	    pruby.so, a PHP module
	      libruby.so.1.6.2 (or newer)

I don't know whether pRuby works together with mod_ruby. Probably not.
Someone should try and fix it.

Usage tutorial
~~~~~~~~~~~~~~
Basicly, you write PHP files with extension .php (or .php3). This file is
mainly a HTML file, but characters inside `<?php' and `?>' are interpreted
by PHP as a program which is executed when the page is downloaded. See the
PHP Manual (downloadable from www.php.net) about PHP language syntax.
Continue reading after understanding the concept of pure PHP (without
pruby), and having written your *first* PHP script. (If you don't have an
idea then write a script that asks a number in a HTML form, then checks for
bounds (say 0 <= x <= 100), and computes the approximation of its
factorial.)

Now let's talk about pRuby. You should write as few code in PHP as possible.
You should switch to Ruby very soon with

	<?php
	ruby_eval('
	  # ...
	  # your whole Ruby script comes here with all apostrophes and
	  # backslashes properly preceded by a backslash
	  # ...
	');
	?>

An example:

	<?php
	ruby_eval('
	  PHP.print "Hello. Double quote: \\" "
	  PHP.print "Single quote (apostrophe): \\\' "
	  PHP.print "Backslash: \\\\ "
	');
	?>

I know this is ugly, but avoiding the extra backslashes would make things
much less portable, and would create greater confusion. Luckily you can load
.lrb and .erb files in which no extra backslashes are required.

So you'll work with the following file types and extensions:

-- .htm: forget it.

-- .html: pure HTML, with no scripting. The strings `<?' and `<%' are
illegal in HTML, and they may cause various strange effects in browsers. So
don't do scripting in a .html file!

-- .php3: PHP3 script file. It's mainly a HTML, but code between `<?php' and
`?>' is executed by PHP and is replaced by its output. There are also other
delimiters, but they are not portable. Since pRuby does not work with PHP3,
you should avoid this extension.

-- .php: PHP (PHP >=4.0) script file. It's mainly a HTML, but code between
`<?php' and `?>' is executed by PHP and is replaced by its output. There are
also other delimiters, but they are not portable. With pruby, you'll have
the `ruby_eval' function in PHP, from which you can call Ruby code. Note
that this code is re-compiled each time the page is downloaded, so you
should put as small code here as possible.

-- .lrb: Ruby script files containing mostly libraries (e.g class
definitions, but no object creation). I chose the .lrb extension instead of
the standard .rb to show that this file is not for direct exection by Ruby.
The .lrb file is mainly a Ruby file, but everything _must_ be enclosed as

	TopUtil::myself().instance_eval do
	  # all file
	end

Also the `require' instruction must only be used to load .so extensions.
Other .lrb files should be loaded with `load_rb' (explained later). Note
that you cannot get an .lrb file from the web browser directly; .lrb files
can be loaded only from .php files.

-- .erb: similar to eRuby and eRb files. It's mainly a HTML, but code
between `<?ruby' and `?>' is executed by pruby (as Ruby code) and is
replaced by its output. There are also other delimiters. Note that you
cannot get an .erb file from the web browser directly; .erb files can be
loaded only from .php files. As a special case, you can  have a file
with .php extension which contains both Ruby and PHP code:

	<?php pruby_erb_run(); exit; <<<__LINE__
	?>
	Text.
	<?ruby PHP.print "Hello!\n"
	__LINE__
	?>

---

So the main execution flow is (for the Apache webserver):

1. the user requests http://host.ho/dir/file.php
2. the web browser of the user connects to your webserver host.ho (directly
   or via HTTP proxy)
3. your webserver Apache accepts the connection, and consults the httpd.conf
   and .htaccess files about what to do with a file with .php extension. It
   finds in some of them a line:

	AddType application/x-httpd-php .php
	# ^^^ not php3!!
   
   Also *Module entries must be present in httpd.conf:

	LoadModule php4_module libexec/libphp4.so
	AddModule mod_php4.c

   Note that Apache cannot do anything with a file with an .rb extension. So
   don't download your .rb files directly. Write a .php wrapper first!

4. the PHP processor located in libphp4.so is invoked for the file
   dir/file.php. It parses the HTTP request, and begins interpreting the
   file as a PHP script (see `.php' earlier in this document).

5. When the PHP functions `ruby_eval' or `erb_run' or `lrb_load' are called,
   control is given to the Ruby interpreter.

6. The Ruby interpreter reloads the .lrb files _only_ if they were changed
   after the last time they were loaded. Note that only those .lrb files are
   loaded which are _explicitly_ requested with `lrb_load' calls (either in
   PHP or Ruby).

7. The Ruby interpreter uses different namespaces for all files (.php
   ruby_eval(), .lrb, .erb), so scripts won't disturb each other. Please
   don't use global Ruby variables ($...) for persistency between page
   downloads! It usually won't work right. See about persistency later in
   this document.

8. You can call PHP functions from Ruby with `PHP.call', you can read and
   write global PHP variables with `PHP::GLOBALS[...]'. You can print to the
   page with `PHP.print' (which is the same as `PHP.echo').

9. You should free complex data structures (arrays, objects and resources)
   obtained from PHP with `obj.free'. If you don't free them, it may cause a
   long-standing memory leak until `GC.start' is invoked (either explicitly
   or implicitly).

How to exchange data between PHP and Ruby?
""""""""""""""""""""""""""""""""""""""""""
Use the PHP.call to call PHP functions:

	PHP.call "function_name", argument...

Examples:

	PHP.call "phpinfo"
	PHP.call "PHPiNFo" # PHP functions are case insensitive
	p PHP.call("join", " are ", ["Who","you?"])

PHP function `join' gives back bad function name in the backtrace. (Don't
blame me, it's a bug in PHP. The pure PHP code `call_user_func("join", 0,
0);' is also buggy.) If this bothers you, call

	PHP.call "pruby_call_any1", "join", 0, 0
	# ^^^ pruby_call_any1 is slooow!

How to write to the web browser's window
""""""""""""""""""""""""""""""""""""""""
This section deals with the pRuby equivalent of the PHP builtin instuction
`echo'. The `echo' instruction writes the given strings into the web
browser's window just as if the string had appeared outside '<?php'.

The following forms are equivalent and do the same as PHP echo:

	print "foo\n"			# recommended in pure, toplevel code
	puts  "foo"
	PHP.print "foo\n"
	PHP.echo  "foo\n"
	STDOUT.print "foo\n"		# recommended in class definition
	STDOUT.puts  "foo"
	STDOUT <<    "foo\n"
	$stdout.print "foo\n"
	$stdout.puts  "foo"
	$stdout <<    "foo\n"
	$>.print "foo\n"
	$>.puts  "foo"
	$> <<    "foo\n"
	PHP.call "echo", "foo\n"	# deprecated
	PHP::Writer.print "foo\n"
	PHP::Writer.puts  "foo"
	PHP::Writer <<    "foo\n"

In addition, you can also use `p' to print objects in debug notation:

	p PHP::GLOBALS			# will be looong
	PHP.ph PHP::GLOBALS		# like `p', but quotes with PHP.hsc

All these names (STDOUT, $stdout, $>, PHP::Writer) point to the same object.
This objects has the following output methods, similar to IO:

	flush
	self << object
	print arg...
	printf format, arg...
	putc char
	puts obj...
	sync
	sync=
	write string
	syswrite string			# same as write

That object also has the following (fake) input methods, which _always_
behave like if it was EOF: binmode close closed? each each_line each_byte
eof eof? getc gets isatty tty? lineno lineno= pos pos= read readchar
readline readlines rewind sysread tell ungetc.

You can use the `STDOUT.flush' method (and alikes...) to flush output to the
web browser. Note that it has nothing to do with PHP `ob_end_flush()'.

pRuby is fully compatible with PHP's output buffering. You can call the
following functions (with PHP.call) any time:

	ob_implicit_flush(bool)
	ob_start()
	ob_end_clean()
	ob_end_flush()
	ob_get_contents()

How to install the binary
~~~~~~~~~~~~~~~~~~~~~~~~~
You should read compilation instructions even if you install from binary,
because they explain some important inner aspects of Ruby, PHP and pRuby that
is useful to know even for binary installations (and troubleshooting :-(). Now,
I give shortened, mini-explanation about installing from binary.

The binary is `pruby.so'. Installation steps:

1. Obtain the correct binary. (This sounds easy, but it isn't. For PHP
   modules, it is always the best if you re-compile it yourself.) pRuby is
   not distributed in binary form, so you'll have to get it from friends etc.
   If pruby.so is much less than 1Mb, you also have to obtain librubys.so.

2. Copy pruby.so to PHP's extension/* dir (where the other .so files
   reside).

3. Update php.ini (e.g `extension=pruby.so').

4. Restart your webserver.

5. Test the extension with `dl("pruby.so")'.

If you get the error message `Module compile with ..., PHP compiled with...'
when loading pruby.so in PHP, then that binary pruby.so _cannot_ be used
with that version of binary PHP. Either or both of them must be recompiled.

How to compile/install?
~~~~~~~~~~~~~~~~~~~~~~~
Here I'll explain how to build from source. That's not so easy... Actually,
_using_ pRuby is easy, straightforward and comfortable. But unfortunately
installing is quite difficult and may require some human intervention.
(That's it: you have to correct the install scripts if they fail to detect
your configuration correctly.)

Please give me feedback if you had to modify something in the source because
it didn't compile.

Programs you'll need (Dependencies)
"""""""""""""""""""""""""""""""""""
-- UNIX operating system (_might_ work on Windoze, but it's untested,
   undocumented and probably only wizards will be able to make it work)
-- Ruby >=1.6.2 _installed_ (maybe Ruby >=1.6.0 is also OK)
   OR
   the soruce .tar.gz of Ruby >=1.6.2
-- PHP >=4.0.3 installed and running on your webserver, compiled with shared
   library (.so) support
-- the source .tar.gz of your installed PHP (the installed PHP can be
   built from a different source, e.g by your Linux distribution vendor,
   but you need _some_ PHP source .tar.gz for that exact PHP version)
-- GNU bash installed
-- GNU make installed
-- GNU sed (and probably some other trivial console utilities) installed
-- gcc with shared library (.so) support installed

You should know
"""""""""""""""
-- what is the web (www, the World-Wide Web)
-- what is a web browser
-- what is UNIX
-- what is the C language
-- what is gcc (the GNU C compiler)
-- what is a shell (e.g bash)
-- what is a shell script
-- what is a configure script
-- what is GNU Make
-- what is a Makefile
-- what is Ruby (see docs on www.ruby-lang.org)
-- what is PHP (see the PHP Manual on www.php.net)
-- what is a webserver, how PHP relates to a webserver
-- what is Apache
-- what is a CGI script
-- what is dynamic linking
-- what is a shared library (an .so file)
-- (optional) what is Ruby's cgi.rb module
-- (optional) what is Perl's CGI.pm module

Main steps of the installation
""""""""""""""""""""""""""""""
M0.Download and install the required Dependencies.

M1.Install Ruby. `make install' is mandatory, but you can do `configure
   --prefix=/tmp/my-ruby'.

M2.Start reading the PHP manual (not included in the standard PHP source
   distribution; get it from www.php.net). Understand PHP's purpose,
   understand the language syntax, understand php.ini, write and _execute_
   your 1st PHP script. (If you don't have an idea then write a script that
   asks a number in a HTML form, then checks for bounds (say 0 <= x <= 100),
   and computes the approximation of its factorial.) Understand the `dl'
   function.

M3.Create a .php file with contents

	<?php phpinfo() ?>

   Examine this file in your web browser. Save the results into file
   phpinfo.out. See also contrib/phpinfo.php and contrib/_htaccess.

M4.Install and test some other shared library PHP extensions (e.g ftp.so,
   mysql.so, zlib.so). See `extension_dir' and `extension' entries in
   `php.ini'. Test runtime dynamic loading by creating and running
   (downloading) a .php file like:

	<?php dl("zlib.so"); echo "OK."; var_dump(get_loaded_extensions()); ?>

M5.Compile pRuby using the pRuby sources, the PHP sources and eigther Ruby
   sources or the installed version of Ruby. (This will be explained in
   greater detail later.)

M6.Copy pruby.so into your PHP extension/ dir. Consult and update `php.ini' if
   necessary. (Do not write an `extension=pruby.so' line yet!) Restart your
   webserver (maybe not necessary, but it's safe to do it).

M7.Run the test*.php files in the pRuby distrubution.

M8.Decide whether you need a permanent `extension=pruby.so' line in your
   php.ini. Having such a line will speed up script startup dramatically,
   but will need to restart the webserver each time you modify pruby.so.
   If yes, modify it and restart your webserver.

You're done with the installation. (Or at least you're supposed to be.)

Use pRuby. Develop using pRuby. Give (presumably good) feedback to the
author of pRuby. Find and correct bugs in pRuby.

Detailed explanation of the installation
""""""""""""""""""""""""""""""""""""""""
Our primary goal is to create (and debug) the file `pruby.so'. This is a
shared library, which PHP is able to load as an extension (either with the
`dl()' PHP function or due to an `extension=pruby.so' line in php.ini).

This `pruby.so' file must be a shared library. It cannot be linked
statically. (For wizards: it is theoretically possible to link pRuby
statically, but that process is untested and is not covered in this
document.)

The `pruby.so' file embeds the Ruby interpreter, either statically
(libruby.a, total file size of pruby.so will be >1.5Mb) or dynamically
(librubys.so, file size of pruby.so will be <200Kb). The `pruby.so' file has
nothing to do with the Ruby executable binary (e.g /usr/local/bin/ruby), and
does not need it. However, other Ruby-related, installed files (e.g
`complex.rb', `base64.rb', `md5.so', `socket.so') _might_ be needed by the
scripts executed by pRuby (but not by pRuby itself). So, it's essential that
you have Ruby installed, both during compilation and during execution of
pRuby.

pRuby does _not_ require the following Ruby modules:

	cgi.rb
	net/http.rb
	socket.so
	mod_ruby.so
	eruby.so
	eRb

Compiling `pruby.so' is not simple: it's more difficult than compiling a
simple UNIX application program. That's partly because it involves creating
and linking to shared libraries, and partly because compiling a PHP
extension has always been a great mess. (Compiling Ruby extensions is
comparatively easy and straightforward, so we're fighting for PHP most of
the time.)

`pruby.so' is a fully functional and conformant PHP extension, but does not
follow the usual way in which PHP extensions are compiled. That's because
the usual way has tons of drawbacks, for example:

-- it needs the brand newest GNU autoconf and automake to be installed
-- it uses the brain-damaged M4 macro processor
-- it overwrites PHP's main `configure' script (and so on)
-- it is messy to re-compile _only_ one extension and leave the others
   absolutely intact

pRuby's different way offers the following advantages:

-- autoconf and automake is absolutely not required
-- M4 is not required
-- not even a single byte in your PHP source tree is overwritten
-- you have to install only one single file, pruby.so

[...]

Installation steps:

M0. Do it.

M1. Do it.

M2. Do it.

M3. Do it.

    In that rare case you have problems with saving URLs, use one of the
    following methods:

    -- In Netscape, use File/Save as...
    -- lynx -dump http://HOST/PATH/phpinfo.php >phpinfo.out
    -- wget http://HOST/PATH/phpinfo.php -O phpinfo.out
    -- ruby contrib/get.rb http://HOST/PATH/phpinfo.php phpinfo.out

    After doing this step, you're advised to delete phpinfo.php, because it
    can give valuable information for crackers.

M4. Do it.

M5. Details:

M5A.If you'd like to embed Ruby dynamically, you'll need librubys.so
    (intentionally _not_ libruby.so to avoid name conflict with libruby.a).
    If you don't want dynamic embedding, go to step M5B.

    In your Ruby source dir (after ./configure), as root, do...

	make ruby
	make libruby.so.`./ruby -e'print RUBY_VERSION'`
	mv   libruby.so.`./ruby -e'print RUBY_VERSION'` /usr/local/lib/librubys.so

    You can choose a different directory than /usr/local/lib, but it must be
    on your library path (/etc/ld.so.conf, /etc/ld.so.cache, env var
    LD_LIBRARY_PATH, env var LD_RUN_PATH, etc. -- it depends on your os).

M5B.In the pRuby source dir, do

	cp Configuration.in Configuration
	
    Edit Configuration (it's a shell script...). There is no sensible
    default, so you _must_ edit it. See comments there for more info.

M5C.In the pRuby source dir, do

	make conf

    This creates rbwhere.mk, configed.now etc.

M5D.In the pRuby source dir, do

	make

    This creates libruby.so.

M6. Details:

M6A.In the pRuby source dir, as root, do

	make install

    This copies pruby.so to its final location (e.g /usr/local/lib/php/-
    /extensions/no-debug-non-zts-20000809)

M6B.As root, edit your php.ini. (Use `make php_ini_which' to find it.)
    Do not add an `extension=pruby.so' line yet!
    Probably you don't have to change anything right now, but it is always
    a good idea to revise an important configuration file.

M6C.Restart your webserver. If it doesn't come up, see the error log (e.g
    /usr/local/apache/logs/error_log). View static HTML pages on your
    webserver. View PHP files (perhaps the one which created phpinfo.out).

M7. Currently there are no test files :-(.

M8. Decide whether you need a permanent `extension=pruby.so' line in your
    php.ini. Having such a line will speed up script startup dramatically,
    but will need to restart the webserver each time you modify pruby.so.
    If yes, modify it and restart your webserver.

At this point, you've successfully finished the installation.

For testing purposes, you should have a `MaxClients 1' in Apache's
httpd.conf. (Don't use the Apache of your main, _real_ website for
testing!! `MaxClients 1' would make that site unusable.)

ervi.rb
~~~~~~~
# This will be similar to eRuby and eRb, but not the same. There will be
# compatibility isses.
#
# Now we define a filter which converts a text (or HTML...) file into a
# Ruby program. Most of the text file will be converted to a `print'
# instruction, i.e the generated Ruby program will simply print the contents
# of the original file (of course, not by opening the original file, but
# getting the data from the .rb file itself). It is possible to put Ruby
# code into the text file, which won't be printed verbatim, but executed each
# time the generated .rb file is run.
#
# Syntax:
#
# <? ... ?>
# <%php ... %>
# <?php ... ?>
#   completely ignored, inserted as a comment into the .rb file. This is for
#   skipping PHP code.
#
# <?ruby# ?>
# <%ruby# ... %>
# <%# ... %>
#   completely ignored, inserted as a comment into the .rb file. The `<%' form
#   is compatible with eRuby.
#
# <?ruby ... ?>
# <%ruby ... %>
# <% ... %>
#   will be evaluated as Ruby code. The code should use the `print' function
#   to append text to the output (in place of itself). The `<%' form
#   is compatible with eRuby.
#
# <?ruby= ... ?>
# <%ruby= ... %>
# <%= ... %>
#   will be evaluated as a Ruby code block. Will be replaced with the value
#   of (the last instruction) of the block. The `<%' form
#   is compatible with eRuby. 
#
# All Ruby code segments share the same local variables, instance variables,
# constants (and global variables, of course). Methods defined a code segment
# will be available in later code segments, but won't be available in the
# `main' program. Methods defined in the main program will be available in
# the code segments.
#
# Incompatibility with eRuby: lines starting with `%' won't be evaluated. (Of
# course there are more incompatilities not listed here.)
#
# The filter inserts `#line LINENUMBER' comments into the generated code so
# line numbers will appear correctly in exception backtraces (etc.). You may
# have to patch parse.y in the Ruby sources to make it work. (If you don't
# patch it, the only drawback is that line numbers may appear incorrectly.)

Error and exception handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Errors happening in pure PHP are handled by PHP's standard error mechanism
(see php.ini entries: error_reporting, display_errors, log_errors). The
default behaviour is: the error message is printed to the page and --
depending on the severity of the error -- execution is either continued or
aborted.

Unrescued Ruby exceptions are propagated to PHP's standard error mechanism
with severity E_ERROR and message `Ruby exception of type...'. The error is
dumped with a full backtrace.

Errors happening in PHP code which was called from Ruby raise a
PHP::PHPFatalError or PHP::PHPNormalError exception in Ruby (these
exceptions are subclasses of PHP::PHPError). These exceptions are unrescued
by default, so they are propagated to PHP's standard error mechanish with
their original severity (E_ERROR, E_WARNING etc.) and message `calling PHP
from Ruby, exception of type PHP::PHP...'. Again, you get a full backtrace
including the line numbers of your PHP and Ruby code.

You can rescue PHP::PHPFatalError yourself. Nothing is printed or logged
automatically if
you rescue the error. Note that these errors (E_ERROR,
E_CORE_ERROR etc.) are considered `severe' and would cause a PHP script to
abort (exit, bail out, `zend_bailout()'). So you should do the same: exit
from Ruby as soon as possible. You should _not_ call any PHP function after
the error happend (if you call one, it may cause a segfault).

You can rescue PHP::PHPNormalError yourself. Nothing is printed or logged
autmatically if you rescue the error. You are free to do anything, including
calling PHP after rescuing the error.

PHP::PHPError classes have the following extra methods:

	phperr_fix()		# include the PHP line in the backtrace
	phperr_file()		# get the filename where the error happened
	phperr_line()		# get the line number where the error happened
	phperr_type()		# get the numeric error_type (E_...)
	phperr_val()		# get the value returned from the function
				# that caused the error (usually nil, false
				# or the empty string)

module PHP
~~~~~~~~~~
str2=PHP.hsc(str)
  quotes like PHP function HTMLspecialchars, but not exactly the same.

PHP.ph(*objs)
  same as `p PHP.hsc(*objs)'

FAQ
~~~
Will pRuby work with the CGI (SAPI) version of PHP?
"""""""""""""""""""""""""""""""""""""""""""""""""""
Although untested, very probably yes.

Will pRuby work with the Apache (SAPI) version of PHP?
""""""""""""""""""""""""""""""""""""""""""""""""""""""
Yes, certainly. It's the main testing platform of pRuby.

Will there be multithreading support in pRuby?
""""""""""""""""""""""""""""""""""""""""""""""
No. Maybe never. pRuby will never work correctly in a multithreaded
webserver, partly because Ruby itself is not designed to be multithreaded.

Is PHP::GLOBALS always defined?
"""""""""""""""""""""""""""""""
Yes. Even if you don't use global variables in PHP.

Is PHP::GLOBALS["GLOBALS"] always defined?
""""""""""""""""""""""""""""""""""""""""""
No, only if you use `$GLOBALS[...]' in the PHP main code.

Misfeatures
~~~~~~~~~~~
-- no syntax highlighting for Ruby code :-(

Some docs for writing PHP extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PHP and Ruby follow a different memory (de-)allocation model. In PHP, data is
always allocated by the caller. In PHP, there is reference counting. In
Ruby, there isn't.

Bad:	zval *function();
Good:	void function(zval **return);
 return_value=data_rb2php(ret); # <<< this is illegal

---

# Numbers are: number of occurences in PHP 4.0.3's ext/ ** / *.c

zval *zu; # uninitialized pointer
zval *zg; # initialized pointer, but points to garbage
zval *zn; # initialized pointer, may point to zval with garbage type or
          # destructed zval
zval *zv; # initialized pointer, points to working zval

ALLOC_ZVAL(zu)		zu=malloc(sizeof(zval))
FREE_ZVAL(zn)		free(zn)
ALLOC_ZVAL_REL(zu)	# used for debugging??
FREE_ZVAL_REL(zn)	# used for debugging??

INIT_PZVAL(zg)		zp->refcount=1, zp->is_ref=0			 34
INIT_ZVAL(*zg)		*zp=zval_used_for_init # initilized NULL value	  0
ALLOC_INIT_ZVAL(zu)	ALLOC_ZVAL(zp), INIT_ZVAL(*zp)			  4
MAKE_STD_ZVAL(zu)	ALLOC_ZVAL(zp), INIT_PZVAL(zp)			108

ZVAL_NULL(zn)
ZVAL_RESOURCE(zn,l)
ZVAL_BOOL(zn,b)
ZVAL_LONG(zn,l)
ZVAL_DOUBLE(zn,d)
ZVAL_STRING(zn,s,du)
ZVAL_STRINGL(zn,s,l,du)
ZVAL_EMPTY_STRING(zn)
Imp: array...
Imp: object...

SEPARATE_ZVAL(&zv)	if (is_ref) ...
convert_to_string(zv)
convert_to_string_ex(&zv)

ZVAL_ADDREF(zn)		++(zn)->refcount				  3
zval_add_ref(&zn)	++(zn)->refcount				 11
ZVAL_DELREF(zn)		--(zn)->refcount # no free if ==0!!		  0
zval_del_ref(&zn)	--(zn)->refcount, FREE_ZVAL if ==0		 20
zval_dtor(zv)		destructor; free() all _inside_ zp, but not zp	 68
zval_copy_ctor(zv)	copy constructor; use zval_copy_ctor(znew=zold)	 42

Typical life cycle 1:

	zval name_zp;
	char *name_zp_s[]="a_function_name";
	# ^^^ we need this extra var, because call_user_function_ex()
	#     calls zend_str_tolower(), which writes into this string. Simple
	#     string constants are unchangable by default (for GCC).
	zval *zp;
	INIT_PZVAL(&name_zp); ZVAL_STRING(&name_zp, name_zp_s, 0);
	MAKE_STD_ZVAL(zp);
	if (..) ZVAL_STRING(zp,"test",1); # copy with strdup()
	   else call_user_function(CG(function_table), NULL, name_zp, zp, argc, ...);
	# process it
	# zval_del_ref includes: refcount--, zval_dtor, FREE_ZVAL
	#if 0
	  # bad practice: ignores existing refs (refcount>=2)
	  zval_dtor(zp);
	  FREE_ZVAL(zp);
	#else
	  # good practice
	  zval_del_ref(&zp);
	#endif

Typical life cycle 2:

	zval zz;
	INIT_PZVAL(&zz);
	ZVAL_STRING(&zz,"getcwd",1); # do copy!!
	# process it
	zval_dtor(&zz);
	# no FREE_ZVAL, we don't want to free &zz!

`zval', `zval*' or `zval**'?
""""""""""""""""""""""""""""
Storing the return value from a function, the programmer has two choices:
	
	zval retval;
	INIT_PZVAL(&retval);
	call_user_function(CG(function_table), ?obj?, ?name?, &retval, argc, ...);
	# do something with retval
	if (retval.refcount!=1) abort();
	# ^^^ if this happens, we're lost. We cannot help about it.
	zval_dtor(&retval);

Or, using pointers, never needing to abort:

	zval retvalp;
	MAKE_STD_ZVAL(retvalp);
	call_user_function(CG(function_table), ?obj?, ?name?, &retvalp, argc, ...);
	# do something with retvalp
	#if 0
	  # vvv would fail if retvalp->refcount!=1
	  zval_dtor(retvalp);
	  FREE_ZVAL(retvalp);
	#else
	  # vvv always OK
	  zval_del_ref(&retvalp);
	#endif

See the COPY_PZVAL_TO_ZVAL(zv, pzv) macro in zend.h...

---

This is the end of README. Should it be longer??
