dmitry          Thu Jul 17 09:53:42 2008 UTC

  Added files:                 (Branch: PHP_5_3)
    /php-src/ext/curl/tests     curl_006.phpt 
    /php-src/ext/filter/tests   callback_closure.phpt 
    /php-src/ext/mysqli/tests   
                                mysqli_set_local_infile_handler_closures.phpt 
    /php-src/ext/pcntl/tests    signal_closure_handler.phpt 
    /php-src/ext/session/tests  save_handler_closures.inc 
                                session_set_save_handler_closures.phpt 
    /php-src/ext/sqlite/tests   sqlite_closures_001.phpt 
                                sqlite_closures_002.phpt 
    /php-src/ext/standard/tests/assert  assert_closures.phpt 
    /php-src/ext/standard/tests/general_functions       closures_001.phpt 
                                                        closures_002.phpt 
                                                        ob_start_closures.phpt 
    /php-src/ext/xml/tests      xml_closures_001.phpt 

  Modified files:              
    /php-src/ext/mysqli mysqli_api.c 
    /php-src/ext/standard       basic_functions.c 
    /php-src/ext/xml    xml.c 
    /php-src/main       output.c 
  Log:
  Support for closures
  
  
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqli/mysqli_api.c?r1=1.118.2.22.2.16.2.17&r2=1.118.2.22.2.16.2.18&diff_format=u
Index: php-src/ext/mysqli/mysqli_api.c
diff -u php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.17 
php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.18
--- php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.17        Thu Apr 24 
14:22:19 2008
+++ php-src/ext/mysqli/mysqli_api.c     Thu Jul 17 09:53:41 2008
@@ -17,7 +17,7 @@
   |          Ulf Wendel <[EMAIL PROTECTED]>                                    
 |
   +----------------------------------------------------------------------+
 
-  $Id: mysqli_api.c,v 1.118.2.22.2.16.2.17 2008/04/24 14:22:19 andrey Exp $ 
+  $Id: mysqli_api.c,v 1.118.2.22.2.16.2.18 2008/07/17 09:53:41 dmitry Exp $ 
 */
 
 #ifdef HAVE_CONFIG_H
@@ -1420,6 +1420,7 @@
                efree(callback_name);
                RETURN_FALSE;
        }
+       efree(callback_name);
 
        /* save callback function */
        if (!mysql->li_read) {
@@ -1427,7 +1428,7 @@
        } else {
                zval_dtor(mysql->li_read);
        }
-       ZVAL_STRING(mysql->li_read, callback_name, 0);
+       ZVAL_ZVAL(mysql->li_read, callback_func, 1, 0);
 
        RETURN_TRUE;
 }
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/basic_functions.c?r1=1.725.2.31.2.64.2.35&r2=1.725.2.31.2.64.2.36&diff_format=u
Index: php-src/ext/standard/basic_functions.c
diff -u php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.35 
php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.36
--- php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.35 Sun May 25 
14:06:13 2008
+++ php-src/ext/standard/basic_functions.c      Thu Jul 17 09:53:42 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: basic_functions.c,v 1.725.2.31.2.64.2.35 2008/05/25 14:06:13 bjori Exp 
$ */
+/* $Id: basic_functions.c,v 1.725.2.31.2.64.2.36 2008/07/17 09:53:42 dmitry 
Exp $ */
 
 #include "php.h"
 #include "php_streams.h"
@@ -5392,6 +5392,10 @@
                zval result;
                zend_compare_arrays(&result, func1, func2 TSRMLS_CC);
                ret = (Z_LVAL(result) == 0);
+       } else if (Z_TYPE_P(func1) == IS_OBJECT && Z_TYPE_P(func2) == 
IS_OBJECT) {
+               zval result;
+               zend_compare_objects(&result, func1, func2 TSRMLS_CC);
+               ret = (Z_LVAL(result) == 0);
        } else {
                ret = 0;
        }
@@ -6044,7 +6048,7 @@
                efree(function_name);
        }
 
-       if (Z_TYPE_P(tick_fe.arguments[0]) != IS_ARRAY) {
+       if (Z_TYPE_P(tick_fe.arguments[0]) != IS_ARRAY && 
Z_TYPE_P(tick_fe.arguments[0]) != IS_OBJECT) {
                convert_to_string_ex(&tick_fe.arguments[0]);
        }
 
http://cvs.php.net/viewvc.cgi/php-src/ext/xml/xml.c?r1=1.157.2.4.2.5.2.8&r2=1.157.2.4.2.5.2.9&diff_format=u
Index: php-src/ext/xml/xml.c
diff -u php-src/ext/xml/xml.c:1.157.2.4.2.5.2.8 
php-src/ext/xml/xml.c:1.157.2.4.2.5.2.9
--- php-src/ext/xml/xml.c:1.157.2.4.2.5.2.8     Sat Jul  5 20:17:58 2008
+++ php-src/ext/xml/xml.c       Thu Jul 17 09:53:42 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: xml.c,v 1.157.2.4.2.5.2.8 2008/07/05 20:17:58 felipe Exp $ */
+/* $Id: xml.c,v 1.157.2.4.2.5.2.9 2008/07/17 09:53:42 dmitry Exp $ */
 
 #define IS_EXT_MODULE
 
@@ -508,7 +508,7 @@
        }
 
        /* IS_ARRAY might indicate that we're using array($obj, 'method') 
syntax */
-       if (Z_TYPE_PP(data) != IS_ARRAY) {
+       if (Z_TYPE_PP(data) != IS_ARRAY && Z_TYPE_PP(data) != IS_OBJECT) {
 
                convert_to_string_ex(data);
                if (Z_STRLEN_PP(data) == 0) {
http://cvs.php.net/viewvc.cgi/php-src/main/output.c?r1=1.167.2.3.2.4.2.5&r2=1.167.2.3.2.4.2.6&diff_format=u
Index: php-src/main/output.c
diff -u php-src/main/output.c:1.167.2.3.2.4.2.5 
php-src/main/output.c:1.167.2.3.2.4.2.6
--- php-src/main/output.c:1.167.2.3.2.4.2.5     Tue Jul 15 09:09:09 2008
+++ php-src/main/output.c       Thu Jul 17 09:53:42 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: output.c,v 1.167.2.3.2.4.2.5 2008/07/15 09:09:09 lstrojny Exp $ */
+/* $Id: output.c,v 1.167.2.3.2.4.2.6 2008/07/17 09:53:42 dmitry Exp $ */
 
 #include "php.h"
 #include "ext/standard/head.h"
@@ -526,8 +526,17 @@
                        }
                }
        } else if (output_handler && output_handler->type == IS_OBJECT) {
-               php_error_docref(NULL TSRMLS_CC, E_ERROR, "No method name 
given: use ob_start(array($object,'method')) to specify instance $object and 
the name of a method of class %s to use as output handler", 
Z_OBJCE_P(output_handler)->name);
-               result = FAILURE;
+               /* do we have callable object */
+               if (zend_is_callable(output_handler, 0, &handler_name)) {
+                       SEPARATE_ZVAL(&output_handler);
+                       Z_ADDREF_P(output_handler);
+                       result = php_ob_init_named(initial_size, block_size, 
handler_name, output_handler, chunk_size, erase TSRMLS_CC);
+                       efree(handler_name);
+               } else {
+                       efree(handler_name);
+                       php_error_docref(NULL TSRMLS_CC, E_ERROR, "No method 
name given: use ob_start(array($object,'method')) to specify instance $object 
and the name of a method of class %s to use as output handler", 
Z_OBJCE_P(output_handler)->name);
+                       result = FAILURE;
+               }
        } else {
                result = php_ob_init_named(initial_size, block_size, 
OB_DEFAULT_HANDLER_NAME, NULL, chunk_size, erase TSRMLS_CC);
        }

http://cvs.php.net/viewvc.cgi/php-src/ext/curl/tests/curl_006.phpt?view=markup&rev=1.1
Index: php-src/ext/curl/tests/curl_006.phpt
+++ php-src/ext/curl/tests/curl_006.phpt
--TEST--
Test curl_opt() function with CURLOPT_WRITEFUNCTION paremter set to a closure
--SKIPIF--
<?php if (!extension_loaded("curl") || false === 
getenv(b'PHP_CURL_HTTP_REMOTE_SERVER')) print "skip"; ?>
--FILE--
<?php
/* Prototype  : bool curl_setopt(resource ch, int option, mixed value)
 * Description: Set an option for a cURL transfer
 * Source code: ext/curl/interface.c
 * Alias to functions:
 */

  $host = getenv('PHP_CURL_HTTP_REMOTE_SERVER');

  // start testing
  echo '*** Testing curl_setopt($ch, CURLOPT_WRITEFUNCTION, <closure>); ***' . 
"\n";

  $url = "{$host}/get.php?test=get";
  $ch = curl_init();

  ob_start(); // start output buffering
  curl_setopt($ch, CURLOPT_URL, $url); //set the url we want to use
  curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) {
    echo 'Data: '.$data;
    return strlen ($data);
  });
  
  curl_exec($ch);
  curl_close($ch);
?>
===DONE===
--EXPECTF--
*** Testing curl_setopt($ch, CURLOPT_WRITEFUNCTION, <closure>); ***
Data: Hello World!
Hello World!===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/filter/tests/callback_closure.phpt?view=markup&rev=1.1
Index: php-src/ext/filter/tests/callback_closure.phpt
+++ php-src/ext/filter/tests/callback_closure.phpt
--TEST--
callback function is a closure
--SKIPIF--
<?php if (!extension_loaded("filter")) die("skip"); ?>
--FILE--
<?php
$callback = function ($var) {
        return $var;
};
$var = "test";
var_dump(filter_var($var, FILTER_CALLBACK, array('options'=> $callback)));
?>
--EXPECT--      
string(4) "test"

http://cvs.php.net/viewvc.cgi/php-src/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt?view=markup&rev=1.1
Index: php-src/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt
+++ php-src/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt
--TEST--
mysqli_set_local_infile_handler() - use closures as handler
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifemb.inc');
require_once('skipifconnectfailure.inc');

if (!function_exists('mysqli_set_local_infile_handler'))
        die("skip - function not available.");

require_once('connect.inc');
if (!$TEST_EXPERIMENTAL)
        die("skip - experimental (= unsupported) feature");

if (!$link = mysqli_connect($host, $user, $passwb, $db, $port, $socket))
        die("skip Cannot connect to MySQL");

if (!$res = mysqli_query($link, 'SHOW VARIABLES LIKE "local_infile"')) {
        mysqli_close($link);
        die("skip Cannot check if Server variable 'local_infile' is set to 
'ON'");
}

$row = mysqli_fetch_assoc($res);
mysqli_free_result($res);
mysqli_close($link);

if ('ON' != $row['Value'])
        die(sprintf("skip Server variable 'local_infile' seems not set to 'ON', 
found '%s'",
                $row['Value']));
?>
--INI--
mysqli.allow_local_infile=1
--FILE--
<?php
        require_once('connect.inc');
        require_once('local_infile_tools.inc');
        require_once('table.inc');

        $callback_replace_buffer = function ($fp, &$buffer, $buflen, &$error) {
                static $invocation = 0;

                printf("Callback: %d\n", $invocation++);
                flush();

                $buffer = fread($fp, $buflen);

                if ($invocation > 10)
                        return 0;

                return strlen($buffer);
        };

        $file = create_standard_csv(1);
        if (!try_handler(20, $link, $file, $callback_replace_buffer, null))
                printf("[008] Failure\n");

        mysqli_close($link);
        print "done!";
?>
--EXPECTF--
Callback set to 'Closure object'
Callback: 0
Callback: 1
done!
http://cvs.php.net/viewvc.cgi/php-src/ext/pcntl/tests/signal_closure_handler.phpt?view=markup&rev=1.1
Index: php-src/ext/pcntl/tests/signal_closure_handler.phpt
+++ php-src/ext/pcntl/tests/signal_closure_handler.phpt
--TEST--
Closures as a signal handler
--SKIPIF--
<?php
        if (!extension_loaded("pcntl")) print "skip"; 
        if (!function_exists("pcntl_signal")) print "skip pcntl_signal() not 
available";
        if (!function_exists("posix_kill")) print "skip posix_kill() not 
available";
        if (!function_exists("posix_getpid")) print "skip posix_getpid() not 
available";
?>
--FILE--
<?php
declare (ticks = 1);

pcntl_signal(SIGTERM, function ($signo) { echo "Signal handler called!\n"; });

echo "Start!\n";
posix_kill(posix_getpid(), SIGTERM);
$i = 0; // dummy
echo "Done!\n";

?>
--EXPECT--
Start!
Signal handler called!
Done!

http://cvs.php.net/viewvc.cgi/php-src/ext/session/tests/save_handler_closures.inc?view=markup&rev=1.1
Index: php-src/ext/session/tests/save_handler_closures.inc
+++ php-src/ext/session/tests/save_handler_closures.inc
<?php

require_once 'save_handler.inc';

foreach (array ('open', 'close', 'read', 'write', 'destroy', 'gc') as $fn) {
        ${$fn.'_closure'} = function () use ($fn) { return call_user_func_array 
($fn, func_get_args ()); };
}

?>

http://cvs.php.net/viewvc.cgi/php-src/ext/session/tests/session_set_save_handler_closures.phpt?view=markup&rev=1.1
Index: php-src/ext/session/tests/session_set_save_handler_closures.phpt
+++ php-src/ext/session/tests/session_set_save_handler_closures.phpt
--TEST--
Test session_set_save_handler() function : using closures as callbacks
--INI--
session.save_path=
session.name=PHPSESSID
--SKIPIF--
<?php include('skipif.inc'); ?>
--FILE--
<?php

ob_start();

/* 
 * Prototype : bool session_set_save_handler(callback $open, callback $close, 
callback $read, callback $write, callback $destroy, callback $gc)
 * Description : Sets user-level session storage functions
 * Source code : ext/session/session.c 
 */

echo "*** Testing session_set_save_handler() : using closures as callbacks 
***\n";

require_once "save_handler_closures.inc";
var_dump(session_module_name());
var_dump(session_module_name(FALSE));
var_dump(session_module_name("blah"));
var_dump(session_module_name("foo"));

$path = dirname(__FILE__);
session_save_path($path);
session_set_save_handler($open_closure, $close_closure, $read_closure, 
$write_closure, $destroy_closure, $gc_closure);

session_start();
$_SESSION["Blah"] = "Hello World!";
$_SESSION["Foo"] = FALSE;
$_SESSION["Guff"] = 1234567890;
var_dump($_SESSION);

session_write_close();
session_unset();
var_dump($_SESSION);

echo "Starting session again..!\n";
session_id($session_id);
session_set_save_handler($open_closure, $close_closure, $read_closure, 
$write_closure, $destroy_closure, $gc_closure);
session_start();
var_dump($_SESSION);
session_write_close();

ob_end_flush();
?>
--EXPECTF--
*** Testing session_set_save_handler() : using closures as callbacks ***

unicode(%d) "%s"

Warning: session_module_name(): Cannot find named PHP session module () in %s 
on line %d
bool(false)

Warning: session_module_name(): Cannot find named PHP session module (blah) in 
%s on line %d
bool(false)

Warning: session_module_name(): Cannot find named PHP session module (foo) in 
%s on line %d
bool(false)
Open [%s,PHPSESSID]
Read [%s,%s]
array(3) {
  [u"Blah"]=>
  unicode(12) "Hello World!"
  [u"Foo"]=>
  bool(false)
  [u"Guff"]=>
  int(1234567890)
}
Write [%s,%s,Blah|U:12:"Hello World!";Foo|b:0;Guff|i:1234567890;]

Notice: fwrite(): %d character unicode buffer downcoded for binary stream 
runtime_encoding in %s on line %d
Close [%s,PHPSESSID]
array(3) {
  [u"Blah"]=>
  unicode(12) "Hello World!"
  [u"Foo"]=>
  bool(false)
  [u"Guff"]=>
  int(1234567890)
}
Starting session again..!
Open [%s,PHPSESSID]
Read [%s,%s]
array(3) {
  [u"Blah"]=>
  unicode(12) "Hello World!"
  [u"Foo"]=>
  bool(false)
  [u"Guff"]=>
  int(1234567890)
}
Write [%s,%s,Blah|U:12:"Hello World!";Foo|b:0;Guff|i:1234567890;]

Notice: fwrite(): %d character unicode buffer downcoded for binary stream 
runtime_encoding in %s on line %d
Close [%s,PHPSESSID]

http://cvs.php.net/viewvc.cgi/php-src/ext/sqlite/tests/sqlite_closures_001.phpt?view=markup&rev=1.1
Index: php-src/ext/sqlite/tests/sqlite_closures_001.phpt
+++ php-src/ext/sqlite/tests/sqlite_closures_001.phpt
--TEST--
sqlite: aggregate functions with closures
--INI--
sqlite.assoc_case=0
--SKIPIF--
<?php # vim:ft=php
if (!extension_loaded("sqlite")) print "skip"; ?>
--FILE--
<?php 
include "blankdb.inc";

$data = array(
        "one",
        "two",
        "three"
        );

sqlite_query("CREATE TABLE strings(a)", $db);

foreach ($data as $str) {
        sqlite_query("INSERT INTO strings VALUES('" . 
sqlite_escape_string($str) . "')", $db);
}

function cat_step(&$context, $string)
{
        $context .= $string;
}

function cat_fin(&$context)
{
        return $context;
}

sqlite_create_aggregate($db, "cat", function (&$context, $string) {
        $context .= $string;
}, function (&$context) {
        return $context;
});

$r = sqlite_query("SELECT cat(a) from strings", $db);
while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
        var_dump($row);
}

sqlite_close($db);

echo "DONE!\n";
?>
--EXPECT--
array(1) {
  [0]=>
  unicode(11) "onetwothree"
}
DONE!

http://cvs.php.net/viewvc.cgi/php-src/ext/sqlite/tests/sqlite_closures_002.phpt?view=markup&rev=1.1
Index: php-src/ext/sqlite/tests/sqlite_closures_002.phpt
+++ php-src/ext/sqlite/tests/sqlite_closures_002.phpt
--TEST--
sqlite: regular functions with closures
--INI--
sqlite.assoc_case=0
--SKIPIF--
<?php # vim:ft=php
if (!extension_loaded("sqlite")) print "skip"; ?>
--FILE--
<?php 
include "blankdb.inc";

$data = array(
        array("one", "uno"),
        array("two", "dos"),
        array("three", "tres"),
        );

sqlite_query("CREATE TABLE strings(a,b)", $db);

foreach ($data as $row) {
        sqlite_query("INSERT INTO strings VALUES('" . 
sqlite_escape_string($row[0]) . "','" . sqlite_escape_string($row[1]) . "')", 
$db);
}

sqlite_create_function($db, "implode", function () {
        $args = func_get_args();
        $sep = array_shift($args);
        return implode($sep, $args);
});

$r = sqlite_query("SELECT implode('-', a, b) from strings", $db);
while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
        var_dump($row);
}

sqlite_close($db);

echo "DONE!\n";
?>
--EXPECT--
array(1) {
  [0]=>
  unicode(7) "one-uno"
}
array(1) {
  [0]=>
  unicode(7) "two-dos"
}
array(1) {
  [0]=>
  unicode(10) "three-tres"
}
DONE!

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/assert/assert_closures.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/assert/assert_closures.phpt
+++ php-src/ext/standard/tests/assert/assert_closures.phpt
--TEST--
assert() - basic - accept closures as callback.
--INI--
assert.active = 1
assert.warning = 1
assert.bail = 0
assert.quiet_eval = 0
--FILE--
<?php
assert_options(ASSERT_CALLBACK, function () { echo "Hello World!\n"; });
assert(0);
?>
--EXPECTF--
Hello World!

Warning: assert(): Assertion failed in %s on line %d

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/general_functions/closures_001.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/general_functions/closures_001.phpt
+++ php-src/ext/standard/tests/general_functions/closures_001.phpt
--TEST--
register_shutdown_function() & closure
--FILE--
<?php
register_shutdown_function(function () { echo "Hello World!\n"; });

echo "Done\n";
?>
--EXPECTF--     
Done
Hello World!

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/general_functions/closures_002.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/general_functions/closures_002.phpt
+++ php-src/ext/standard/tests/general_functions/closures_002.phpt
--TEST--
register_tick_function() & closure
--FILE--
<?php

declare (ticks = 1);

$i = 0;
register_tick_function(function () use (&$i) { $i++; });

echo "Test\n";
echo "$i\n";
echo "$i\n";
var_dump ($i != 0);
echo "$i\n";
echo "Done\n";

?>
--EXPECTF--     
Test
%d
%d
bool(true)
%d
Done

http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/general_functions/ob_start_closures.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/general_functions/ob_start_closures.phpt
+++ php-src/ext/standard/tests/general_functions/ob_start_closures.phpt
--TEST--
Test ob_start() function : closures as output handlers
--INI--
output_buffering=0
--FILE--
<?php
echo "*** Testing ob_start() : closures as output handlers ***\n";

ob_start(function ($output) {
  return 'Output (1): ' . $output;
});

ob_start(function ($output) {
  return 'Output (2): ' . $output;
});

echo "Test\nWith newlines\n";

$str1 = ob_get_contents ();

ob_end_flush();

$str2 = ob_get_contents ();

ob_end_flush();

echo $str1, $str2;

?>
===DONE===
--EXPECT--
*** Testing ob_start() : closures as output handlers ***
Output (1): Output (2): Test
With newlines
Test
With newlines
Output (2): Test
With newlines
===DONE===

http://cvs.php.net/viewvc.cgi/php-src/ext/xml/tests/xml_closures_001.phpt?view=markup&rev=1.1
Index: php-src/ext/xml/tests/xml_closures_001.phpt
+++ php-src/ext/xml/tests/xml_closures_001.phpt
--TEST--
XML parser test using closures as callbacks
--SKIPIF--
<?php include("skipif.inc"); ?>
--INI--
magic_quotes_runtime=0
--FILE--
<?php
chdir(dirname(__FILE__));

$start_element = function ($xp, $elem, $attribs)
{
        print "<$elem";
        if (sizeof($attribs)) {
                while (list($k, $v) = each($attribs)) {
                        print " $k=\"$v\"";
                }
        }
        print ">\n";
};

$end_element = function ($xp, $elem)
{
        print "</$elem>\n";
};

$xp = xml_parser_create();
xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
xml_set_element_handler($xp, $start_element, $end_element);
$fp = fopen("xmltest.xml", "r");
while ($data = fread($fp, 4096)) {
        xml_parse($xp, $data, feof($fp));
}
xml_parser_free($xp);

?>
--EXPECT--
<root id="elem1">
<elem1>
<elem2>
<elem3>
<elem4>
</elem4>
</elem3>
</elem2>
</elem1>
</root>

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to