diff options
author | SVN Migration <svn@php.net> | 2006-04-26 11:08:11 +0000 |
---|---|---|
committer | SVN Migration <svn@php.net> | 2006-04-26 11:08:11 +0000 |
commit | 79f14997b447f5917f16138d00d9877f1eeabae0 (patch) | |
tree | aac481f9ab3d2192e236780a3c2b5b7fe18e3144 | |
parent | ad1bbaca04a802350884c07e2899a240d1a04e28 (diff) | |
download | php-git-79f14997b447f5917f16138d00d9877f1eeabae0.tar.gz |
This commit was manufactured by cvs2svn to create tag 'php_5_1_2'.php-5.1.2
98 files changed, 6181 insertions, 0 deletions
diff --git a/Zend/tests/bug36006.phpt b/Zend/tests/bug36006.phpt new file mode 100755 index 0000000000..79f9897d13 --- /dev/null +++ b/Zend/tests/bug36006.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #36006 (Problem with $this in __destruct()) +--FILE-- +<?php + +class Person { + public $dad; + public function __destruct() { + $this->dad = null; /* no segfault if this is commented out */ + } +} + +class Dad extends Person { + public $son; + public function __construct() { + $this->son = new Person; + $this->son->dad = $this; /* no segfault if this is commented out */ + } + public function __destruct() { + $this->son = null; + parent::__destruct(); /* segfault here */ + } +} + +$o = new Dad; +unset($o); +echo "ok\n"; +?> +--EXPECT-- +ok diff --git a/Zend/tests/bug36037.phpt b/Zend/tests/bug36037.phpt new file mode 100755 index 0000000000..3ccebf652d --- /dev/null +++ b/Zend/tests/bug36037.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #36037 (heredoc adds extra line number) +--FILE-- +<?php +echo __LINE__, "\n"; +$x=<<<XXX +123 +YYY; +XXX; +echo __LINE__, "\n"; +?> +--EXPECT-- +2 +7 diff --git a/Zend/tests/bug36071.phpt b/Zend/tests/bug36071.phpt new file mode 100755 index 0000000000..3b8e05dfab --- /dev/null +++ b/Zend/tests/bug36071.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #36071 (Engine Crash related with 'clone') +--INI-- +error_reporting=4095 +--FILE-- +<?php +$a = clone 0; +$a[0]->b = 0; +echo "ok\n"; +?> +--EXPECTF-- +Warning: __clone method called on non-object in %sbug36071.php on line 2 +ok
\ No newline at end of file diff --git a/Zend/tests/bug36268.phpt b/Zend/tests/bug36268.phpt new file mode 100755 index 0000000000..5276d50d48 --- /dev/null +++ b/Zend/tests/bug36268.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #36268 (Object destructors called even after fatal errors) +--FILE-- +<?php +class Foo { + function __destruct() { + echo "Ha!\n"; + } +} +$x = new Foo(); +bar(); +?> +--EXPECTF-- +Fatal error: Call to undefined function bar() in %sbug36268.php on line 8 diff --git a/Zend/tests/bug36303.phpt b/Zend/tests/bug36303.phpt new file mode 100755 index 0000000000..612022ad56 --- /dev/null +++ b/Zend/tests/bug36303.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #36303 (foreach on error_zval produces segfault) +--FILE-- +<?php +$x="test"; +foreach($x->a->b as &$v) { +} +echo "ok\n"; +?> +--EXPECTF-- +Warning: Invalid argument supplied for foreach() in %sbug36303.php on line 3 +ok diff --git a/Zend/tests/bug36513.phpt b/Zend/tests/bug36513.phpt new file mode 100755 index 0000000000..f46da4efc5 --- /dev/null +++ b/Zend/tests/bug36513.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #36513 (comment will be outputed in last line) +--FILE-- +<?php +function test($s) { + echo "'".trim(str_replace(" ", " ", htmlspecialchars_decode(strip_tags(highlight_string($s,1)))))."'\n"; +} + +eval('echo "1";//2'); +eval('echo 3; //{ 4?>5'); +echo "\n"; + +//test('<?php echo "1";//'); +test('<?php echo "1";//2'); +test('<?php echo "1";//22'); +test('<?php echo 3; // 4 ?>5'); +?> +--EXPECT-- +135 +'<?php echo "1";//2' +'<?php echo "1";//22' +'<?php echo 3; // 4 ?>5' diff --git a/Zend/tests/bug36568.phpt b/Zend/tests/bug36568.phpt new file mode 100755 index 0000000000..d621491a4c --- /dev/null +++ b/Zend/tests/bug36568.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #36568 (memory_limit has no effect) +--SKIPIF-- +<?php + if (!function_exists('memory_get_usage')) die('skip PHP is configured without memory_limit'); +?> +--INI-- +memory_limit=16M +--FILE-- +<?php +ini_set("memory_limit", "32M"); +echo ini_get("memory_limit"); +?> +--EXPECT-- +32M diff --git a/Zend/tests/bug37046.phpt b/Zend/tests/bug37046.phpt new file mode 100755 index 0000000000..09b8f0cb5d --- /dev/null +++ b/Zend/tests/bug37046.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #37046 (foreach breaks static scope) +--FILE-- +<?php +function s() { + static $storage = array(array('x', 'y')); + return $storage[0]; +} + +foreach (s() as $k => $function) { + echo "op1 $k\n"; + if ($k == 0) { + foreach (s() as $k => $function) { + echo "op2 $k\n"; + } + } +} +?> +--EXPECT-- +op1 0 +op2 0 +op2 1 +op1 1 diff --git a/Zend/tests/bug37138.phpt b/Zend/tests/bug37138.phpt new file mode 100755 index 0000000000..f8503f8da9 --- /dev/null +++ b/Zend/tests/bug37138.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #37138 (__autoload tries to load callback'ed self and parent) +--FILE-- +<?php +function __autoload ($CN) {var_dump ($CN);} +class st { + public static function e () {echo ("EHLO\n");} + public static function e2 () {call_user_func (array ('self', 'e'));} +} +class stch extends st { + public static function g () {call_user_func (array ('parent', 'e'));} +} +st::e (); +st::e2 (); +stch::g (); +?> +--EXPECT-- +EHLO +EHLO +EHLO + diff --git a/Zend/tests/zend_strtod.phpt b/Zend/tests/zend_strtod.phpt new file mode 100644 index 0000000000..1b11be0388 --- /dev/null +++ b/Zend/tests/zend_strtod.phpt @@ -0,0 +1,19 @@ +--TEST-- +zend_strtod() leaks on big doubles +--INI-- +precision=14 +--FILE-- +<?php +var_dump("1139932690.21688500" - "1139932790.21688500"); +var_dump("1139932690000.21688500" - "331139932790.21688500"); +var_dump("339932690.21688500" - "4564645646456463461139932790.21688500"); +var_dump("123123139932690.21688500" - "11399327900000000.21688500"); + +echo "Done\n"; +?> +--EXPECTF-- +float(-100) +float(808792757210) +float(-4.5646456464565E+27) +float(-11276204760067000) +Done diff --git a/ext/com_dotnet/tests/bug34272.phpt b/ext/com_dotnet/tests/bug34272.phpt new file mode 100644 index 0000000000..3a65e2ce28 --- /dev/null +++ b/ext/com_dotnet/tests/bug34272.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #34272 (empty array onto COM object blows up) +--SKIPIF-- +<?php +if (!extension_loaded("com_dotnet")) print "skip COM/.Net support not present"; ?> +--FILE-- +<?php +error_reporting(E_ALL); + +try { + $dict = new COM("Scripting.Dictionary"); + $dict->add('foo', array()); + print sizeof($dict['foo'])."\n"; + $dict->add('bar', array(23)); + print sizeof($dict['bar'])." \n"; +} catch (Exception $e) { + print $e; +} +?> +--EXPECT-- +0 +1 diff --git a/ext/date/tests/bug36224.phpt b/ext/date/tests/bug36224.phpt new file mode 100644 index 0000000000..1690f4e7b2 --- /dev/null +++ b/ext/date/tests/bug36224.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #36224 (date(DATE_ATOM) gives wrong resulsts) +--FILE-- +<?php +date_default_timezone_set("Europe/Oslo"); + +echo date(DATE_ATOM, strtotime('2006-01-31T19:23:56Z')) . "\n"; +echo date(DATE_ATOM, strtotime('2006-01-31T19:23:56')) . "\n"; + +?> +--EXPECT-- +2006-01-31T20:23:56+01:00 +2006-01-31T19:23:56+01:00 diff --git a/ext/date/tests/bug36510.phpt b/ext/date/tests/bug36510.phpt new file mode 100644 index 0000000000..ea8bb028b2 --- /dev/null +++ b/ext/date/tests/bug36510.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #36510 (strtotime() fails to parse date strings with tabs) +--FILE-- +<?php +date_default_timezone_set("UTC"); + +$t = 1140973388; + +var_dump(strtotime("-2 hours", $t)); +var_dump(strtotime("-2\thours", $t)); +?> +--EXPECT-- +int(1140966188) +int(1140966188) diff --git a/ext/date/tests/bug36599.phpt b/ext/date/tests/bug36599.phpt new file mode 100644 index 0000000000..b34a7c288f --- /dev/null +++ b/ext/date/tests/bug36599.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #36599 (DATE_W3C format constant incorrect). +--FILE-- +<?php +date_default_timezone_set("UTC"); + +echo date( DATE_ATOM, strtotime( "2006-03-03 08:47:55" ) ), "\n"; +echo date( DATE_W3C, strtotime( "2006-03-03 08:47:55" ) ), "\n"; +?> +--EXPECT-- +2006-03-03T08:47:55+00:00 +2006-03-03T08:47:55+00:00 diff --git a/ext/date/tests/bug36988.phpt b/ext/date/tests/bug36988.phpt new file mode 100644 index 0000000000..d35e58939a --- /dev/null +++ b/ext/date/tests/bug36988.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #36988 (mktime freezes on long numbers) +--INI-- +date.timezone=GMT +--FILE-- +<?php +$start = microtime(true); +$a = mktime(1, 1, 1, 1, 1, 11111111111); +echo (microtime(true) - $start) < 1 ? "smaller than one second" : "more than a second"; +?> +--EXPECT-- +smaller than one second diff --git a/ext/date/tests/bug37017.phpt b/ext/date/tests/bug37017.phpt new file mode 100644 index 0000000000..61dc8ba383 --- /dev/null +++ b/ext/date/tests/bug37017.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #37017 (strtotime fails before 13:00:00 with some time zones identifiers). +--INI-- +date.timezone=GMT +--FILE-- +<?php +echo strtotime("2006-05-12 13:00:01 America/New_York"), "\n"; +echo strtotime("2006-05-12 13:00:00 America/New_York"), "\n"; +echo strtotime("2006-05-12 12:59:59 America/New_York"), "\n"; +echo strtotime("2006-05-12 12:59:59 GMT"), "\n"; +?> +--EXPECT-- +1147453201 +1147453200 +1147453199 +1147438799 diff --git a/ext/dba/tests/bug36436.phpt b/ext/dba/tests/bug36436.phpt new file mode 100755 index 0000000000..e85cf85282 --- /dev/null +++ b/ext/dba/tests/bug36436.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #36436 DBA problem with Berkeley DB4 +--SKIPIF-- +<?php + $handler = 'db4'; + require_once('skipif.inc'); +?> +--FILE-- +<?php + +$handler = 'db4'; +require_once('test.inc'); + +$db = dba_popen($db_filename, 'c', 'db4'); + +dba_insert('X', 'XYZ', $db); +dba_insert('Y', '123', $db); + +var_dump($db, dba_fetch('X', $db)); + +var_dump(dba_firstkey($db)); +var_dump(dba_nextkey($db)); + +dba_close($db); +unlink($db_filename); + +?> +===DONE=== +--EXPECTF-- +resource(%d) of type (dba persistent) +string(3) "XYZ" +string(1) "X" +string(1) "Y" +===DONE=== diff --git a/ext/dom/tests/bug36756.phpt b/ext/dom/tests/bug36756.phpt new file mode 100644 index 0000000000..e24f9f0804 --- /dev/null +++ b/ext/dom/tests/bug36756.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #36756: (DOMDocument::removeChild corrupts node) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + +/* Node is preserved from removeChild */ +$dom = new DOMDocument(); +$dom->loadXML('<root><child/></root>'); +$xpath = new DOMXpath($dom); +$node = $xpath->query('/root')->item(0); +echo $node->nodeName . "\n"; +$dom->removeChild($GLOBALS['dom']->firstChild); +echo "nodeType: " . $node->nodeType . "\n"; + +/* Node gets destroyed during removeChild */ +$dom->loadXML('<root><child/></root>'); +$xpath = new DOMXpath($dom); +$node = $xpath->query('//child')->item(0); +echo $node->nodeName . "\n"; +$GLOBALS['dom']->removeChild($GLOBALS['dom']->firstChild); + +echo "nodeType: " . $node->nodeType . "\n"; + +?> +--EXPECTF-- +root +nodeType: 1 +child + +Warning: Couldn't fetch DOMElement. Node no longer exists in %sbug36756.php on line %d + +Notice: Undefined property: DOMElement::$nodeType in %sbug36756.php on line %d +nodeType: diff --git a/ext/dom/tests/dom007.phpt b/ext/dom/tests/dom007.phpt new file mode 100644 index 0000000000..649d630336 --- /dev/null +++ b/ext/dom/tests/dom007.phpt @@ -0,0 +1,99 @@ +--TEST-- +Test 7: DTD tests +--SKIPIF-- +<?php +require_once('skipif.inc'); +?> +--FILE-- +<?php +$xml = <<< EOXML +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE courses [ +<!ELEMENT courses (course+)> +<!ELEMENT course (title, description, temp*)> +<!ATTLIST course cid ID #REQUIRED> +<!ELEMENT title (#PCDATA)> +<!ELEMENT description (#PCDATA)> +<!ELEMENT temp (#PCDATA)> +<!ATTLIST temp vid ID #REQUIRED> +<!ENTITY test 'http://www.hpl.hp.com/semweb/2003/query_tester#'> +<!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'> +<!NOTATION GIF PUBLIC "-" "image/gif"> +<!ENTITY myimage PUBLIC "-" "mypicture.gif" NDATA GIF> +]> +<courses> + <course cid="c1"> + <title>Basic Languages</title> + <description>Introduction to Languages</description> + </course> + <course cid="c6"> + <title>French I</title> + <description>Introduction to French</description> + <temp vid="c7"> + </temp> + </course> +</courses> +EOXML; + +$dom = new DOMDocument(); +$dom->loadXML($xml); + +$dtd = $dom->doctype; + +/* Notation Tests */ +$nots = $dtd->notations; + +$length = $nots->length; +echo "Length: ".$length."\n"; + +foreach ($nots AS $key=>$node) { + echo "Key $key: ".$node->nodeName." (".$node->systemId.") (".$node->publicId.")\n"; +} +print "\n"; +for($x=0; $x < $length; $x++) { + echo "Index $x: ".$nots->item($x)->nodeName." (".$nots->item($x)->systemId.") (".$nots->item($x)->publicId.")\n"; +} + +echo "\n"; +$node = $nots->getNamedItem('xxx'); +var_dump($node); + +echo "\n"; +/* Entity Decl Tests */ +$ents = $dtd->entities; +$length = $ents->length; +echo "Length: ".$length."\n"; +foreach ($ents AS $key=>$node) { + echo "Key: $key Name: ".$node->nodeName."\n"; +} +echo "\n"; +for($x=0; $x < $length; $x++) { + echo "Index $x: ".$ents->item($x)->nodeName."\n"; +} + +echo "\n"; +$node = $ents->item(3); +var_dump($node); +$node = $ents->getNamedItem('xxx'); +var_dump($node); + + +--EXPECT-- +Length: 1 +Key GIF: GIF (image/gif) (-) + +Index 0: GIF (image/gif) (-) + +NULL + +Length: 3 +Key: test Name: test +Key: rdf Name: rdf +Key: myimage Name: myimage + +Index 0: test +Index 1: rdf +Index 2: myimage + +NULL +NULL diff --git a/ext/gd/tests/bug36697.phpt b/ext/gd/tests/bug36697.phpt new file mode 100644 index 0000000000..b257f63e25 --- /dev/null +++ b/ext/gd/tests/bug36697.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #36697 (TrueColor transparency with GIF palette output). +--SKIPIF-- +<?php + if (!extension_loaded('gd')) { + die("skip gd extension not available\n"); + } + if (!GD_BUNDLED) { + die('skip external GD libraries may fail'); + } +?> +--FILE-- +<?php +$dest = dirname(__FILE__) . "/36697.gif"; + +$im = imagecreatetruecolor(192, 36); +$trans_color = imagecolorallocate($im, 255, 0, 0); +$color = imagecolorallocate($im, 255, 255, 255); +imagecolortransparent($im, $trans_color); +imagefilledrectangle($im, 0,0, 192,36, $trans_color); +$c = imagecolorat($im, 191,35); +imagegif($im, $dest); +imagedestroy($im); +$im = imagecreatefromgif($dest); +$c = imagecolorat($im, 191, 35); +$colors = imagecolorsforindex($im, $c); +echo $colors['red'] . ' ' . $colors['green'] . ' ' . $colors['blue']; +@unlink($dest); +?> +--EXPECT-- +255 0 0 diff --git a/ext/mysqli/tests/bug36420.phpt b/ext/mysqli/tests/bug36420.phpt new file mode 100644 index 0000000000..d35485e7fd --- /dev/null +++ b/ext/mysqli/tests/bug36420.phpt @@ -0,0 +1,25 @@ +--TEST-- +bug #36420 (segfault when access result->num_rows after calling result->close()) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + +include "connect.inc"; +$mysqli = mysqli_connect($host, $user, $passwd); + +$result = $mysqli->query('select 1'); + +$result->close(); +echo $result->num_rows; + +$mysqli->close(); +echo $result->num_rows; + +echo "Done\n"; +?> +--EXPECTF-- +Warning: main(): Couldn't fetch mysqli_result in %s on line %d + +Warning: main(): Couldn't fetch mysqli_result in %s on line %d +Done diff --git a/ext/mysqli/tests/bug36745.phpt b/ext/mysqli/tests/bug36745.phpt new file mode 100644 index 0000000000..7bbfe8180c --- /dev/null +++ b/ext/mysqli/tests/bug36745.phpt @@ -0,0 +1,23 @@ +--TEST-- +bug #36745 : LOAD DATA LOCAL INFILE doesn't return correct error message +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + include ("connect.inc"); + + /*** test mysqli_connect 127.0.0.1 ***/ + $mysql = mysqli_connect($host, $user, $passwd, "test"); + + $mysql->query("DROP TABLE IF EXISTS litest"); + $mysql->query("CREATE TABLE litest (a VARCHAR(20))"); + + $mysql->query("LOAD DATA LOCAL INFILE 'filenotfound' INTO TABLE litest"); + var_dump($mysql->error); + + $mysql->close(); + printf("Done"); +?> +--EXPECT-- +string(31) "Can't find file 'filenotfound'." +Done diff --git a/ext/mysqli/tests/bug36802.phpt b/ext/mysqli/tests/bug36802.phpt new file mode 100644 index 0000000000..69ef56bba0 --- /dev/null +++ b/ext/mysqli/tests/bug36802.phpt @@ -0,0 +1,42 @@ +--TEST-- +bug #36802 : crashes with mysql_init +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + + class my_mysqli extends mysqli { + function __construct() + { + } + } + + include "connect.inc"; + + + $mysql = mysqli_init(); + + /* following operations should not work */ + $x[0] = @$mysql->set_charset('utf8'); + $x[1] = @$mysql->query("SELECT 'foo' FROM DUAL"); + + /* following operations should work */ + $x[2] = ($mysql->client_version > 0); + $x[3] = $mysql->errno; + $mysql->close(); + + + + var_dump($x); +?> +--EXPECT-- +array(4) { + [0]=> + NULL + [1]=> + NULL + [2]=> + bool(true) + [3]=> + int(0) +} diff --git a/ext/oci8/tests/bind_long.phpt b/ext/oci8/tests/bind_long.phpt new file mode 100644 index 0000000000..58590f145a --- /dev/null +++ b/ext/oci8/tests/bind_long.phpt @@ -0,0 +1,38 @@ +--TEST-- +bind LONG field +--SKIPIF-- +<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?> +--FILE-- +<?php + +require dirname(__FILE__)."/connect.inc"; + +$stmt = oci_parse($c, "create table phptestlng( id number(10), fileimage long)"); +oci_execute($stmt); + +$stmt = oci_parse ($c, "insert into phptestlng (id, fileimage) values (:id, :fileimage)"); +$i=1; +$fileimage = file_get_contents( dirname(__FILE__)."/test.gif"); + +oci_bind_by_name( $stmt, ":id", $i, -1); +oci_bind_by_name( $stmt, ":fileimage", $fileimage, -1, SQLT_LNG); +oci_execute($stmt, OCI_DEFAULT); +oci_commit($c); + +$stmt = oci_parse($c, "SELECT fileimage FROM phptestlng"); +oci_execute($stmt); + +$row = oci_fetch_row($stmt); +var_dump(md5($row[0])); +var_dump(strlen($row[0])); + +$stmt = oci_parse($c, "drop table phptestlng"); +oci_execute($stmt); + +echo "Done\n"; + +?> +--EXPECT-- +string(32) "d04e7036e2f4221abc88fd14e960a45b" +int(2523) +Done diff --git a/ext/oci8/tests/bind_long_raw.phpt b/ext/oci8/tests/bind_long_raw.phpt new file mode 100644 index 0000000000..2a9962eace --- /dev/null +++ b/ext/oci8/tests/bind_long_raw.phpt @@ -0,0 +1,38 @@ +--TEST-- +bind LONG RAW field +--SKIPIF-- +<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?> +--FILE-- +<?php + +require dirname(__FILE__)."/connect.inc"; + +$stmt = oci_parse($c, "create table phptestlngraw( id number(10), fileimage long raw)"); +oci_execute($stmt); + +$stmt = oci_parse ($c, "insert into phptestlngraw (id, fileimage) values (:id, :fileimage)"); +$i=1; +$fileimage = file_get_contents( dirname(__FILE__)."/test.gif"); + +oci_bind_by_name( $stmt, ":id", $i, -1); +oci_bind_by_name( $stmt, ":fileimage", $fileimage, -1, SQLT_LBI); +oci_execute($stmt, OCI_DEFAULT); +oci_commit($c); + +$stmt = oci_parse($c, "SELECT fileimage FROM phptestlngraw"); +oci_execute($stmt); + +$row = oci_fetch_row($stmt); +var_dump(md5($row[0])); +var_dump(strlen($row[0])); + +$stmt = oci_parse($c, "drop table phptestlngraw"); +oci_execute($stmt); + +echo "Done\n"; + +?> +--EXPECT-- +string(32) "614fcbba1effb7caa27ef0ef25c27fcf" +int(2523) +Done diff --git a/ext/oci8/tests/bind_raw.phpt b/ext/oci8/tests/bind_raw.phpt new file mode 100644 index 0000000000..c9087e552b --- /dev/null +++ b/ext/oci8/tests/bind_raw.phpt @@ -0,0 +1,39 @@ +--TEST-- +bind RAW field +--SKIPIF-- +<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?> +--FILE-- +<?php + +require dirname(__FILE__)."/connect.inc"; + +$stmt = oci_parse($c, "create table phptestrawtable( id number(10), fileimage raw(1000))"); +oci_execute($stmt); + +$stmt = oci_parse ($c, "insert into phptestrawtable (id, fileimage) values (:id, :fileimage)"); +$i=1; +$fileimage = file_get_contents( dirname(__FILE__)."/test.gif"); +$fileimage = substr($fileimage, 0, 300); + +oci_bind_by_name( $stmt, ":id", $i, -1); +oci_bind_by_name( $stmt, ":fileimage", $fileimage, -1, SQLT_BIN); +oci_execute($stmt, OCI_DEFAULT); +oci_commit($c); + +$stmt = oci_parse($c, "SELECT fileimage FROM phptestrawtable"); +oci_execute($stmt); + +$row = oci_fetch_row($stmt); +var_dump(md5($row[0])); +var_dump(strlen($row[0])); + +$stmt = oci_parse($c, "drop table phptestrawtable"); +oci_execute($stmt); + +echo "Done\n"; + +?> +--EXPECT-- +string(32) "88b274d7a257ac6f70435b83abd4e26e" +int(300) +Done diff --git a/ext/oci8/tests/bug36010.phpt b/ext/oci8/tests/bug36010.phpt new file mode 100644 index 0000000000..ef435496a8 --- /dev/null +++ b/ext/oci8/tests/bug36010.phpt @@ -0,0 +1,26 @@ +--TEST-- +bug #36010 (Crash when executing SQL statment with lob parameter twice) +--SKIPIF-- +<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?> +--FILE-- +<?php + +require dirname(__FILE__).'/connect.inc'; + +function f($conn) +{ + $sql = "begin :p_clob := 'lob string'; end;"; + $stid = oci_parse($conn, $sql); + $clob = oci_new_descriptor($conn, OCI_D_LOB); + oci_bind_by_name($stid, ":p_clob", $clob, -1, OCI_B_CLOB); + $r = oci_execute($stid, OCI_DEFAULT); +} + +f($c); +f($c); + +echo "Done\n"; + +?> +--EXPECT-- +Done diff --git a/ext/oci8/tests/bug36096.phpt b/ext/oci8/tests/bug36096.phpt new file mode 100644 index 0000000000..44b3a6ddca --- /dev/null +++ b/ext/oci8/tests/bug36096.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #36096 (oci_result() returns garbage after oci_fetch() failed) +--SKIPIF-- +<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?> +--FILE-- +<?php + +require dirname(__FILE__)."/connect.inc"; + +$sql = "SELECT 'ABC' FROM DUAL WHERE 1<>1"; +$stmt = oci_parse($c, $sql); + +if(oci_execute($stmt, OCI_COMMIT_ON_SUCCESS)){ + var_dump(oci_fetch($stmt)); + var_dump(oci_result($stmt, 1)); + var_dump(oci_field_name($stmt, 1)); + var_dump(oci_field_type($stmt, 1)); +} + +echo "Done\n"; + +?> +--EXPECT-- +bool(false) +bool(false) +string(5) "'ABC'" +string(4) "CHAR" +Done diff --git a/ext/oci8/tests/lob_019.phpt b/ext/oci8/tests/lob_019.phpt Binary files differnew file mode 100644 index 0000000000..fb9a3c8188 --- /dev/null +++ b/ext/oci8/tests/lob_019.phpt diff --git a/ext/oci8/tests/lob_020.phpt b/ext/oci8/tests/lob_020.phpt Binary files differnew file mode 100644 index 0000000000..edd0f02490 --- /dev/null +++ b/ext/oci8/tests/lob_020.phpt diff --git a/ext/oci8/tests/test.gif b/ext/oci8/tests/test.gif Binary files differnew file mode 100644 index 0000000000..f352c7308f --- /dev/null +++ b/ext/oci8/tests/test.gif diff --git a/ext/pcre/pcrelib/pcre_printint.src b/ext/pcre/pcrelib/pcre_printint.src new file mode 100644 index 0000000000..34f52d114d --- /dev/null +++ b/ext/pcre/pcrelib/pcre_printint.src @@ -0,0 +1,466 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Copyright (c) 1997-2005 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + + +/* This module contains a PCRE private debugging function for printing out the +internal form of a compiled regular expression, along with some supporting +local functions. This source file is used in two places: + +(1) It is #included by pcre_compile.c when it is compiled in debugging mode +(DEBUG defined in pcre_internal.h). It is not included in production compiles. + +(2) It is always #included by pcretest.c, which can be asked to print out a +compiled regex for debugging purposes. */ + + +static const char *OP_names[] = { OP_NAME_LIST }; + + +/************************************************* +* Print single- or multi-byte character * +*************************************************/ + +static int +print_char(FILE *f, uschar *ptr, BOOL utf8) +{ +int c = *ptr; + +if (!utf8 || (c & 0xc0) != 0xc0) + { + if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c); + return 0; + } +else + { + int i; + int a = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int s = 6*a; + c = (c & _pcre_utf8_table3[a]) << s; + for (i = 1; i <= a; i++) + { + /* This is a check for malformed UTF-8; it should only occur if the sanity + check has been turned off. Rather than swallow random bytes, just stop if + we hit a bad one. Print it with \X instead of \x as an indication. */ + + if ((ptr[i] & 0xc0) != 0x80) + { + fprintf(f, "\\X{%x}", c); + return i - 1; + } + + /* The byte is OK */ + + s -= 6; + c |= (ptr[i] & 0x3f) << s; + } + if (c < 128) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c); + return a; + } +} + + + +/************************************************* +* Find Unicode property name * +*************************************************/ + +static const char * +get_ucpname(int ptype, int pvalue) +{ +#ifdef SUPPORT_UCP +int i; +for (i = _pcre_utt_size; i >= 0; i--) + { + if (ptype == _pcre_utt[i].type && pvalue == _pcre_utt[i].value) break; + } +return (i >= 0)? _pcre_utt[i].name : "??"; +#else +ptype = ptype; /* Avoid compiler warning */ +pvalue = pvalue; +return "??"; +#endif +} + + + +/************************************************* +* Print compiled regex * +*************************************************/ + +/* Make this function work for a regex with integers either byte order. +However, we assume that what we are passed is a compiled regex. */ + +static void +pcre_printint(pcre *external_re, FILE *f) +{ +real_pcre *re = (real_pcre *)external_re; +uschar *codestart, *code; +BOOL utf8; + +unsigned int options = re->options; +int offset = re->name_table_offset; +int count = re->name_count; +int size = re->name_entry_size; + +if (re->magic_number != MAGIC_NUMBER) + { + offset = ((offset << 8) & 0xff00) | ((offset >> 8) & 0xff); + count = ((count << 8) & 0xff00) | ((count >> 8) & 0xff); + size = ((size << 8) & 0xff00) | ((size >> 8) & 0xff); + options = ((options << 24) & 0xff000000) | + ((options << 8) & 0x00ff0000) | + ((options >> 8) & 0x0000ff00) | + ((options >> 24) & 0x000000ff); + } + +code = codestart = (uschar *)re + offset + count * size; +utf8 = (options & PCRE_UTF8) != 0; + +for(;;) + { + uschar *ccode; + int c; + int extra = 0; + + fprintf(f, "%3d ", (int)(code - codestart)); + + if (*code >= OP_BRA) + { + if (*code - OP_BRA > EXTRACT_BASIC_MAX) + fprintf(f, "%3d Bra extra\n", GET(code, 1)); + else + fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA); + code += _pcre_OP_lengths[OP_BRA]; + continue; + } + + switch(*code) + { + case OP_END: + fprintf(f, " %s\n", OP_names[*code]); + fprintf(f, "------------------------------------------------------------------\n"); + return; + + case OP_OPT: + fprintf(f, " %.2x %s", code[1], OP_names[*code]); + break; + + case OP_CHAR: + { + fprintf(f, " "); + do + { + code++; + code += 1 + print_char(f, code, utf8); + } + while (*code == OP_CHAR); + fprintf(f, "\n"); + continue; + } + break; + + case OP_CHARNC: + { + fprintf(f, " NC "); + do + { + code++; + code += 1 + print_char(f, code, utf8); + } + while (*code == OP_CHARNC); + fprintf(f, "\n"); + continue; + } + break; + + case OP_KETRMAX: + case OP_KETRMIN: + case OP_ALT: + case OP_KET: + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_COND: + case OP_REVERSE: + fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]); + break; + + case OP_BRANUMBER: + printf("%3d %s", GET2(code, 1), OP_names[*code]); + break; + + case OP_CREF: + if (GET2(code, 1) == CREF_RECURSE) + fprintf(f, " Cond recurse"); + else + fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]); + break; + + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + fprintf(f, " "); + if (*code >= OP_TYPESTAR) + { + fprintf(f, "%s", OP_names[code[1]]); + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) + { + fprintf(f, " %s ", get_ucpname(code[2], code[3])); + extra = 2; + } + } + else extra = print_char(f, code+1, utf8); + fprintf(f, "%s", OP_names[*code]); + break; + + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: + fprintf(f, " "); + extra = print_char(f, code+3, utf8); + fprintf(f, "{"); + if (*code != OP_EXACT) fprintf(f, ","); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_MINUPTO) fprintf(f, "?"); + break; + + case OP_TYPEEXACT: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + fprintf(f, " %s", OP_names[code[3]]); + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) + { + fprintf(f, " %s ", get_ucpname(code[4], code[5])); + extra = 2; + } + fprintf(f, "{"); + if (*code != OP_TYPEEXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_TYPEMINUPTO) fprintf(f, "?"); + break; + + case OP_NOT: + if (isprint(c = code[1])) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + break; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + if (isprint(c = code[1])) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + fprintf(f, "%s", OP_names[*code]); + break; + + case OP_NOTEXACT: + case OP_NOTUPTO: + case OP_NOTMINUPTO: + if (isprint(c = code[3])) fprintf(f, " [^%c]{", c); + else fprintf(f, " [^\\x%02x]{", c); + if (*code != OP_NOTEXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_NOTMINUPTO) fprintf(f, "?"); + break; + + case OP_RECURSE: + fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]); + break; + + case OP_REF: + fprintf(f, " \\%d", GET2(code,1)); + ccode = code + _pcre_OP_lengths[*code]; + goto CLASS_REF_REPEAT; + + case OP_CALLOUT: + fprintf(f, " %s %d %d %d", OP_names[*code], code[1], GET(code,2), + GET(code, 2 + LINK_SIZE)); + break; + + case OP_PROP: + case OP_NOTPROP: + fprintf(f, " %s %s", OP_names[*code], get_ucpname(code[1], code[2])); + break; + + /* OP_XCLASS can only occur in UTF-8 mode. However, there's no harm in + having this code always here, and it makes it less messy without all those + #ifdefs. */ + + case OP_CLASS: + case OP_NCLASS: + case OP_XCLASS: + { + int i, min, max; + BOOL printmap; + + fprintf(f, " ["); + + if (*code == OP_XCLASS) + { + extra = GET(code, 1); + ccode = code + LINK_SIZE + 1; + printmap = (*ccode & XCL_MAP) != 0; + if ((*ccode++ & XCL_NOT) != 0) fprintf(f, "^"); + } + else + { + printmap = TRUE; + ccode = code + 1; + } + + /* Print a bit map */ + + if (printmap) + { + for (i = 0; i < 256; i++) + { + if ((ccode[i/8] & (1 << (i&7))) != 0) + { + int j; + for (j = i+1; j < 256; j++) + if ((ccode[j/8] & (1 << (j&7))) == 0) break; + if (i == '-' || i == ']') fprintf(f, "\\"); + if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i); + if (--j > i) + { + if (j != i + 1) fprintf(f, "-"); + if (j == '-' || j == ']') fprintf(f, "\\"); + if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j); + } + i = j; + } + } + ccode += 32; + } + + /* For an XCLASS there is always some additional data */ + + if (*code == OP_XCLASS) + { + int ch; + while ((ch = *ccode++) != XCL_END) + { + if (ch == XCL_PROP) + { + int ptype = *ccode++; + int pvalue = *ccode++; + fprintf(f, "\\p{%s}", get_ucpname(ptype, pvalue)); + } + else if (ch == XCL_NOTPROP) + { + int ptype = *ccode++; + int pvalue = *ccode++; + fprintf(f, "\\P{%s}", get_ucpname(ptype, pvalue)); + } + else + { + ccode += 1 + print_char(f, ccode, TRUE); + if (ch == XCL_RANGE) + { + fprintf(f, "-"); + ccode += 1 + print_char(f, ccode, TRUE); + } + } + } + } + + /* Indicate a non-UTF8 class which was created by negation */ + + fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : ""); + + /* Handle repeats after a class or a back reference */ + + CLASS_REF_REPEAT: + switch(*ccode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + fprintf(f, "%s", OP_names[*ccode]); + extra += _pcre_OP_lengths[*ccode]; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + min = GET2(ccode,1); + max = GET2(ccode,3); + if (max == 0) fprintf(f, "{%d,}", min); + else fprintf(f, "{%d,%d}", min, max); + if (*ccode == OP_CRMINRANGE) fprintf(f, "?"); + extra += _pcre_OP_lengths[*ccode]; + break; + + /* Do nothing if it's not a repeat; this code stops picky compilers + warning about the lack of a default code path. */ + + default: + break; + } + } + break; + + /* Anything else is just an item with no data*/ + + default: + fprintf(f, " %s", OP_names[*code]); + break; + } + + code += _pcre_OP_lengths[*code] + extra; + fprintf(f, "\n"); + } +} + +/* End of pcre_printint.src */ diff --git a/ext/pcre/pcrelib/pcre_ucp_searchfuncs.c b/ext/pcre/pcrelib/pcre_ucp_searchfuncs.c new file mode 100644 index 0000000000..ac964ca903 --- /dev/null +++ b/ext/pcre/pcrelib/pcre_ucp_searchfuncs.c @@ -0,0 +1,175 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + + +/* This module contains code for searching the table of Unicode character +properties. */ + +#include "pcre_internal.h" + +#include "ucp.h" /* Category definitions */ +#include "ucpinternal.h" /* Internal table details */ +#include "ucptable.c" /* The table itself */ + + +/* Table to translate from particular type value to the general value. */ + +static int ucp_gentype[] = { + ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ + ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ + ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ + ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */ + ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */ + ucp_P, ucp_P, /* Ps, Po */ + ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */ + ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ +}; + + + +/************************************************* +* Search table and return type * +*************************************************/ + +/* Three values are returned: the category is ucp_C, ucp_L, etc. The detailed +character type is ucp_Lu, ucp_Nd, etc. The script is ucp_Latin, etc. + +Arguments: + c the character value + type_ptr the detailed character type is returned here + script_ptr the script is returned here + +Returns: the character type category +*/ + +int +_pcre_ucp_findprop(const int c, int *type_ptr, int *script_ptr) +{ +int bot = 0; +int top = sizeof(ucp_table)/sizeof(cnode); +int mid; + +/* The table is searched using a binary chop. You might think that using +intermediate variables to hold some of the common expressions would speed +things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it +makes things a lot slower. */ + +for (;;) + { + if (top <= bot) + { + *type_ptr = ucp_Cn; + *script_ptr = ucp_Common; + return ucp_C; + } + mid = (bot + top) >> 1; + if (c == (ucp_table[mid].f0 & f0_charmask)) break; + if (c < (ucp_table[mid].f0 & f0_charmask)) top = mid; + else + { + if ((ucp_table[mid].f0 & f0_rangeflag) != 0 && + c <= (ucp_table[mid].f0 & f0_charmask) + + (ucp_table[mid].f1 & f1_rangemask)) break; + bot = mid + 1; + } + } + +/* Found an entry in the table. Set the script and detailed type values, and +return the general type. */ + +*script_ptr = (ucp_table[mid].f0 & f0_scriptmask) >> f0_scriptshift; +*type_ptr = (ucp_table[mid].f1 & f1_typemask) >> f1_typeshift; + +return ucp_gentype[*type_ptr]; +} + + + +/************************************************* +* Search table and return other case * +*************************************************/ + +/* If the given character is a letter, and there is another case for the +letter, return the other case. Otherwise, return -1. + +Arguments: + c the character value + +Returns: the other case or -1 if none +*/ + +int +_pcre_ucp_othercase(const int c) +{ +int bot = 0; +int top = sizeof(ucp_table)/sizeof(cnode); +int mid, offset; + +/* The table is searched using a binary chop. You might think that using +intermediate variables to hold some of the common expressions would speed +things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it +makes things a lot slower. */ + +for (;;) + { + if (top <= bot) return -1; + mid = (bot + top) >> 1; + if (c == (ucp_table[mid].f0 & f0_charmask)) break; + if (c < (ucp_table[mid].f0 & f0_charmask)) top = mid; + else + { + if ((ucp_table[mid].f0 & f0_rangeflag) != 0 && + c <= (ucp_table[mid].f0 & f0_charmask) + + (ucp_table[mid].f1 & f1_rangemask)) break; + bot = mid + 1; + } + } + +/* Found an entry in the table. Return -1 for a range entry. Otherwise return +the other case if there is one, else -1. */ + +if ((ucp_table[mid].f0 & f0_rangeflag) != 0) return -1; + +offset = ucp_table[mid].f1 & f1_casemask; +if ((offset & f1_caseneg) != 0) offset |= f1_caseneg; +return (offset == 0)? -1 : c + offset; +} + + +/* End of pcre_ucp_searchfuncs.c */ diff --git a/ext/pcre/pcrelib/pcrecpparg.h b/ext/pcre/pcrelib/pcrecpparg.h new file mode 100644 index 0000000000..323dde58e5 --- /dev/null +++ b/ext/pcre/pcrelib/pcrecpparg.h @@ -0,0 +1,171 @@ +// Copyright (c) 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat + +#ifndef _PCRECPPARG_H +#define _PCRECPPARG_H + +#include <stdlib.h> // for NULL +#include <string> + +namespace pcrecpp { + +class StringPiece; + +// Hex/Octal/Binary? + +// Special class for parsing into objects that define a ParseFrom() method +template <class T> +class _RE_MatchObject { + public: + static inline bool Parse(const char* str, int n, void* dest) { + T* object = reinterpret_cast<T*>(dest); + return object->ParseFrom(str, n); + } +}; + +class Arg { + public: + // Empty constructor so we can declare arrays of Arg + Arg(); + + // Constructor specially designed for NULL arguments + Arg(void*); + + typedef bool (*Parser)(const char* str, int n, void* dest); + +// Type-specific parsers +#define PCRE_MAKE_PARSER(type,name) \ + Arg(type* p) : arg_(p), parser_(name) { } \ + Arg(type* p, Parser parser) : arg_(p), parser_(parser) { } + + + PCRE_MAKE_PARSER(char, parse_char); + PCRE_MAKE_PARSER(unsigned char, parse_uchar); + PCRE_MAKE_PARSER(short, parse_short); + PCRE_MAKE_PARSER(unsigned short, parse_ushort); + PCRE_MAKE_PARSER(int, parse_int); + PCRE_MAKE_PARSER(unsigned int, parse_uint); + PCRE_MAKE_PARSER(long, parse_long); + PCRE_MAKE_PARSER(unsigned long, parse_ulong); +#if 1 + PCRE_MAKE_PARSER(long long, parse_longlong); +#endif +#if 1 + PCRE_MAKE_PARSER(unsigned long long, parse_ulonglong); +#endif + PCRE_MAKE_PARSER(float, parse_float); + PCRE_MAKE_PARSER(double, parse_double); + PCRE_MAKE_PARSER(std::string, parse_string); + PCRE_MAKE_PARSER(StringPiece, parse_stringpiece); + +#undef PCRE_MAKE_PARSER + + // Generic constructor + template <class T> Arg(T*, Parser parser); + // Generic constructor template + template <class T> Arg(T* p) + : arg_(p), parser_(_RE_MatchObject<T>::Parse) { + } + + // Parse the data + bool Parse(const char* str, int n) const; + + private: + void* arg_; + Parser parser_; + + static bool parse_null (const char* str, int n, void* dest); + static bool parse_char (const char* str, int n, void* dest); + static bool parse_uchar (const char* str, int n, void* dest); + static bool parse_float (const char* str, int n, void* dest); + static bool parse_double (const char* str, int n, void* dest); + static bool parse_string (const char* str, int n, void* dest); + static bool parse_stringpiece (const char* str, int n, void* dest); + +#define PCRE_DECLARE_INTEGER_PARSER(name) \ + private: \ + static bool parse_ ## name(const char* str, int n, void* dest); \ + static bool parse_ ## name ## _radix( \ + const char* str, int n, void* dest, int radix); \ + public: \ + static bool parse_ ## name ## _hex(const char* str, int n, void* dest); \ + static bool parse_ ## name ## _octal(const char* str, int n, void* dest); \ + static bool parse_ ## name ## _cradix(const char* str, int n, void* dest) + + PCRE_DECLARE_INTEGER_PARSER(short); + PCRE_DECLARE_INTEGER_PARSER(ushort); + PCRE_DECLARE_INTEGER_PARSER(int); + PCRE_DECLARE_INTEGER_PARSER(uint); + PCRE_DECLARE_INTEGER_PARSER(long); + PCRE_DECLARE_INTEGER_PARSER(ulong); + PCRE_DECLARE_INTEGER_PARSER(longlong); + PCRE_DECLARE_INTEGER_PARSER(ulonglong); + +#undef PCRE_DECLARE_INTEGER_PARSER +}; + +inline Arg::Arg() : arg_(NULL), parser_(parse_null) { } +inline Arg::Arg(void* p) : arg_(p), parser_(parse_null) { } + +inline bool Arg::Parse(const char* str, int n) const { + return (*parser_)(str, n, arg_); +} + +// This part of the parser, appropriate only for ints, deals with bases +#define MAKE_INTEGER_PARSER(type, name) \ + inline Arg Hex(type* ptr) { \ + return Arg(ptr, Arg::parse_ ## name ## _hex); } \ + inline Arg Octal(type* ptr) { \ + return Arg(ptr, Arg::parse_ ## name ## _octal); } \ + inline Arg CRadix(type* ptr) { \ + return Arg(ptr, Arg::parse_ ## name ## _cradix); } + +MAKE_INTEGER_PARSER(short, short); +MAKE_INTEGER_PARSER(unsigned short, ushort); +MAKE_INTEGER_PARSER(int, int); +MAKE_INTEGER_PARSER(unsigned int, uint); +MAKE_INTEGER_PARSER(long, long); +MAKE_INTEGER_PARSER(unsigned long, ulong); +#if 1 +MAKE_INTEGER_PARSER(long long, longlong); +#endif +#if 1 +MAKE_INTEGER_PARSER(unsigned long long, ulonglong); +#endif + +#undef PCRE_IS_SET +#undef PCRE_SET_OR_CLEAR +#undef MAKE_INTEGER_PARSER + +} // namespace pcrecpp + + +#endif /* _PCRECPPARG_H */ diff --git a/ext/pdo/tests/bug_35671.phpt b/ext/pdo/tests/bug_35671.phpt new file mode 100644 index 0000000000..768773f90d --- /dev/null +++ b/ext/pdo/tests/bug_35671.phpt @@ -0,0 +1,45 @@ +--TEST-- +PDO Common: PHP Bug #35671: binding by name breakage +--SKIPIF-- +<?php # vim:ft=php +if (!extension_loaded('pdo')) die('skip'); +$dir = getenv('REDIR_TEST_DIR'); +if (false == $dir) die('skip no driver'); +require_once $dir . 'pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/'); +require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; +$db = PDOTest::factory(); + +$db->exec('CREATE TABLE test (field1 VARCHAR(32), field2 VARCHAR(32), field3 VARCHAR(32))'); +$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +$insert = $db->prepare("insert into test (field1, field2, field3) values (:value1, :value2, :value3)"); + +$parm = array( + ":value1" => 15, + ":value2" => 20, + ":value3" => 25 +); + +$insert->execute($parm); +$insert = null; + +var_dump($db->query("SELECT * from test")->fetchAll(PDO::FETCH_ASSOC)); + +?> +--EXPECT-- +array(1) { + [0]=> + array(3) { + ["field1"]=> + string(2) "15" + ["field2"]=> + string(2) "20" + ["field3"]=> + string(2) "25" + } +} diff --git a/ext/pdo_pgsql/tests/bug36727.phpt b/ext/pdo_pgsql/tests/bug36727.phpt new file mode 100644 index 0000000000..c6f7c8a80f --- /dev/null +++ b/ext/pdo_pgsql/tests/bug36727.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #36727 (segfault in bindValue() when no parameters are defined) +--SKIPIF-- +<?php +if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +require dirname(__FILE__) . '/config.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +require dirname(__FILE__) . '/config.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); + +$stmt = $db->prepare('SELECT * FROM child'); +var_dump($stmt->bindValue(':test', 1, PDO::PARAM_INT)); + +echo "Done\n"; +?> +--EXPECT-- +bool(false) +Done diff --git a/ext/pgsql/tests/80_bug36625.phpt b/ext/pgsql/tests/80_bug36625.phpt new file mode 100755 index 0000000000..a95cea7110 --- /dev/null +++ b/ext/pgsql/tests/80_bug36625.phpt @@ -0,0 +1,49 @@ +--TEST-- +Bug #36625 (pg_trace() does not work) +--SKIPIF-- +<?php +require_once('skipif.inc'); +?> +--FILE-- +<?php + +require_once('config.inc'); + +$dbh = @pg_connect($conn_str); +if (!$dbh) { + die ('Could not connect to the server'); +} + +$tracefile = dirname(__FILE__) . '/trace.tmp'; + +@unlink($tracefile); +var_dump(file_exists($tracefile)); + +pg_trace($tracefile, 'w', $dbh); +$res = pg_query($dbh, 'select 1'); +var_dump($res); +pg_close($dbh); + +$found = 0; +function search_trace_file($line) +{ + if (strpos($line, '"select 1"') !== false || strpos($line, "'select 1'") !== false) { + $GLOBALS['found']++; + } +} + +$trace = file($tracefile); +array_walk($trace, 'search_trace_file'); +var_dump($found > 0); +var_dump(file_exists($tracefile)); + +?> +===DONE=== +--CLEAN-- +<?php unlink($tracefile); ?> +--EXPECTF-- +bool(false) +resource(%d) of type (pgsql result) +bool(true) +bool(true) +===DONE=== diff --git a/ext/reflection/tests/007.phpt b/ext/reflection/tests/007.phpt new file mode 100755 index 0000000000..83764e5515 --- /dev/null +++ b/ext/reflection/tests/007.phpt @@ -0,0 +1,162 @@ +--TEST-- +ReflectionClass::newInstance[Args] +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php + +function test($class) +{ + echo "====>$class\n"; + try + { + $ref = new ReflectionClass($class); + } + catch (ReflectionException $e) + { + var_dump($e->getMessage()); + return; // only here + } + + echo "====>newInstance()\n"; + try + { + var_dump($ref->newInstance()); + } + catch (ReflectionException $e) + { + var_dump($e->getMessage()); + } + + echo "====>newInstance(25)\n"; + try + { + var_dump($ref->newInstance(25)); + } + catch (ReflectionException $e) + { + var_dump($e->getMessage()); + } + + echo "====>newInstance(25, 42)\n"; + try + { + var_dump($ref->newInstance(25, 42)); + } + catch (ReflectionException $e) + { + var_dump($e->getMessage()); + } + + echo "\n"; +} + +function __autoload($class) +{ + echo __FUNCTION__ . "($class)\n"; +} + +test('Class_does_not_exist'); + +Class NoCtor +{ +} + +test('NoCtor'); + +Class WithCtor +{ + function __construct() + { + echo __METHOD__ . "()\n"; + var_dump(func_get_args()); + } +} + +test('WithCtor'); + +Class WithCtorWithArgs +{ + function __construct($arg) + { + echo __METHOD__ . "($arg)\n"; + var_dump(func_get_args()); + } +} + +test('WithCtorWithArgs'); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- + +====>Class_does_not_exist +__autoload(Class_does_not_exist) +string(41) "Class Class_does_not_exist does not exist" +====>NoCtor +====>newInstance() +object(NoCtor)#%d (0) { +} +====>newInstance(25) +string(86) "Class NoCtor does not have a constructor, so you cannot pass any constructor arguments" +====>newInstance(25, 42) +string(86) "Class NoCtor does not have a constructor, so you cannot pass any constructor arguments" + +====>WithCtor +====>newInstance() +WithCtor::__construct() +array(0) { +} +object(WithCtor)#%d (0) { +} +====>newInstance(25) +WithCtor::__construct() +array(1) { + [0]=> + int(25) +} +object(WithCtor)#%d (0) { +} +====>newInstance(25, 42) +WithCtor::__construct() +array(2) { + [0]=> + int(25) + [1]=> + int(42) +} +object(WithCtor)#%d (0) { +} + +====>WithCtorWithArgs +====>newInstance() + +Warning: Missing argument 1 for WithCtorWithArgs::__construct() in %s007.php on line %d + +Notice: Undefined variable: arg in %s007.php on line %d +WithCtorWithArgs::__construct() +array(0) { +} +object(WithCtorWithArgs)#%d (0) { +} +====>newInstance(25) +WithCtorWithArgs::__construct(25) +array(1) { + [0]=> + int(25) +} +object(WithCtorWithArgs)#%d (0) { +} +====>newInstance(25, 42) +WithCtorWithArgs::__construct(25) +array(2) { + [0]=> + int(25) + [1]=> + int(42) +} +object(WithCtorWithArgs)#%d (0) { +} + +===DONE=== diff --git a/ext/reflection/tests/bug29986.phpt b/ext/reflection/tests/bug29986.phpt new file mode 100644 index 0000000000..85bad6d6ec --- /dev/null +++ b/ext/reflection/tests/bug29986.phpt @@ -0,0 +1,41 @@ +--TEST-- +Reflection Bug #29986 (Class constants won't work with predefined constants when using ReflectionClass) +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php +class just_constants +{ + const BOOLEAN_CONSTANT = true; + const NULL_CONSTANT = null; + const STRING_CONSTANT = 'This is a string'; + const INTEGER_CONSTANT = 1000; + const FLOAT_CONSTANT = 3.14159265; +} + +Reflection::export(new ReflectionClass('just_constants')); +?> +--EXPECTF-- +Class [ <user> class just_constants ] { + @@ %s + + - Constants [5] { + Constant [ boolean BOOLEAN_CONSTANT ] { } + Constant [ null NULL_CONSTANT ] { } + Constant [ string STRING_CONSTANT ] { } + Constant [ integer INTEGER_CONSTANT ] { } + Constant [ double FLOAT_CONSTANT ] { } + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} diff --git a/ext/reflection/tests/bug36308.phpt b/ext/reflection/tests/bug36308.phpt new file mode 100755 index 0000000000..52717b474a --- /dev/null +++ b/ext/reflection/tests/bug36308.phpt @@ -0,0 +1,22 @@ +--TEST-- +Reflection Bug #36308 (ReflectionProperty::getDocComment() does not reflect extended class commentary) +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php +class Base { + /** Base comment block */ + public $foo = 'bar'; +} + +class Extended extends Base { + /** Extended commentary */ + public $foo = 'zim'; +} + +$reflect = new ReflectionClass('Extended'); +$props = $reflect->getProperties(); +echo $props[0]->getDocComment(); +?> +--EXPECT-- +/** Extended commentary */
\ No newline at end of file diff --git a/ext/reflection/tests/bug36337.phpt b/ext/reflection/tests/bug36337.phpt new file mode 100644 index 0000000000..8ec928fc89 --- /dev/null +++ b/ext/reflection/tests/bug36337.phpt @@ -0,0 +1,30 @@ +--TEST-- +Reflection Bug #36337 (ReflectionProperty fails to return correct visibility) +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php + +abstract class enum { + protected $_values; + + public function __construct() { + $property = new ReflectionProperty(get_class($this),'_values'); + var_dump($property->isProtected()); + } + +} + +final class myEnum extends enum { + public $_values = array( + 0 => 'No value', + ); +} + +$x = new myEnum(); + +echo "Done\n"; +?> +--EXPECT-- +bool(false) +Done diff --git a/ext/reflection/tests/bug36434.phpt b/ext/reflection/tests/bug36434.phpt new file mode 100644 index 0000000000..e305c657a8 --- /dev/null +++ b/ext/reflection/tests/bug36434.phpt @@ -0,0 +1,33 @@ +--TEST-- +Reflection Bug #36434 (Properties from parent class fail to indetify their true origin) +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php +class ancester +{ +public $ancester = 0; + function ancester() + { + return $this->ancester; + } +} +class foo extends ancester +{ +public $bar = "1"; + function foo() + { + return $this->bar; + } +} + +$r = new ReflectionClass('foo'); +foreach ($r->GetProperties() as $p) +{ + echo $p->getName(). " ". $p->getDeclaringClass()->getName()."\n"; +} + +?> +--EXPECT-- +bar foo +ancester ancester diff --git a/ext/reflection/tests/parameters_002.phpt b/ext/reflection/tests/parameters_002.phpt new file mode 100755 index 0000000000..6f911448c2 --- /dev/null +++ b/ext/reflection/tests/parameters_002.phpt @@ -0,0 +1,209 @@ +--TEST-- +ReflectionParameter::getClass(), getDeclaringClass(), getDeclaringFunction() +--SKIPIF-- +<?php extension_loaded('reflection') or die('skip'); ?> +--FILE-- +<?php + +function test($nix, Array $ar, &$ref, stdClass $std, NonExistingClass $na, stdClass &$opt = NULL, $def = "FooBar") +{ +} + +class test +{ + function test($nix, Array $ar, &$ref, stdClass $std, NonExistingClass $na, stdClass $opt = NULL, $def = "FooBar") + { + } +} + +function check_params_decl_func($r, $f) +{ + $c = $r->$f(); + echo $f . ': ' . ($c ? ($c instanceof ReflectionMethod ? $c->class . '::' : '') . $c->name : 'NULL') . "()\n"; +} + +function check_params_decl_class($r, $f) +{ + $c = $r->$f(); + echo $f . ': ' . ($c ? $c->name : 'NULL') . "\n"; +} + +function check_params_func($r, $f) +{ + echo $f . ': '; + $v = $r->$f(); + var_dump($v); +} + +function check_params($r) +{ + echo "#####" . ($r instanceof ReflectionMethod ? $r->class . '::' : '') . $r->name . "()#####\n"; + $i = 0; + foreach($r->getParameters() as $p) + { + echo "===" . $i . "===\n"; + $i++; + check_params_func($p, 'getName'); + check_params_func($p, 'isPassedByReference'); + try + { + check_params_decl_class($p, 'getClass'); + } + catch(ReflectionException $e) + { + echo $e->getMessage() . "\n"; + } + check_params_decl_class($p, 'getDeclaringClass'); +// check_params_decl_func($p, 'getDeclaringFunction'); + check_params_func($p, 'isArray'); + check_params_func($p, 'allowsNull'); + check_params_func($p, 'isOptional'); + check_params_func($p, 'isDefaultValueAvailable'); + if ($p->isOptional()) + { + check_params_func($p, 'getDefaultValue'); + } + } +} + +check_params(new ReflectionFunction('test')); + +check_params(new ReflectionMethod('test::test')); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +#####test()##### +===0=== +getName: string(3) "nix" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===1=== +getName: string(2) "ar" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: NULL +isArray: bool(true) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===2=== +getName: string(3) "ref" +isPassedByReference: bool(true) +getClass: NULL +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===3=== +getName: string(3) "std" +isPassedByReference: bool(false) +getClass: stdClass +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===4=== +getName: string(2) "na" +isPassedByReference: bool(false) +Class NonExistingClass does not exist +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===5=== +getName: string(3) "opt" +isPassedByReference: bool(true) +getClass: stdClass +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(true) +isDefaultValueAvailable: bool(true) +getDefaultValue: NULL +===6=== +getName: string(3) "def" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: NULL +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(true) +isDefaultValueAvailable: bool(true) +getDefaultValue: string(6) "FooBar" +#####test::test()##### +===0=== +getName: string(3) "nix" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===1=== +getName: string(2) "ar" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: test +isArray: bool(true) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===2=== +getName: string(3) "ref" +isPassedByReference: bool(true) +getClass: NULL +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===3=== +getName: string(3) "std" +isPassedByReference: bool(false) +getClass: stdClass +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===4=== +getName: string(2) "na" +isPassedByReference: bool(false) +Class NonExistingClass does not exist +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(false) +isOptional: bool(false) +isDefaultValueAvailable: bool(false) +===5=== +getName: string(3) "opt" +isPassedByReference: bool(false) +getClass: stdClass +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(true) +isDefaultValueAvailable: bool(true) +getDefaultValue: NULL +===6=== +getName: string(3) "def" +isPassedByReference: bool(false) +getClass: NULL +getDeclaringClass: test +isArray: bool(false) +allowsNull: bool(true) +isOptional: bool(true) +isDefaultValueAvailable: bool(true) +getDefaultValue: string(6) "FooBar" +===DONE=== diff --git a/ext/session/tests/bug36459.phpt b/ext/session/tests/bug36459.phpt new file mode 100644 index 0000000000..30c94f81d9 --- /dev/null +++ b/ext/session/tests/bug36459.phpt @@ -0,0 +1,41 @@ +--TEST-- +bug #31454 (Incorrect adding PHPSESSID to links, which contains \r\n) +--SKIPIF-- +<?php include('skipif.inc'); ?> +--FILE-- +<?php +error_reporting(E_ALL); + +ini_set('session.use_trans_sid', 1); +ini_set('session.use_cookies', 0); +ini_set('session.name', 'sid'); + +session_start(); + +# Do not remove \r from this tests, they are essential! +?> +<html> + <head> + <title>Bug #36459 Incorrect adding PHPSESSID to links, which contains \r\n</title> + </head> + <body> + <p>See source html code</p> + <a href="/b2w/www/ru/adm/pages/?action=prev&rec_id=8&pid=2" + style="font: normal 11pt Times New Roman">incorrect link</a><br /> + <br /> + <a href="/b2w/www/ru/adm/pages/?action=prev&rec_id=8&pid=2" style="font: normal 11pt Times New Roman">correct link</a> + </body> +</html> +--EXPECTF-- +<html> + <head> + <title>Bug #36459 Incorrect adding PHPSESSID to links, which contains \r\n</title> + </head> + <body> + <p>See source html code</p> + <a href="/b2w/www/ru/adm/pages/?action=prev&rec_id=8&pid=2&sid=%s" + style="font: normal 11pt Times New Roman">incorrect link</a><br /> + <br /> + <a href="/b2w/www/ru/adm/pages/?action=prev&rec_id=8&pid=2&sid=%s" style="font: normal 11pt Times New Roman">correct link</a> + </body> +</html> diff --git a/ext/simplexml/tests/009b.phpt b/ext/simplexml/tests/009b.phpt new file mode 100755 index 0000000000..dba300c72f --- /dev/null +++ b/ext/simplexml/tests/009b.phpt @@ -0,0 +1,35 @@ +--TEST-- +SimpleXML: foreach +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$sxe = simplexml_load_string(<<<EOF +<?xml version='1.0'?> +<!DOCTYPE sxe SYSTEM "notfound.dtd"> +<sxe id="elem1"> + Plain text. + <elem1 attr1='first'>Bla bla 1.<!-- comment --><elem2> + Here we have some text data. + </elem2></elem1> + <elem11 attr2='second'>Bla bla 2.</elem11> +</sxe> +EOF +); +var_dump($sxe->children()); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(SimpleXMLElement)#%d (3) { + ["@attributes"]=> + array(1) { + ["id"]=> + string(5) "elem1" + } + ["elem1"]=> + string(10) "Bla bla 1." + ["elem11"]=> + string(10) "Bla bla 2." +} +===DONE=== diff --git a/ext/simplexml/tests/026.phpt b/ext/simplexml/tests/026.phpt new file mode 100755 index 0000000000..d6de94be3d --- /dev/null +++ b/ext/simplexml/tests/026.phpt @@ -0,0 +1,40 @@ +--TEST-- +SimpleXML: getName() +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<people> + <person>Jane</person> +</people> +EOF; + +function traverse_xml($xml, $pad = '') +{ + $name = $xml->getName(); + echo "$pad<$name"; + foreach($xml->attributes() as $attr => $value) + { + echo " $attr=\"$value\""; + } + echo ">" . trim($xml) . "\n"; + foreach($xml->children() as $node) + { + traverse_xml($node, $pad.' '); + } + echo $pad."</$name>\n"; +} + + +$people = simplexml_load_string($xml); +traverse_xml($people); + +?> +===DONE=== +--EXPECTF-- +<people> + <person>Jane + </person> +</people> +===DONE=== diff --git a/ext/simplexml/tests/027.phpt b/ext/simplexml/tests/027.phpt new file mode 100755 index 0000000000..f32786c7cc --- /dev/null +++ b/ext/simplexml/tests/027.phpt @@ -0,0 +1,74 @@ +--TEST-- +SimpleXML: Adding an elements +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<people></people> +EOF; + +function traverse_xml($xml, $pad = '') +{ + $name = $xml->getName(); + echo "$pad<$name"; + foreach($xml->attributes() as $attr => $value) + { + echo " $attr=\"$value\""; + } + echo ">" . trim($xml) . "\n"; + foreach($xml->children() as $node) + { + traverse_xml($node, $pad.' '); + } + echo $pad."</$name>\n"; +} + + +$people = simplexml_load_string($xml); +traverse_xml($people); +$people->person = 'Joe'; +$people->person['gender'] = 'male'; +traverse_xml($people); +$people->person = 'Jane'; +traverse_xml($people); +$people->person['gender'] = 'female'; +$people->person[1] = 'Joe'; +$people->person[1]['gender'] = 'male'; +traverse_xml($people); +$people->person[3] = 'Minni-me'; +$people->person[2]['gender'] = 'male'; +traverse_xml($people); +$people->person[3]['gender'] = 'error'; + +?> +===DONE=== +--EXPECTF-- +<people> +</people> +<people> + <person gender="male">Joe + </person> +</people> +<people> + <person gender="male">Jane + </person> +</people> +<people> + <person gender="female">Jane + </person> + <person gender="male">Joe + </person> +</people> + +Warning: main(): Cannot add element person number 3 when only 2 such elements exist in %s027.php on line %d +<people> + <person gender="female">Jane + </person> + <person gender="male">Joe + </person> + <person gender="male">Minni-me + </person> +</people> + +Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %s027.php on line %d diff --git a/ext/simplexml/tests/028.phpt b/ext/simplexml/tests/028.phpt new file mode 100755 index 0000000000..753056b9ad --- /dev/null +++ b/ext/simplexml/tests/028.phpt @@ -0,0 +1,42 @@ +--TEST-- +SimpleXML: Adding an elements without text +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<people></people> +EOF; + +function traverse_xml($xml, $pad = '') +{ + $name = $xml->getName(); + echo "$pad<$name"; + foreach($xml->attributes() as $attr => $value) + { + echo " $attr=\"$value\""; + } + echo ">" . trim($xml) . "\n"; + foreach($xml->children() as $node) + { + traverse_xml($node, $pad.' '); + } + echo $pad."</$name>\n"; +} + + +$people = simplexml_load_string($xml); +traverse_xml($people); +$people->person['name'] = 'John'; +traverse_xml($people); + +?> +===DONE=== +--EXPECTF-- +<people> +</people> +<people> + <person name="John"> + </person> +</people> +===DONE=== diff --git a/ext/simplexml/tests/029.phpt b/ext/simplexml/tests/029.phpt new file mode 100755 index 0000000000..86a4f308e3 --- /dev/null +++ b/ext/simplexml/tests/029.phpt @@ -0,0 +1,40 @@ +--TEST-- +SimpleXML: foreach and count +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<people> + <person name="Joe"/> + <person name="John"> + <children> + <person name="Joe"/> + </children> + </person> + <person name="Jane"/> +</people> +EOF; + +$people = simplexml_load_string($xml); + +foreach($people as $person) +{ + var_dump((string)$person['name']); + var_dump(count($people)); + var_dump(count($person)); +} + +?> +===DONE=== +--EXPECTF-- +string(3) "Joe" +int(3) +int(0) +string(4) "John" +int(3) +int(1) +string(4) "Jane" +int(3) +int(0) +===DONE=== diff --git a/ext/simplexml/tests/030.phpt b/ext/simplexml/tests/030.phpt new file mode 100644 index 0000000000..774a5f1459 --- /dev/null +++ b/ext/simplexml/tests/030.phpt @@ -0,0 +1,44 @@ +--TEST-- +SimpleXML: isset and unset by offset +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<root s:att1="b" att1="a" + xmlns:s="urn::test" xmlns:t="urn::test-t"> + <child1>test</child1> + <child1>test 2</child1> + <s:child3 /> +</root> +EOF; + +$sxe = simplexml_load_string($xml); + +echo $sxe->child1[0]."\n"; +echo $sxe->child1[1]."\n\n"; + +var_dump(isset($sxe->child1[1])); +unset($sxe->child1[1]); +var_dump(isset($sxe->child1[1])); +echo "\n"; + +$atts = $sxe->attributes("urn::test"); +var_dump(isset($atts[0])); +unset($atts[0]); +var_dump(isset($atts[0])); +var_dump(isset($atts[TRUE])); + +?> +===DONE=== +--EXPECT-- +test +test 2 + +bool(true) +bool(false) + +bool(true) +bool(false) +bool(false) +===DONE=== diff --git a/ext/simplexml/tests/031.phpt b/ext/simplexml/tests/031.phpt new file mode 100644 index 0000000000..cd2d266ba1 --- /dev/null +++ b/ext/simplexml/tests/031.phpt @@ -0,0 +1,57 @@ +--TEST-- +SimpleXML: addChild and addAttribute +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<root s:att1="b" att1="a" + xmlns:s="urn::test" xmlns:t="urn::test-t"> + <child1>test</child1> + <child1>test 2</child1> + <s:child3 /> +</root> +EOF; + +$sxe = simplexml_load_string($xml); + +/* Add new attribute in a new namespace */ +$sxe->addAttribute('v:att11', 'xxx', 'urn::test-v'); + +/* Try to add attribute again -> display warning as method is for new Attr only */ +$sxe->addAttribute('v:att11', 'xxx', 'urn::test-v'); + +/* Add new attribute w/o namespace */ +$sxe->addAttribute('att2', 'no-ns'); + +$d = $sxe->attributes(); +/* Try to add element to attribute -> display warning and do not add */ +$d->addChild('m:test', 'myval', 'urn::test'); + + +/* Test adding elements in various configurations */ +$sxe->addChild('m:test1', 'myval', 'urn::test'); + +/* New namespace test */ +$n = $sxe->addChild('m:test2', 'myval', 'urn::testnew'); + +$sxe->addChild('test3', 'myval', 'urn::testnew'); +$sxe->addChild('test4', 'myval'); + +/* Does not add prefix here although name is valid (but discouraged) - change behavior? */ +$sxe->addChild('s:test5', 'myval'); + +echo $sxe->asXML(); +?> +===DONE=== +--EXPECTF-- +Warning: SimpleXMLElement::addAttribute(): Attribute already exists in %s031.php on line %d + +Warning: SimpleXMLElement::addChild(): Cannot add element to attributes in %s031.php on line %d +<?xml version="1.0"?> +<root xmlns:s="urn::test" xmlns:t="urn::test-t" xmlns:v="urn::test-v" s:att1="b" att1="a" v:att11="xxx" att2="no-ns"> + <child1>test</child1> + <child1>test 2</child1> + <s:child3/> +<s:test1>myval</s:test1><m:test2 xmlns:m="urn::testnew">myval</m:test2><test3 xmlns="urn::testnew">myval</test3><test4>myval</test4><test5>myval</test5></root> +===DONE=== diff --git a/ext/simplexml/tests/032.phpt b/ext/simplexml/tests/032.phpt new file mode 100755 index 0000000000..5c2225146a --- /dev/null +++ b/ext/simplexml/tests/032.phpt @@ -0,0 +1,45 @@ +--TEST-- +SimpleXML: comparing instances +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php +$xml =<<<EOF +<people> + <person name="Joe"/> + <person name="John"> + <children> + <person name="Joe"/> + </children> + </person> + <person name="Jane"/> +</people> +EOF; + +$xml1 =<<<EOF +<people> + <person name="John"> + <children> + <person name="Joe"/> + </children> + </person> + <person name="Jane"/> +</people> +EOF; + + +$people = simplexml_load_string($xml); +$people1 = simplexml_load_string($xml); +$people2 = simplexml_load_string($xml1); + +var_dump($people1 == $people); +var_dump($people2 == $people); +var_dump($people2 == $people1); + +?> +===DONE=== +--EXPECTF-- +bool(true) +bool(false) +bool(false) +===DONE=== diff --git a/ext/simplexml/tests/033.phpt b/ext/simplexml/tests/033.phpt new file mode 100755 index 0000000000..ba01b21555 --- /dev/null +++ b/ext/simplexml/tests/033.phpt @@ -0,0 +1,137 @@ +--TEST-- +SimpleXML: casting instances +--SKIPIF-- +<?php if (!extension_loaded("simplexml")) print "skip"; ?> +--FILE-- +<?php + +$xml =<<<EOF +<people> +test + <person name="Joe"/> + <person name="John"> + <children> + <person name="Joe"/> + </children> + </person> + <person name="Jane"/> +</people> +EOF; + +$foo = simplexml_load_string( "<foo />" ); +$people = simplexml_load_string($xml); + +var_dump((bool)$foo); +var_dump((bool)$people); +var_dump((int)$foo); +var_dump((int)$people); +var_dump((double)$foo); +var_dump((double)$people); +var_dump((string)$foo); +var_dump((string)$people); +var_dump((array)$foo); +var_dump((array)$people); +var_dump((object)$foo); +var_dump((object)$people); + +?> +===DONE=== +--EXPECTF-- +bool(false) +bool(true) +int(0) +int(0) +float(0) +float(0) +string(0) "" +string(15) " +test + + + +" +array(0) { +} +array(1) { + ["person"]=> + array(3) { + [0]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(3) "Joe" + } + } + [1]=> + object(SimpleXMLElement)#%d (2) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(4) "John" + } + ["children"]=> + object(SimpleXMLElement)#%d (1) { + ["person"]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(3) "Joe" + } + } + } + } + [2]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(4) "Jane" + } + } + } +} +object(SimpleXMLElement)#%d (0) { +} +object(SimpleXMLElement)#%d (1) { + ["person"]=> + array(3) { + [0]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(3) "Joe" + } + } + [1]=> + object(SimpleXMLElement)#%d (2) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(4) "John" + } + ["children"]=> + object(SimpleXMLElement)#%d (1) { + ["person"]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(3) "Joe" + } + } + } + } + [2]=> + object(SimpleXMLElement)#%d (1) { + ["@attributes"]=> + array(1) { + ["name"]=> + string(4) "Jane" + } + } + } +} +===DONE=== diff --git a/ext/simplexml/tests/bug36611.phpt b/ext/simplexml/tests/bug36611.phpt new file mode 100644 index 0000000000..fdfed0d019 --- /dev/null +++ b/ext/simplexml/tests/bug36611.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #36611 (assignment to SimpleXML object attribute changes argument type to string) +--FILE-- +<?php + +$xml_str = <<<EOD +<?xml version="1.0" encoding="ISO-8859-1" ?> +<c_fpobel > + <pos > + <pos/> + </pos> +</c_fpobel> +EOD; + +$xml = simplexml_load_string ($xml_str) ; + +$val = 1; + +var_dump($val); +$obj->pos["act_idx"] = $val; +var_dump($val) ; + +echo "Done\n"; +?> +--EXPECT-- +int(1) +int(1) +Done diff --git a/ext/soap/tests/bugs/bug36226.phpt b/ext/soap/tests/bugs/bug36226.phpt new file mode 100755 index 0000000000..c88d969f29 --- /dev/null +++ b/ext/soap/tests/bugs/bug36226.phpt @@ -0,0 +1,139 @@ +--TEST-- +Bug #36226 SOAP Inconsistent handling when passing potential arrays. +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +<?php +ini_set("soap.wsdl_cache_enabled",0); +$timestamp = "2005-11-08T11:22:07+03:00"; +$wsdl = dirname(__FILE__)."/bug35142.wsdl"; + +function PostEvents($x) { + var_dump($x); + exit(); + return $x; +} + +class TestSoapClient extends SoapClient { + + function __construct($wsdl, $options) { + parent::__construct($wsdl, $options); + $this->server = new SoapServer($wsdl, $options); + $this->server->addFunction('PostEvents'); + } + + function __doRequest($request, $location, $action, $version) { + echo "$request\n"; + $this->server->handle($request); + return $response; + } + +} + +$soapClient = new TestSoapClient($wsdl, + array('trace' => 1, 'exceptions' => 0, + 'classmap' => array('logOnEvent' => 'LogOnEvent', + 'logOffEvent' => 'LogOffEvent', + 'events' => 'IVREvents'), + 'features' => SOAP_SINGLE_ELEMENT_ARRAYS)); + +$logOnEvent = new LogOnEvent(34567, $timestamp); +$logOffEvents[] = new LogOffEvent(34567, $timestamp, "Smoked"); +$logOffEvents[] = new LogOffEvent(34568, $timestamp, "SmokeFree"); +$ivrEvents = new IVREvents("1.0", 101, 12345, 'IVR', $logOnEvent, $logOffEvents); + +$result = $soapClient->PostEvents($ivrEvents); + +class LogOffEvent { + public $audienceMemberId; + public $timestamp; + public $smokeStatus; + public $callInitiator; + + function __construct($audienceMemberId, $timestamp, $smokeStatus) { + $this->audienceMemberId = $audienceMemberId; + $this->timestamp = $timestamp; + $this->smokeStatus = $smokeStatus; + $this->callInitiator = "IVR"; + } +} + +class LogOnEvent { + public $audienceMemberId; + public $timestamp; + + function __construct($audienceMemberId, $timestamp) { + $this->audienceMemberId = $audienceMemberId; + $this->timestamp = $timestamp; + } +} + +class IVREvents { + public $version; + public $activityId; + public $messageId; + public $source; + public $logOnEvent; + public $logOffEvent; + + function __construct($version, $activityId, $messageId, $source, $logOnEvent=NULL, $logOffEvent=NULL) { + $this->version = $version; + $this->activityId = $activityId; + $this->messageId = $messageId; + $this->source = $source; + $this->logOnEvent = $logOnEvent; + $this->logOffEvent = $logOffEvent; + } +} +?> +--EXPECTF-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testurl/Message"><SOAP-ENV:Body><ns1:ivrEvents version="1.0" activityId="101" messageId="12345" source="IVR"><ns1:logOffEvent audienceMemberId="34567" timestamp="2005-11-08T11:22:07+03:00" smokeStatus="Smoked" callInitiator="IVR"/><ns1:logOffEvent audienceMemberId="34568" timestamp="2005-11-08T11:22:07+03:00" smokeStatus="SmokeFree" callInitiator="IVR"/><ns1:logOnEvent audienceMemberId="34567" timestamp="2005-11-08T11:22:07+03:00"/></ns1:ivrEvents></SOAP-ENV:Body></SOAP-ENV:Envelope> + +object(IVREvents)#%d (6) { + ["version"]=> + string(3) "1.0" + ["activityId"]=> + int(101) + ["messageId"]=> + int(12345) + ["source"]=> + string(3) "IVR" + ["logOnEvent"]=> + array(1) { + [0]=> + object(LogOnEvent)#10 (2) { + ["audienceMemberId"]=> + int(34567) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + } + } + ["logOffEvent"]=> + array(2) { + [0]=> + object(LogOffEvent)#%d (4) { + ["audienceMemberId"]=> + int(34567) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + ["smokeStatus"]=> + string(6) "Smoked" + ["callInitiator"]=> + string(3) "IVR" + } + [1]=> + object(LogOffEvent)#%d (4) { + ["audienceMemberId"]=> + int(34568) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + ["smokeStatus"]=> + string(9) "SmokeFree" + ["callInitiator"]=> + string(3) "IVR" + } + } +} diff --git a/ext/soap/tests/bugs/bug36575.phpt b/ext/soap/tests/bugs/bug36575.phpt new file mode 100755 index 0000000000..aad8fcad6a --- /dev/null +++ b/ext/soap/tests/bugs/bug36575.phpt @@ -0,0 +1,52 @@ +--TEST-- +Bug #36575 (Incorrect complex type instantiation with hierarchies) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +<?php +abstract class CT_A1 { + public $var1; +} + +class CT_A2 extends CT_A1 { + public $var2; +} + +class CT_A3 extends CT_A2 { + public $var3; +} + +// returns A2 in WSDL +function test( $a1 ) { + $a3 = new CT_A3(); + $a3->var1 = $a1->var1; + $a3->var2 = "var two"; + $a3->var3 = "var three"; + return $a3; +} + +$classMap = array("A1" => "CT_A1", "A2" => "CT_A2", "A3" => "CT_A3"); + +$client = new SoapClient(dirname(__FILE__)."/bug36575.wsdl", array("trace" => 1, "exceptions" => 0, "classmap" => $classMap)); +$a2 = new CT_A2(); +$a2->var1 = "one"; +$a2->var2 = "two"; +$client->test($a2); + +$soapRequest = $client->__getLastRequest(); + +echo $soapRequest; + +$server = new SoapServer(dirname(__FILE__)."/bug36575.wsdl", array("classmap" => $classMap)); +$server->addFunction("test"); +$server->handle($soapRequest); +echo "ok\n"; +?> +--EXPECT-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:test.soap#" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:test.soap.types#" 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:test><a1 xsi:type="ns2:A2"><var1 xsi:type="xsd:string">one</var1><var2 xsi:type="xsd:string">two</var2></a1></ns1:test></SOAP-ENV:Body></SOAP-ENV:Envelope> +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:test.soap#" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:test.soap.types#" 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:testResponse><result xsi:type="ns2:A3"><var1 xsi:type="xsd:string">one</var1><var2 xsi:type="xsd:string">var two</var2><var3 xsi:type="xsd:string">var three</var3></result></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> +ok diff --git a/ext/soap/tests/bugs/bug36575.wsdl b/ext/soap/tests/bugs/bug36575.wsdl new file mode 100755 index 0000000000..0f1899bcd5 --- /dev/null +++ b/ext/soap/tests/bugs/bug36575.wsdl @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?>
+<definitions name="shoppingcart"
+ xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:tns="urn:test.soap#" targetNamespace="urn:test.soap#"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:types="urn:test.soap.types#">
+ <!-- all datatypes will be imported to namespace types: -->
+ <types>
+ <xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:tns="urn:test.soap.types#"
+ targetNamespace="urn:test.soap.types#">
+
+ <xs:complexType name="A1">
+ <xs:all>
+ <xs:element name="var1" type="xs:string" nillable="true"/>
+ </xs:all>
+ </xs:complexType>
+
+ <xs:complexType name="A2">
+ <xs:complexContent>
+ <xs:extension base="tns:A1">
+ <xs:all>
+ <xs:element name="var2" type="xs:string" nillable="true"/>
+ </xs:all>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="A3">
+ <xs:complexContent>
+ <xs:extension base="tns:A2">
+ <xs:all>
+ <xs:element name="var3" type="xs:string" nillable="true"/>
+ </xs:all>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:schema>
+ </types>
+
+ <message name="test-request">
+ <part name="a1" type="types:A1"/>
+ </message>
+ <message name="test-response">
+ <part name="result" type="types:A2"/>
+ </message>
+
+ <portType name="catalog-porttype">
+ <operation name="test" parameterOrder="a1">
+ <input name="test-request" message="tns:test-request"/>
+ <output name="test-response" message="tns:test-response"/>
+ </operation>
+ </portType>
+
+ <!-- @type doesn't like tns: -->
+ <binding name="catalog-binding" type="tns:catalog-porttype">
+ <soap:binding style="rpc"
+ transport="http://schemas.xmlsoap.org/soap/http"/>
+
+ <operation name="test">
+ <soap:operation soapAction="urn:test.soap#test"/>
+ <input>
+ <soap:body use="encoded" namespace="urn:test.soap#"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </input>
+ <output>
+ <soap:body use="encoded" namespace="urn:test.soap#"
+ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </output>
+ </operation>
+ </binding>
+
+ <service name="catalog">
+ <!-- @binding doesn't like to be tns: -->
+ <port name="catalog-port" binding="tns:catalog-binding">
+ <soap:address location="xxxxxxxx"/>
+ </port>
+ </service>
+
+</definitions>
diff --git a/ext/soap/tests/bugs/bug36614.phpt b/ext/soap/tests/bugs/bug36614.phpt new file mode 100755 index 0000000000..ba6734812d --- /dev/null +++ b/ext/soap/tests/bugs/bug36614.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #36614 (Segfault when using Soap) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +<?php +$lo_soap = new SoapClient(dirname(__FILE__)."/bug36614.wsdl"); +echo "ok\n"; +?> +--EXPECT-- +ok diff --git a/ext/soap/tests/bugs/bug36614.wsdl b/ext/soap/tests/bugs/bug36614.wsdl new file mode 100755 index 0000000000..ecf1b1b2fe --- /dev/null +++ b/ext/soap/tests/bugs/bug36614.wsdl @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<definitions name="SonicMobile Web-Services" + targetNamespace="http://soap.sonicmobile.com/sonicmobile.wsdl" + xmlns="http://schemas.xmlsoap.org/wsdl/" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:sonic="http://soap.sonicmobile.com/sonicmobile.wsdl" + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <types> + <xsd:schema xmlns="http://www.w3.org/2000/10/XMLSchema"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> + <complexType name="TransportCount"> + <all> + <element name="transport" type="string" /> + <element name="count" type="integer" /> + <element name="rate" type="integer" /> + <element name="last_message" type="integer" /> + </all> + </complexType> + <complexType name="ArrayOfTransportCount"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" arrayType="TransportCount[]" /> + </restriction> + </complexContent> + </complexType> + </xsd:schema> + </types> + + <message name="userSendMessageRequest"> + <part name="sourceUser" type="xsd:int"/> + <part name="password" type="xsd:string"/> + <part name="destinationUser" type="xsd:int"/> + <part name="content" type="xsd:string"/> + <part name="sendRepliesTo" type="xsd:string"/> + <part name="reference" type="xsd:string"/> + </message> + + <message name="sendMessageRequest"> + <part name="application" type="xsd:string"/> + <part name="password" type="xsd:string"/> + <part name="destination" type="xsd:string"/> + <part name="content" type="xsd:string"/> + <part name="reference" type="xsd:string"/> + <part name="requestSource" type="xsd:string"/> + <part name="customer" type="xsd:string"/> + <part name="class" type="xsd:string"/> + </message> + + <message name="MessageResponse"> + <part name="messageid" type="xsd:int"/> + <part name="response" type="xsd:string"/> + </message> + + <message name="messageCountRequest"> + <part name="password" type="xsd:string"/> + </message> + + <message name="messageCountResponse"> + <part name="transports" type="tns:ArrayOfTransportCount"/> + </message> + + <message name="serverStatusRequest"> + <part name="password" type="xsd:string"/> + </message> + <message name="serverStatusResponse"> + <part name="status_string" type="xsd:string"/> + </message> + + <message name="flushGatewayRequest"> + <part name="password" type="xsd:string"/> + </message> + <message name="flushGatewayResponse"> + <part name="status_string" type="xsd:string"/> + </message> + + <portType name="SonicMobilePortType"> + <operation name="userSendMessage"> + <input message="sonic:userSendMessageRequest"/> + <output message="sonic:MessageResponse"/> + </operation> + + <operation name="sendMessage"> + <input message="sonic:sendMessageRequest"/> + <output message="sonic:MessageResponse"/> + </operation> + + <operation name="messageCount"> + <input message="sonic:messageCountRequest"/> + <output message="sonic:messageCountResponse"/> + </operation> + + <operation name="serverStatus"> + <input message="sonic:serverStatusRequest"/> + <output message="sonic:serverStatusResponse"/> + </operation> + + <operation name="flushGateway"> + <input message="sonic:flushGatewayRequest"/> + <output message="sonic:flushGatewayResponse"/> + </operation> + </portType> + + <binding name="SonicMobileBinding" type="sonic:SonicMobilePortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + + <operation name="userSendMessage"> + <soap:operation soapAction="http://soap.sonicmobile.com/SonicMobile/SOAP#userSendMessage"/> + + <input> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </input> + + <output> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </output> + </operation> + + <operation name="sendMessage"> + <soap:operation soapAction="http://soap.sonicmobile.com/SonicMobile/SOAP#sendMessage"/> + + <input> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </input> + + <output> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </output> + </operation> + + <operation name="messageCount"> + <soap:operation soapAction="http://soap.sonicmobile.com/SonicMobile/SOAP#messageCount"/> + + <input> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </input> + + <output> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </output> + </operation> + + <operation name="serverStatus"> + <soap:operation soapAction="http://soap.sonicmobile.com/SonicMobile/SOAP#serverStatus"/> + + <input> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </input> + + <output> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </output> + </operation> + + <operation name="flushGateway"> + <soap:operation soapAction="http://soap.sonicmobile.com/SonicMobile/SOAP#flushGateway"/> + + <input> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </input> + <output> + <soap:body + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + namespace="http://soap.sonicmobile.com/SonicMobile/SOAP" + use="encoded" /> + </output> + </operation> + + </binding> + + <service name="SonicMobile"> + <port name="SonicMobilePort" binding="sonic:SonicMobileBinding"> + <soap:address location="http://soap.sonicmobile.com/"/> + </port> + </service> + +</definitions> diff --git a/ext/soap/tests/bugs/bug36629.phpt b/ext/soap/tests/bugs/bug36629.phpt new file mode 100755 index 0000000000..08b74a5fca --- /dev/null +++ b/ext/soap/tests/bugs/bug36629.phpt @@ -0,0 +1,53 @@ +--TEST-- +Bug #36629 (SoapServer::handle() exits on SOAP faults) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +function test1() { + throw new SoapFault("Server", "test1"); +} +function test2() { + return new SoapFault("Server", "test2"); +} + +$server = new soapserver(null,array('uri'=>"http://testuri.org")); +$server->addfunction(array("test1","test2")); + +$HTTP_RAW_POST_DATA = <<<EOF +<?xml version="1.0" encoding="ISO-8859-1"?> +<SOAP-ENV:Envelope + SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:si="http://soapinterop.org/xsd"> + <SOAP-ENV:Body> + <ns1:test1 xmlns:ns1="http://testuri.org" /> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> +EOF; +$server->handle(); + +$HTTP_RAW_POST_DATA = <<<EOF +<?xml version="1.0" encoding="ISO-8859-1"?> +<SOAP-ENV:Envelope + SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:si="http://soapinterop.org/xsd"> + <SOAP-ENV:Body> + <ns1:test2 xmlns:ns1="http://testuri.org" /> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> +EOF; +$server->handle(); +echo "ok\n"; +?> +--EXPECT-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>test1</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope> +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>test2</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope> +ok diff --git a/ext/soap/tests/classmap003.phpt b/ext/soap/tests/classmap003.phpt new file mode 100755 index 0000000000..ac87a1682e --- /dev/null +++ b/ext/soap/tests/classmap003.phpt @@ -0,0 +1,54 @@ +--TEST-- +SOAP Classmap 3: encoding of inherited objects +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +ini_set("soap.wsdl_cache_enabled",0); + +class A { + public $x; + function __construct($a){ + $this->x = $a; + } +} + +class B extends A { + public $y; + function __construct($a){ + parent::__construct($a); + $this->y = $a + 1; + } +} + +function f(){ + return new B(5); +} + +class LocalSoapClient extends SoapClient { + + function __construct($wsdl, $options) { + parent::__construct($wsdl, $options); + $this->server = new SoapServer($wsdl, $options); + $this->server->addFunction("f"); + } + + function __doRequest($request, $location, $action, $version) { + ob_start(); + $this->server->handle($request); + $response = ob_get_contents(); + ob_end_clean(); + return $response; + } +} + +$client = new LocalSoapClient(dirname(__FILE__)."/classmap003.wsdl", + array('classmap'=>array('A'=>'A','B'=>'B'))); +print_r($client->f()); +?> +--EXPECT-- +B Object +( + [y] => 6 + [x] => 5 +) diff --git a/ext/soap/tests/classmap003.wsdl b/ext/soap/tests/classmap003.wsdl new file mode 100755 index 0000000000..494c41864e --- /dev/null +++ b/ext/soap/tests/classmap003.wsdl @@ -0,0 +1,51 @@ +<?xml version='1.0' encoding='UTF-8'?>
+
+<!-- WSDL file generated by Zend Studio. -->
+
+<definitions name="ab" targetNamespace="urn:ab" xmlns:typens="urn:ab" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/">
+ <types>
+ <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ab">
+ <xsd:complexType name="A">
+ <xsd:sequence>
+ <xsd:element name="x" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="B">
+ <xsd:complexContent>
+ <xsd:extension base="typens:A">
+ <xsd:sequence>
+ <xsd:element name="y" type="xsd:anyType"/>
+ </xsd:sequence>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:schema>
+ </types>
+ <message name="f"/>
+ <message name="fResponse">
+ <part name="fReturn" type="typens:A"/>
+ </message>
+ <portType name="abServerPortType">
+ <operation name="f">
+ <input message="typens:f"/>
+ <output message="typens:fResponse"/>
+ </operation>
+ </portType>
+ <binding name="abServerBinding" type="typens:abServerPortType">
+ <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="f">
+ <soap:operation soapAction="urn:abServerAction"/>
+ <input>
+ <soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </input>
+ <output>
+ <soap:body namespace="urn:ab" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
+ </output>
+ </operation>
+ </binding>
+ <service name="abService">
+ <port name="abServerPort" binding="typens:abServerBinding">
+ <soap:address location="http://localhost/abServer.php"/>
+ </port>
+ </service>
+</definitions>
diff --git a/ext/soap/tests/server023.phpt b/ext/soap/tests/server023.phpt new file mode 100755 index 0000000000..c227204d33 --- /dev/null +++ b/ext/soap/tests/server023.phpt @@ -0,0 +1,37 @@ +--TEST-- +SOAP Server 23: Send SOAP headers those were not received +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +function test() { + global $server; + $server->addSoapHeader(new SoapHeader("http://testuri.org", "Test1", "Hello Header!")); + $server->addSoapHeader(new SoapHeader("http://testuri.org", "Test2", "Hello Header!")); + return "Hello Body!"; +} + +$server = new soapserver(null,array('uri'=>"http://testuri.org")); +$server->addfunction("test"); + +$HTTP_RAW_POST_DATA = <<<EOF +<?xml version="1.0" encoding="ISO-8859-1"?> +<SOAP-ENV:Envelope + SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:si="http://soapinterop.org/xsd"> + <SOAP-ENV:Body> + <ns1:test xmlns:ns1="http://testuri.org"/> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> +EOF; + +$server->handle(); +echo "ok\n"; +?> +--EXPECT-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testuri.org" 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:Header><ns1:Test1>Hello Header!</ns1:Test1><ns1:Test2>Hello Header!</ns1:Test2></SOAP-ENV:Header><SOAP-ENV:Body><ns1:testResponse><return xsi:type="xsd:string">Hello Body!</return></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> +ok diff --git a/ext/soap/tests/server024.phpt b/ext/soap/tests/server024.phpt new file mode 100755 index 0000000000..0ddd9cec39 --- /dev/null +++ b/ext/soap/tests/server024.phpt @@ -0,0 +1,49 @@ +--TEST-- +SOAP Server 24: Send SOAP headers those were not received +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +class TestHeader1 extends SoapHeader { + function __construct($data) { + parent::__construct("http://testuri.org", "Test1", $data); + } +} + +class TestHeader2 extends SoapHeader { + function __construct($data) { + parent::__construct("http://testuri.org", "Test2", $data); + } +} + +function test() { + global $server; + $server->addSoapHeader(new TestHeader1("Hello Header!")); + $server->addSoapHeader(new TestHeader2("Hello Header!")); + return "Hello Body!"; +} + +$server = new soapserver(null,array('uri'=>"http://testuri.org")); +$server->addfunction("test"); + +$HTTP_RAW_POST_DATA = <<<EOF +<?xml version="1.0" encoding="ISO-8859-1"?> +<SOAP-ENV:Envelope + SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:si="http://soapinterop.org/xsd"> + <SOAP-ENV:Body> + <ns1:test xmlns:ns1="http://testuri.org"/> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> +EOF; + +$server->handle(); +echo "ok\n"; +?> +--EXPECT-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testuri.org" 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:Header><ns1:Test1>Hello Header!</ns1:Test1><ns1:Test2>Hello Header!</ns1:Test2></SOAP-ENV:Header><SOAP-ENV:Body><ns1:testResponse><return xsi:type="xsd:string">Hello Body!</return></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> +ok diff --git a/ext/soap/tests/server025.phpt b/ext/soap/tests/server025.phpt new file mode 100755 index 0000000000..0a98b4108a --- /dev/null +++ b/ext/soap/tests/server025.phpt @@ -0,0 +1,46 @@ +--TEST-- +SOAP Server 25: One-way SOAP headers encoding using WSDL +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +class TestHeader1 extends SoapHeader { + function __construct($data) { + parent::__construct("http://testuri.org", "Test1", $data); + } +} + +class TestHeader2 extends SoapHeader { + function __construct($data) { + parent::__construct("http://testuri.org", "Test2", $data); + } +} + +function test() { + global $server; + $server->addSoapHeader(new TestHeader1("Hello Header!")); + $server->addSoapHeader(new TestHeader2("Hello Header!")); + return "Hello Body!"; +} + +$server = new soapserver(dirname(__FILE__)."/server025.wsdl"); +$server->addfunction("test"); + +$HTTP_RAW_POST_DATA = <<<EOF +<?xml version="1.0" encoding="ISO-8859-1"?> +<SOAP-ENV:Envelope + SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> + <SOAP-ENV:Body> + <ns1:test xmlns:ns1="http://testuri.org"/> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> +EOF; + +$server->handle(); +echo "ok\n"; +?> +--EXPECT-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://testuri.org"><SOAP-ENV:Header><ns1:Test1 xsi:type="xsd:string">Hello Header!</ns1:Test1><ns1:Test2 xsi:type="xsd:string">Hello Header!</ns1:Test2></SOAP-ENV:Header><SOAP-ENV:Body><ns1:testResponse><result>Hello Body!</result></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> +ok diff --git a/ext/soap/tests/server025.wsdl b/ext/soap/tests/server025.wsdl new file mode 100755 index 0000000000..2870f4e70d --- /dev/null +++ b/ext/soap/tests/server025.wsdl @@ -0,0 +1,55 @@ +<?xml version="1.0" ?> +<definitions + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + 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/" + xmlns:si="http://soapinterop.org/xsd" + xmlns:tns="http://linuxsrv.home/~dmitry/soap/test.wsdl" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns="http://schemas.xmlsoap.org/wsdl/" + targetNamespace="http://testuri.org"> + + <message name="TestHeader1"> + <part name="Test1" type="xsd:string" /> + </message> + <message name="TestHeader2"> + <part name="Test2" type="xsd:string" /> + </message> + + <message name="TestRequest"> + </message> + <message name="TestResponse"> + <part name="result" type="xsd:string" /> + </message> + + <portType name="TestServicePortType"> + <operation name="test"> + <input message="tns:TestRequest" /> + <output message="tns:TestResponse" /> + </operation> + </portType> + + <binding name="TestServiceBinding" type="tns:TestServicePortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="test"> + <soap:operation soapAction="Test" style="rpc" /> + <input> + <soap:body namespace="http://testuri.org" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="http://testuri.org" use="literal" /> + <soap:header namespace="http://testuri.org" message="tns:TestHeader1" part="Test1" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + <soap:header namespace="http://testuri.org" message="tns:TestHeader2" part="Test2" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + + <service name="TestService"> + <port name="TestServicePort" binding="tns:TestServiceBinding"> + <soap:address location="http://linuxsrv.home/~dmitry/soap/soap_server.php" /> + </port> + </service> + +</definitions> diff --git a/ext/spl/tests/array_019.phpt b/ext/spl/tests/array_019.phpt new file mode 100755 index 0000000000..1416d8407d --- /dev/null +++ b/ext/spl/tests/array_019.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: ArrayIterator and foreach by reference +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$ar = new ArrayObject(array(1)); foreach($ar as &$v) var_dump($v); +$ar = new ArrayIterator(array(2)); foreach($ar as &$v) var_dump($v); +$ar = new RecursiveArrayIterator(array(3)); foreach($ar as &$v) var_dump($v); + +class ArrayIteratorEx extends ArrayIterator +{ + function current() + { + return ArrayIterator::current(); + } +} + +$ar = new ArrayIteratorEx(array(4)); foreach($ar as $v) var_dump($v); +$ar = new ArrayIteratorEx(array(5)); foreach($ar as &$v) var_dump($v); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +int(5) +===DONE=== diff --git a/ext/spl/tests/array_020.phpt b/ext/spl/tests/array_020.phpt new file mode 100755 index 0000000000..cdeb4a216c --- /dev/null +++ b/ext/spl/tests/array_020.phpt @@ -0,0 +1,66 @@ +--TEST-- +SPL: ArrayIterator overloading +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + ArrayIterator::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return ArrayIterator::valid(); + } + + function key() + { + echo __METHOD__ . "\n"; + return ArrayIterator::key(); + } + + function current() + { + echo __METHOD__ . "\n"; + return ArrayIterator::current(); + } + + function next() + { + echo __METHOD__ . "\n"; + return ArrayIterator::next(); + } +} + +$ar = new ArrayIteratorEx(array(1,2)); +foreach($ar as $k => $v) +{ + var_dump($k); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(0) +int(1) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(1) +int(2) +ArrayIteratorEx::next +ArrayIteratorEx::valid +===DONE=== diff --git a/ext/spl/tests/array_021.phpt b/ext/spl/tests/array_021.phpt new file mode 100755 index 0000000000..f2ae0c87e5 --- /dev/null +++ b/ext/spl/tests/array_021.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: ArrayObject::seek() and exceptions +--FILE-- +<?php + +class foo extends ArrayObject +{ + public function seek($key) + { + echo __METHOD__ . "($key)\n"; + throw new Exception("hi"); + } +} + +$test = new foo(array(1,2,3)); + +try +{ + $test->seek('bar'); +} +catch (Exception $e) +{ + echo "got exception\n"; +} + +?> +===DONE=== +--EXPECT-- +foo::seek(bar) +got exception +===DONE=== diff --git a/ext/spl/tests/array_022.phpt b/ext/spl/tests/array_022.phpt new file mode 100755 index 0000000000..d1eafd677c --- /dev/null +++ b/ext/spl/tests/array_022.phpt @@ -0,0 +1,94 @@ +--TEST-- +SPL: ArrayObject/Iterator and reference to self +--FILE-- +==ArrayObject=== +<?php + +class MyArrayObject extends ArrayObject +{ + public function __construct() + { + parent::__construct($this); + $this['bar'] = 'baz'; + } +} + +$a = new MyArrayObject; + +$b = clone $a; +$b['baz'] = 'Foo'; + +var_dump($a); +var_dump($b); + +?> +==ArrayIterator=== +<?php + +class MyArrayIterator extends ArrayIterator +{ + public function __construct() + { + parent::__construct($this); + $this['bar'] = 'baz'; + } +} + +$a = new MyArrayIterator; + +$b = clone $a; +$b['baz'] = 'Foo'; + +var_dump($a); +var_dump($b); + +?> +===DONE=== +--EXPECTF-- +==ArrayObject=== +object(MyArrayObject)#%d (1) { + ["bar"]=> + string(3) "baz" +} +object(MyArrayObject)#%d (2) { + ["bar"]=> + string(3) "baz" + ["baz"]=> + string(3) "Foo" +} +==ArrayIterator=== +object(MyArrayIterator)#%d (1) { + ["bar"]=> + string(3) "baz" +} +object(MyArrayIterator)#%d (2) { + ["bar"]=> + string(3) "baz" + ["baz"]=> + string(3) "Foo" +} +===DONE=== +--UEXPECTF-- +==ArrayObject=== +object(MyArrayObject)#%d (1) { + [u"bar"]=> + unicode(3) "baz" +} +object(MyArrayObject)#%d (2) { + [u"bar"]=> + unicode(3) "baz" + [u"baz"]=> + unicode(3) "Foo" +} +==ArrayIterator=== +object(MyArrayIterator)#%d (1) { + [u"bar"]=> + unicode(3) "baz" +} +object(MyArrayIterator)#%d (2) { + [u"bar"]=> + unicode(3) "baz" + [u"baz"]=> + unicode(3) "Foo" +} +===DONE=== diff --git a/ext/spl/tests/bug36258.phpt b/ext/spl/tests/bug36258.phpt new file mode 100644 index 0000000000..297c7f5978 --- /dev/null +++ b/ext/spl/tests/bug36258.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #36258 (SplFileObject::getPath() may lead to segfault) +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$diriter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('.') ); + +foreach ($diriter as $key => $file) { + var_dump($file->getFilename()); + var_dump($file->getPath()); + break; +} + +echo "Done\n"; +?> +--EXPECTF-- +string(%d) "%s" +string(%d) "%s" +Done diff --git a/ext/spl/tests/bug36287.phpt b/ext/spl/tests/bug36287.phpt new file mode 100755 index 0000000000..29ae0e2c9d --- /dev/null +++ b/ext/spl/tests/bug36287.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #36287 +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."), true); + +$idx = 0; +foreach($it as $file) +{ + echo "First\n"; + if("." != $file && ".." != $file) + { + var_Dump($file->getFilename()); + } + echo "Second\n"; + if($file != "." && $file != "..") + { + var_dump($file->getFilename()); + } + if (++$idx > 1) + { + break; + } +} + +?> +===DONE=== +--EXPECTF-- +First +string(%d) "%s" +Second +string(%d) "%s" +First +string(%d) "%s" +Second +string(%d) "%s" +===DONE=== diff --git a/ext/spl/tests/bug36825.phpt b/ext/spl/tests/bug36825.phpt new file mode 100644 index 0000000000..503ec43a43 --- /dev/null +++ b/ext/spl/tests/bug36825.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #36825 (Exceptions thrown in ArrayObject::offsetGet cause segfault) +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class foo extends ArrayObject +{ + public function offsetGet($key) + { + echo __METHOD__ . "($key)\n"; + throw new Exception("hi"); + } +} + +$test = new foo(); + +try +{ + var_dump($test['bar']); +} +catch (Exception $e) +{ + echo "got exception\n"; +} + +?> +===DONE=== +--EXPECT-- +foo::offsetGet(bar) +got exception +===DONE=== diff --git a/ext/spl/tests/bug36941.phpt b/ext/spl/tests/bug36941.phpt new file mode 100755 index 0000000000..528ba4a462 --- /dev/null +++ b/ext/spl/tests/bug36941.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #36941 (ArrayIterator does not clone itself) +--FILE-- +===ArrayObject=== +<?php +$a = new ArrayObject(); +$a[] = 1; + +$b = clone $a; + +var_dump($a[0], $b[0]); +$b[0] = $b[0] + 1; +var_dump($a[0], $b[0]); +$b[0] = 3; +var_dump($a[0], $b[0]); +?> +===ArrayIterator=== +<?php +$a = new ArrayIterator(); +$a[] = 1; + +$b = clone $a; + +var_dump($a[0], $b[0]); +$b[0] = $b[0] + 1; +var_dump($a[0], $b[0]); +$b[0] = 3; +var_dump($a[0], $b[0]); +?> +===DONE=== +--EXPECT-- +===ArrayObject=== +int(1) +int(1) +int(1) +int(2) +int(1) +int(3) +===ArrayIterator=== +int(1) +int(1) +int(2) +int(2) +int(3) +int(3) +===DONE=== diff --git a/ext/spl/tests/iterator_030.phpt b/ext/spl/tests/iterator_030.phpt new file mode 100755 index 0000000000..6ed8035ac1 --- /dev/null +++ b/ext/spl/tests/iterator_030.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: EmptyIterator access +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new EmptyIterator; + +var_dump($it->valid()); +$it->rewind(); +var_dump($it->valid()); +$it->next(); +var_dump($it->valid()); + +try +{ + var_dump($it->key()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +try +{ + var_dump($it->current()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +Accessing the key of an EmptyIterator +Accessing the value of an EmptyIterator +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt new file mode 100755 index 0000000000..00afa61850 --- /dev/null +++ b/ext/spl/tests/iterator_031.phpt @@ -0,0 +1,118 @@ +--TEST-- +SPL: AppendIterator::append() rewinds when neccessary +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } +} + +$it = new MyArrayIterator(array(1,2)); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; +} + +class MyAppendIterator extends AppendIterator +{ + function __construct() + { + echo __METHOD__ . "\n"; + } + + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + + function append(Iterator $what) + { + echo __METHOD__ . "\n"; + parent::append($what); + } + + function parent__construct() + { + parent::__construct(); + } +} + +$ap = new MyAppendIterator; + +try +{ + $ap->append($it); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->parent__construct(); + +try +{ + $ap->parent__construct($it); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->append($it); +$ap->append($it); +$ap->append($it); + +foreach($ap as $k=>$v) +{ + echo "$k=>$v\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +MyArrayIterator::rewind +0=>1 +1=>2 +MyAppendIterator::__construct +MyAppendIterator::append +Classes derived from AppendIterator must call AppendIterator::__construct() +AppendIterator::getIterator() must be called exactly once per instance +MyAppendIterator::append +MyArrayIterator::rewind +MyAppendIterator::append +MyAppendIterator::append +MyAppendIterator::rewind +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyAppendIterator::valid +===DONE=== diff --git a/ext/spl/tests/iterator_032.phpt b/ext/spl/tests/iterator_032.phpt new file mode 100755 index 0000000000..86695d4af8 --- /dev/null +++ b/ext/spl/tests/iterator_032.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: LimitIterator::getPosition() +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new LimitIterator(new ArrayIterator(array(1,2,3,4)), 1, 2); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; + var_dump($it->getPosition()); +} + +try +{ + $it->seek(0); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->seek(2); +var_dump($it->current()); + +try +{ + $it->seek(3); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->next(); +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1=>2 +int(1) +2=>3 +int(2) +Cannot seek to 0 which is below the offset 1 +int(3) +Cannot seek to 3 which is behind offest 1 plus count 2 +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_033.phpt b/ext/spl/tests/iterator_033.phpt new file mode 100755 index 0000000000..c1880cb2fb --- /dev/null +++ b/ext/spl/tests/iterator_033.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: ParentIterator +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new ParentIterator(new RecursiveArrayIterator(array(1,array(21,22, array(231)),3))); + +foreach(new RecursiveIteratorIterator($it) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +echo "==SECOND==\n"; + +foreach(new RecursiveIteratorIterator($it, 1) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +==SECOND== +int(1) +array(3) { + [0]=> + int(21) + [1]=> + int(22) + [2]=> + array(1) { + [0]=> + int(231) + } +} +int(2) +array(1) { + [0]=> + int(231) +} +===DONE=== diff --git a/ext/spl/tests/iterator_034.phpt b/ext/spl/tests/iterator_034.phpt new file mode 100755 index 0000000000..b81c6d970e --- /dev/null +++ b/ext/spl/tests/iterator_034.phpt @@ -0,0 +1,190 @@ +--TEST-- +SPL: RecursiveIteratorIterator and break deep +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . "() = false\n"; + return false; + } + else + { + return true; + } + } + + function getChildren() + { + echo __METHOD__ . "()\n"; + return parent::getChildren(); + } + + function rewind() + { + echo __METHOD__ . "()\n"; + parent::rewind(); + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it); + } + + function rewind() + { + echo __METHOD__ . "() - BEGIN\n"; + parent::rewind(); + echo __METHOD__ . "() - DONE\n"; + } + + function valid() + { + echo __METHOD__ . "()\n"; + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "()\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "()\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "()\n"; + parent::next(); + } + + function callHasChildren() + { + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + return $res; + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::beginChildren(); + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::endChildren(); + } +} + +$p = 0; +$it = new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2); +foreach($it as $k=>$v) +{ + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; + if ($p++ == 5) + { + echo "===BREAK===\n"; + break; + } +} + +echo "===FOREND===\n"; + +$it->rewind(); + +echo "===CHECK===\n"; + +var_dump($it->valid()); +var_dump($it->current() == "a"); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind() - BEGIN +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>a +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>ba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bbb +RecursiveArrayIteratorIterator::next() +MyRecursiveArrayIterator::valid() = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bcaa +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bcba +===BREAK=== +===FOREND=== +RecursiveArrayIteratorIterator::rewind() - BEGIN +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::endChildren(0) +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +===CHECK=== +RecursiveArrayIteratorIterator::valid() +bool(true) +RecursiveArrayIteratorIterator::current() +bool(true) +===DONE=== diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt new file mode 100644 index 0000000000..eebc7f22a4 --- /dev/null +++ b/ext/spl/tests/iterator_035.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: ArrayIterator and values assigned by reference +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$tmp = 1; + +$a = new ArrayIterator(); +$a[] = $tmp; +$a[] = &$tmp; + +echo "Done\n"; +?> +--EXPECTF-- +Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %s on line %d diff --git a/ext/spl/tests/spl_autoload_008.phpt b/ext/spl/tests/spl_autoload_008.phpt new file mode 100755 index 0000000000..bafd26d877 --- /dev/null +++ b/ext/spl/tests/spl_autoload_008.phpt @@ -0,0 +1,131 @@ +--TEST-- +SPL: spl_autoload() with exceptions +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--INI-- +include_path=. +--FILE-- +<?php + +function MyAutoLoad($className) +{ + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); +} + +class MyAutoLoader +{ + static function autoLoad($className) + { + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); + } + + function dynaLoad($className) + { + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); + } +} + +$obj = new MyAutoLoader; + +$funcs = array( + 'MyAutoLoad', + 'MyAutoLoader::autoLoad', + 'MyAutoLoader::dynaLoad', + array('MyAutoLoader', 'autoLoad'), + array('MyAutoLoader', 'dynaLoad'), + array($obj, 'autoLoad'), + array($obj, 'dynaLoad'), +); + +foreach($funcs as $idx => $func) +{ + echo "====$idx====\n"; + + try + { + var_dump($func); + spl_autoload_register($func); + if (count(spl_autoload_functions())) + { + echo "registered\n"; + + var_dump(class_exists("NoExistingTestClass", true)); + } + } + catch (Exception $e) + { + echo get_class($e) . ": " . $e->getMessage() . "\n"; + } + + spl_autoload_unregister($func); + var_dump(count(spl_autoload_functions())); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +====0==== +string(10) "MyAutoLoad" +registered +MyAutoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====1==== +string(22) "MyAutoLoader::autoLoad" +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====2==== +string(22) "MyAutoLoader::dynaLoad" +LogicException: Function 'MyAutoLoader::dynaLoad' not callable +int(0) +====3==== +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "autoLoad" +} +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====4==== +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "dynaLoad" +} +LogicException: Passed array specifies a non static method but no object +int(0) +====5==== +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "autoLoad" +} +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====6==== +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "dynaLoad" +} +registered +MyAutoLoader::dynaLoad(NoExistingTestClass) +Exception: Bla +int(0) +===DONE=== diff --git a/ext/spl/tests/sxe_005.phpt b/ext/spl/tests/sxe_005.phpt new file mode 100755 index 0000000000..2efd0a6bee --- /dev/null +++ b/ext/spl/tests/sxe_005.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: SimpleXMLIterator and getChildren() +--SKIPIF-- +<?php +if (!extension_loaded("spl")) print "skip"; +if (!extension_loaded('simplexml')) print 'skip'; +if (!extension_loaded("libxml")) print "skip LibXML not present"; +if (!class_exists('RecursiveIteratorIterator')) print 'skip RecursiveIteratorIterator not available'; +?> +--FILE-- +<?php + +$xml =<<<EOF +<?xml version='1.0'?> +<sxe> + <elem1/> + <elem2/> + <elem2/> +</sxe> +EOF; + +class SXETest extends SimpleXMLIterator +{ + function count() + { + echo __METHOD__ . "\n"; + return parent::count(); + } +} + +$sxe = new SXETest($xml); + +var_dump(count($sxe)); +var_dump(count($sxe->elem1)); +var_dump(count($sxe->elem2)); + +?> +===DONE=== +--EXPECT-- +SXETest::count +int(3) +SXETest::count +int(1) +SXETest::count +int(2) +===DONE=== diff --git a/ext/standard/tests/file/bug37158.phpt b/ext/standard/tests/file/bug37158.phpt new file mode 100644 index 0000000000..48df46cc63 --- /dev/null +++ b/ext/standard/tests/file/bug37158.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #37158 (if userspace stream is present, fread() reads in 8192 max, otherwise it works) +--FILE-- +<?php + +class VariableStream { + + function stream_open($path, $mode, $options, &$opened_path) + { + return true; + } +} + +stream_wrapper_register("var", "VariableStream"); + +error_reporting(E_ALL | E_STRICT); +$file = dirname(__FILE__) . '/footest.txt'; +$x = str_repeat(1, 8192); +$fp = fopen($file, 'w'); +for ($i = 0; $i < 5; $i++) { + fwrite($fp, $x); +} +fclose($fp); + +$fp = fopen($file, 'r'); +$outsidecontents = fread($fp, 20000); +fclose($fp); +var_dump('size of contents 1 = ' . strlen($outsidecontents)); +$outsidecontents = file_get_contents($file); +var_dump('size of contents 2 = ' . strlen($outsidecontents)); + +unlink($file); + +echo "Done\n"; +?> +--EXPECT-- +string(26) "size of contents 1 = 20000" +string(26) "size of contents 2 = 40960" +Done diff --git a/ext/standard/tests/filters/read.phpt b/ext/standard/tests/filters/read.phpt new file mode 100644 index 0000000000..a2372cf8f9 --- /dev/null +++ b/ext/standard/tests/filters/read.phpt @@ -0,0 +1,72 @@ +--TEST-- +stream filter - reading +--FILE-- +<?php +echo "-TEST\n"; +class filter extends php_user_filter { + function filter($in, $out, &$consumed, $closing) + { + $output = 0; + while ($bucket = stream_bucket_make_writeable($in)) { + $bucket->data = strtoupper($bucket->data); + $consumed += $bucket->datalen; + stream_bucket_append($out, $bucket); + $output = 1; + } + if ($closing) { + $bucket = stream_bucket_new($this->stream, "\n===close===\n"); + stream_bucket_append($out, $bucket); + $output = 1; + } + return $output ? PSFS_PASS_ON : PSFS_FEED_ME; + } +} +stream_filter_register("strtoupper", "filter") + or die("Failed to register filter"); + +if ($f = fopen(__FILE__, "rb")) { + stream_filter_append($f, "strtoupper"); + while (!feof($f)) { + echo fread($f, 8192); + } + fclose($f); +} +echo "Done\n"; +?> +--EXPECTF-- +%sTEST +<?PHP +ECHO "-TEST\N"; +CLASS FILTER EXTENDS PHP_USER_FILTER { + FUNCTION FILTER($IN, $OUT, &$CONSUMED, $CLOSING) + { + $OUTPUT = 0; + WHILE ($BUCKET = STREAM_BUCKET_MAKE_WRITEABLE($IN)) { + $BUCKET->DATA = STRTOUPPER($BUCKET->DATA); + $CONSUMED += $BUCKET->DATALEN; + STREAM_BUCKET_APPEND($OUT, $BUCKET); + $OUTPUT = 1; + } + IF ($CLOSING) { + $BUCKET = STREAM_BUCKET_NEW($THIS->STREAM, "\N===CLOSE===\N"); + STREAM_BUCKET_APPEND($OUT, $BUCKET); + $OUTPUT = 1; + } + RETURN $OUTPUT ? PSFS_PASS_ON : PSFS_FEED_ME; + } +} +STREAM_FILTER_REGISTER("STRTOUPPER", "FILTER") + OR DIE("FAILED TO REGISTER FILTER"); + +IF ($F = FOPEN(__FILE__, "RB")) { + STREAM_FILTER_APPEND($F, "STRTOUPPER"); + WHILE (!FEOF($F)) { + ECHO FREAD($F, 8192); + } + FCLOSE($F); +} +ECHO "DONE\N"; +?> + +===close=== +Done diff --git a/ext/standard/tests/general_functions/bug36011.phpt b/ext/standard/tests/general_functions/bug36011.phpt new file mode 100755 index 0000000000..08a45014f2 --- /dev/null +++ b/ext/standard/tests/general_functions/bug36011.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #36011 (Strict errormsg wrong for call_user_func() and the likes) +--FILE-- +<?php + +class TestClass +{ + static function test() + { + echo __METHOD__ . "()\n"; + } + + function whee() + { + array_map(array('TestClass', 'test'), array('array_value')); + } + + function whee4() + { + call_user_func(array('TestClass', 'test')); + } + + static function whee5() + { + call_user_func(array('TestClass', 'test')); + } +} + +TestClass::test(); + +$a = new TestClass(); +$a->whee(); +$a->whee4(); +$a->whee5(); + +TestClass::whee5(); + +?> +===DONE=== +--EXPECTF-- +TestClass::test() +TestClass::test() +TestClass::test() +TestClass::test() +TestClass::test() +===DONE=== diff --git a/ext/standard/tests/strings/bug33605.phpt b/ext/standard/tests/strings/bug33605.phpt new file mode 100644 index 0000000000..f0c49eb18f --- /dev/null +++ b/ext/standard/tests/strings/bug33605.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #33605 (substr_compare crashes) +--FILE-- +<?php +$res = substr_compare("aa", "a", -99999999, 0, 0); +var_dump($res); + +?> +--EXPECTF-- +Warning: substr_compare(): The length must be greater than zero in %s on line %d +bool(false) diff --git a/ext/standard/tests/strings/bug36148.phpt b/ext/standard/tests/strings/bug36148.phpt new file mode 100644 index 0000000000..06caac3334 --- /dev/null +++ b/ext/standard/tests/strings/bug36148.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #36148 (unpack("H*hex", $data) is adding an extra character to the end of the string) +--FILE-- +<?php +$values = array("a", "aa", "aaa", "aaaa"); +foreach ($values as $value) { + $a = pack("H*", $value); + $b = unpack("H*", $a); + echo $value.": "; + var_dump($b); +} +?> +--EXPECT-- +a: array(1) { + [1]=> + string(2) "a0" +} +aa: array(1) { + [1]=> + string(2) "aa" +} +aaa: array(1) { + [1]=> + string(4) "aaa0" +} +aaaa: array(1) { + [1]=> + string(4) "aaaa" +} diff --git a/ext/standard/tests/strings/bug36306.phpt b/ext/standard/tests/strings/bug36306.phpt new file mode 100644 index 0000000000..ff6279a2d3 --- /dev/null +++ b/ext/standard/tests/strings/bug36306.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #36306 crc32() 64bit +--FILE-- +<?php + +/* as an example how to write crc32 tests + PHP does not have uint values, you cannot + display crc32 like a signed integer. + Have to find some small strings to truely reproduce + the problem, this example being not a problem +*/ +echo dechex(crc32("platform independant")) . "\n"; +?> +--EXPECT-- +ccd9fe66 diff --git a/ext/standard/tests/strings/bug36944.phpt b/ext/standard/tests/strings/bug36944.phpt new file mode 100644 index 0000000000..2a43d060e2 --- /dev/null +++ b/ext/standard/tests/strings/bug36944.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #36944 (strncmp & strncasecmp do not return false on negative string length) +--FILE-- +<?php + +var_dump(strncmp("test ", "e", -1)); +var_dump(strncmp("test ", "e", 10)); +var_dump(strncmp("test ", "e", 0)); + +var_dump(strncasecmp("test ", "E", -1)); +var_dump(strncasecmp("test ", "E", 10)); +var_dump(strncasecmp("test ", "E", 0)); + +echo "Done\n"; +?> +--EXPECTF-- +Warning: Length must be greater than or equal to 0 in %s on line %d +bool(false) +int(%d) +int(0) + +Warning: Length must be greater than or equal to 0 in %s on line %d +bool(false) +int(%d) +int(0) +Done diff --git a/ext/standard/tests/strings/substr_compare.phpt b/ext/standard/tests/strings/substr_compare.phpt new file mode 100644 index 0000000000..594aed1735 --- /dev/null +++ b/ext/standard/tests/strings/substr_compare.phpt @@ -0,0 +1,39 @@ +--TEST-- +substr_compare() +--FILE-- +<?php + +var_dump(substr_compare("abcde", "bc", 1, 2)); +var_dump(substr_compare("abcde", "bcg", 1, 2)); +var_dump(substr_compare("abcde", "BC", 1, 2, true)); +var_dump(substr_compare("abcde", "bc", 1, 3)); +var_dump(substr_compare("abcde", "cd", 1, 2)); +var_dump(substr_compare("abcde", "abc", 5, 1)); + +var_dump(substr_compare("abcde", -1, 0, NULL, new stdClass)); +echo "Test\n"; +var_dump(substr_compare("abcde", "abc", -1, NULL, -5)); +var_dump(substr_compare("abcde", -1, 0, "str", new stdClass)); + +echo "Done\n"; +?> +--EXPECTF-- +int(0) +int(0) +int(0) +int(1) +int(-1) + +Warning: substr_compare(): The start position cannot exceed initial string length in %s on line %d +bool(false) + +Warning: substr_compare() expects parameter 5 to be boolean, object given in %s on line %d +bool(false) +Test + +Warning: substr_compare(): The length must be greater than zero in %s on line %d +bool(false) + +Warning: substr_compare() expects parameter 4 to be long, string given in %s on line %d +bool(false) +Done diff --git a/ext/xmlreader/tests/011.phpt b/ext/xmlreader/tests/011.phpt new file mode 100644 index 0000000000..89599232fc --- /dev/null +++ b/ext/xmlreader/tests/011.phpt @@ -0,0 +1,34 @@ +--TEST-- +XMLReader: libxml2 XML Reader, string data +--SKIPIF-- +<?php if (!extension_loaded("xmlreader")) print "skip"; +$reader = new XMLReader(); +if (!method_exists($reader, 'readInnerXml')) print "skip"; +?> +--FILE-- +<?php +/* $Id$ */ + +$xmlstring = '<?xml version="1.0" encoding="UTF-8"?> +<books><book>test</book></books>'; + +$reader = new XMLReader(); +$reader->XML($xmlstring); +$reader->read(); +echo $reader->readInnerXml(); +echo "\n"; +$reader->close(); + + +$reader = new XMLReader(); +$reader->XML($xmlstring); +$reader->read(); +echo $reader->readOuterXml(); +echo "\n"; +$reader->close(); +?> +===DONE=== +--EXPECT-- +<book>test</book> +<books><book>test</book></books> +===DONE=== diff --git a/ext/xmlreader/tests/012.dtd b/ext/xmlreader/tests/012.dtd new file mode 100755 index 0000000000..b65412af0e --- /dev/null +++ b/ext/xmlreader/tests/012.dtd @@ -0,0 +1,2 @@ +<!ELEMENT foo EMPTY> +<!ATTLIST foo bar CDATA '' baz CDATA ''> diff --git a/ext/xmlreader/tests/012.phpt b/ext/xmlreader/tests/012.phpt new file mode 100755 index 0000000000..e420bb7a17 --- /dev/null +++ b/ext/xmlreader/tests/012.phpt @@ -0,0 +1,69 @@ +--TEST-- +XMLReader: accessing empty and non existing attributes +--SKIPIF-- +<?php if (!extension_loaded("xmlreader")) print "skip"; ?> +--FILE-- +<?php +/* $Id$ */ + +$xmlstring =<<<EOF +<?xml version="1.0" encoding="UTF-8"?> +<foo bar=""/> +EOF; + +$reader = new XMLReader(); +$reader->XML($xmlstring); +$reader->read(); +var_dump($reader->getAttribute('bar')); +var_dump($reader->getAttribute('baz')); +$reader->close(); + +$xmlstring =<<<EOF +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE foo SYSTEM "012.dtd"> +<foo bar=""/> +EOF; + +$xmlstring = str_replace('012.dtd', dirname(__FILE__).'/012.dtd', $xmlstring); + +$reader = new XMLReader(); +$reader->XML($xmlstring); +$reader->setParserProperty(XMLReader::DEFAULTATTRS, true); +while($reader->read() && $reader->nodeType != XMLReader::ELEMENT); +var_dump($reader->getAttribute('bar')); +var_dump($reader->getAttribute('baz')); +$reader->close(); + +?> +===FILE=== +<?php + +$reader = new XMLReader(); +$reader->open(dirname(__FILE__) . '/012.xml'); +//$reader->setParserProperty(XMLReader::DEFAULTATTRS, true); +while($reader->read() && $reader->nodeType != XMLReader::ELEMENT); +var_dump($reader->getAttribute('bar')); +var_dump($reader->getAttribute('baz')); +$reader->close(); + +$reader = new XMLReader(); +$reader->open(dirname(__FILE__) . '/012.xml'); +$reader->setParserProperty(XMLReader::DEFAULTATTRS, true); +while($reader->read() && $reader->nodeType != XMLReader::ELEMENT); +var_dump($reader->getAttribute('bar')); +var_dump($reader->getAttribute('baz')); +$reader->close(); + +?> +===DONE=== +--EXPECT-- +string(0) "" +NULL +string(0) "" +string(0) "" +===FILE=== +string(0) "" +NULL +string(0) "" +string(0) "" +===DONE=== diff --git a/ext/xmlreader/tests/012.xml b/ext/xmlreader/tests/012.xml new file mode 100755 index 0000000000..5012bd5eff --- /dev/null +++ b/ext/xmlreader/tests/012.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE foo SYSTEM "012.dtd"> +<foo bar=""/> diff --git a/ext/xmlreader/tests/bug36743.phpt b/ext/xmlreader/tests/bug36743.phpt new file mode 100644 index 0000000000..45747d49f1 --- /dev/null +++ b/ext/xmlreader/tests/bug36743.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #36743 (In a class extending XMLReader array properties are not writable) +--FILE-- +<?php + +class Test extends XMLReader +{ + private $testArr = array(); + public function __construct() + { + $this->testArr[] = 1; + var_dump($this->testArr); + } +} + +$t = new test; + +echo "Done\n"; +?> +--EXPECT-- +array(1) { + [0]=> + int(1) +} +Done diff --git a/ext/xmlrpc/tests/bug37057.phpt b/ext/xmlrpc/tests/bug37057.phpt new file mode 100644 index 0000000000..0764d8af67 --- /dev/null +++ b/ext/xmlrpc/tests/bug37057.phpt @@ -0,0 +1,62 @@ +--TEST-- +Bug #37057 (xmlrpc_decode() may produce arrays with numeric string keys which are unaccessible) +--FILE-- +<?php +$response='<?xml version="1.0"?> +<methodResponse> + <params> + <param> + <value> + <struct> + <member> + <name>50</name> + <value><string>0.29</string></value> + </member> + </struct> + </value> + </param> + </params> +</methodResponse>'; + +$retval=xmlrpc_decode($response); +var_dump($retval); +var_dump($retval["50"]); +var_dump($retval[50]); + +$response='<?xml version="1.0"?> +<methodResponse> + <params> + <param> + <value> + <struct> + <member> + <name>0</name> + <value><string>0.29</string></value> + </member> + </struct> + </value> + </param> + </params> +</methodResponse>'; + +$retval=xmlrpc_decode($response); +var_dump($retval); +var_dump($retval["0"]); +var_dump($retval[0]); + +echo "Done\n"; +?> +--EXPECT-- +array(1) { + [50]=> + string(4) "0.29" +} +string(4) "0.29" +string(4) "0.29" +array(1) { + [0]=> + string(4) "0.29" +} +string(4) "0.29" +string(4) "0.29" +Done diff --git a/sapi/cgi/fastcgi.c b/sapi/cgi/fastcgi.c new file mode 100644 index 0000000000..afa5271d0e --- /dev/null +++ b/sapi/cgi/fastcgi.c @@ -0,0 +1,938 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "fastcgi.h" +#include "php.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> + +#ifdef _WIN32 + +#include <windows.h> + + typedef unsigned int size_t; + + struct sockaddr_un { + short sun_family; + char sun_path[MAXPATHLEN]; + }; + + static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE; + static int is_impersonate = 0; + +#define FCGI_LOCK(fd) \ + if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \ + DWORD ret; \ + while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \ + if (in_shutdown) return -1; \ + } \ + if (ret == WAIT_FAILED) { \ + fprintf(stderr, "WaitForSingleObject() failed\n"); \ + return -1; \ + } \ + } + +#define FCGI_UNLOCK(fd) \ + if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \ + ReleaseMutex(fcgi_accept_mutex); \ + } + +#else + +# include <sys/types.h> +# include <sys/stat.h> +# include <unistd.h> +# include <fcntl.h> +# include <sys/socket.h> +# include <sys/un.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +# include <sys/signal.h> + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif + +# ifndef HAVE_SOCKLEN_T + typedef unsigned int socklen_t; +# endif + +# ifdef USE_LOCKING +# define FCGI_LOCK(fd) \ + do { \ + struct flock lock; \ + lock.l_type = F_WRLCK; \ + lock.l_start = 0; \ + lock.l_whence = SEEK_SET; \ + lock.l_len = 0; \ + if (fcntl(fd, F_SETLKW, &lock) != -1) { \ + break; \ + } else if (errno != EINTR || in_shutdown) { \ + return -1; \ + } \ + } while (1) + +# define FCGI_UNLOCK(fd) \ + do { \ + int orig_errno = errno; \ + while (1) { \ + struct flock lock; \ + lock.l_type = F_UNLCK; \ + lock.l_start = 0; \ + lock.l_whence = SEEK_SET; \ + lock.l_len = 0; \ + if (fcntl(fd, F_SETLK, &lock) != -1) { \ + break; \ + } else if (errno != EINTR) { \ + return -1; \ + } \ + } \ + errno = orig_errno; \ + } while (0) +# else +# define FCGI_LOCK(fd) +# define FCGI_UNLOCK(fd) +# endif + +#endif + +typedef union _sa_t { + struct sockaddr sa; + struct sockaddr_un sa_unix; + struct sockaddr_in sa_inet; +} sa_t; + +typedef struct _fcgi_mgmt_rec { + char* name; + char val; +} fcgi_mgmt_rec; + +static const fcgi_mgmt_rec fcgi_mgmt_vars[] = { + {"FCGI_MAX_CONNS", 1}, + {"FCGI_MAX_REQS", 1}, + {"FCGI_MPXS_CONNS", 0} +}; + + +static int is_initialized = 0; +static int is_fastcgi = 0; +static int in_shutdown = 0; + +static inline char* fcgi_strndup(const char *str, int len) +{ + char *s = malloc(len+1); + memcpy(s, str, len+1); + return s; +} + +#ifdef _WIN32 + +static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg) +{ + HANDLE shutdown_event = (HANDLE) arg; + WaitForSingleObject(shutdown_event, INFINITE); + in_shutdown = 1; + return 0; +} + +#else + +static void fcgi_signal_handler(int signo) +{ + if (signo == SIGUSR1 || signo == SIGTERM) { + in_shutdown = 1; + } +} + +#endif + +int fcgi_init(void) +{ + if (!is_initialized) { +#ifdef _WIN32 +# if 0 + /* TODO: Support for TCP sockets */ + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2,0), &wsaData)) { + fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError()); + return 0; + } +# endif + is_initialized = 1; + + if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && + (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && + (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) { + char *str; + DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT; + HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE); + + SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL); + + str = getenv("_FCGI_SHUTDOWN_EVENT_"); + if (str != NULL) { + HANDLE shutdown_event = (HANDLE) atoi(str); + if (!CreateThread(NULL, 0, fcgi_shutdown_thread, + shutdown_event, 0, NULL)) { + return -1; + } + } + str = getenv("_FCGI_MUTEX_"); + if (str != NULL) { + fcgi_accept_mutex = (HANDLE) atoi(str); + } + return is_fastcgi = 1; + } else { + return is_fastcgi = 0; + } +#else + sa_t sa; + socklen_t len = sizeof(sa); + + is_initialized = 1; + errno = 0; + if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) { + struct sigaction new_sa, old_sa; + + sigemptyset(&new_sa.sa_mask); + new_sa.sa_flags = 0; + new_sa.sa_handler = fcgi_signal_handler; + sigaction(SIGUSR1, &new_sa, NULL); + sigaction(SIGTERM, &new_sa, NULL); + sigaction(SIGPIPE, NULL, &old_sa); + if (old_sa.sa_handler == SIG_DFL) { + sigaction(SIGPIPE, &new_sa, NULL); + } + + return is_fastcgi = 1; + } else { + return is_fastcgi = 0; + } +#endif + } + return is_fastcgi; +} + + +int fcgi_is_fastcgi(void) +{ + if (!is_initialized) { + return fcgi_init(); + } else { + return is_fastcgi; + } +} + +int fcgi_listen(const char *path, int backlog) +{ +#ifdef _WIN32 + /* TODO: Support for manual binding on TCP sockets (php -b <port>) */ + return -1; +#else + char *s; + int tcp = 0; + char host[MAXPATHLEN]; + short port = 0; + int listen_socket; + sa_t sa; + socklen_t sa_len; + + if ((s = strchr(path, ':'))) { + port = atoi(s+1); + if (port != 0 && (s-path) < MAXPATHLEN) { + strncpy(host, path, s-path); + host[s-path] = '\0'; + tcp = 1; + } + } + + /* Prepare socket address */ + if (tcp) { + memset(&sa.sa_inet, 0, sizeof(sa.sa_inet)); + sa.sa_inet.sin_family = AF_INET; + sa.sa_inet.sin_port = htons(port); + sa_len = sizeof(sa.sa_inet); + + if (!*host || !strncmp(host, "*", sizeof("*")-1)) { + sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + sa.sa_inet.sin_addr.s_addr = inet_addr(host); + if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) { + struct hostent *hep; + + hep = gethostbyname(host); + if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) { + fprintf(stderr, "Cannot resolve host name '%s'!\n", host); + return -1; + } else if (hep->h_addr_list[1]) { + fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host); + return -1; + } + sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr; + } + } + } else { + int path_len = strlen(path); + + if (path_len >= sizeof(sa.sa_unix.sun_path)) { + fprintf(stderr, "Listening socket's path name is too long.\n"); + return -1; + } + + memset(&sa.sa_unix, 0, sizeof(sa.sa_unix)); + sa.sa_unix.sun_family = AF_UNIX; + memcpy(sa.sa_unix.sun_path, path, path_len + 1); + sa_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len; +#ifdef HAVE_SOCKADDR_UN_SUN_LEN + sa.sa_unix.sun_len = sa_len; +#endif + unlink(path); + } + + /* Create, bind socket and start listen on it */ + if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 || + bind(listen_socket, (struct sockaddr *) &sa, sa_len) < 0 || + listen(listen_socket, backlog) < 0) { + + fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno)); + return -1; + } + + if (!tcp) { + chmod(path, 0777); + } + + if (!is_initialized) { + fcgi_init(); + } + is_fastcgi = 1; + return listen_socket; +#endif +} + +void fcgi_init_request(fcgi_request *req, int listen_socket) +{ + memset(req, 0, sizeof(fcgi_request)); + req->listen_socket = listen_socket; + req->fd = -1; + req->id = -1; + + req->in_len = 0; + req->in_pad = 0; + + req->out_hdr = NULL; + req->out_pos = req->out_buf; +} + +static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count) +{ + int ret; + size_t n = 0; + + do { + ret = write(req->fd, ((char*)buf)+n, count-n); + if (ret > 0) { + n += ret; + } else if (ret <= 0 && errno != 0 && errno != EINTR) { + return ret; + } + } while (n != count); + return n; +} + +static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count) +{ + int ret; + size_t n = 0; + + do { + ret = read(req->fd, ((char*)buf)+n, count-n); + if (ret > 0) { + n += ret; + } else if (ret == 0 && errno == 0) { + return n; + } else if (ret <= 0 && errno != 0 && errno != EINTR) { + return ret; + } + } while (n != count); + return n; +} + +static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len) +{ + int pad = ((len + 7) & ~7) - len; + + hdr->contentLengthB0 = (unsigned char)(len & 0xff); + hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff); + hdr->paddingLength = (unsigned char)pad; + hdr->requestIdB0 = (unsigned char)(req_id & 0xff); + hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff); + hdr->reserved = 0; + hdr->type = type; + hdr->version = FCGI_VERSION_1; + return pad; +} + +static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end, int n) +{ + int name_len, val_len; + char *s; + + while (p < end) { + name_len = *p++; + if (name_len >= 128) { + name_len = ((name_len & 0x7f) << 24); + name_len |= (*p++ << 16); + name_len |= (*p++ << 8); + name_len |= *p++; + } + val_len = *p++; + if (val_len >= 128) { + val_len = ((val_len & 0x7f) << 24); + val_len |= (*p++ << 16); + val_len |= (*p++ << 8); + val_len |= *p++; + } + req->env[n] = s = malloc(name_len + val_len + 2); + memcpy(s, p, name_len); + p += name_len; + s[name_len] = '='; + memcpy(s+name_len+1, p, val_len); + p += val_len; + s[name_len+1+val_len] = '\0'; + n++; + if (n > sizeof(req->env)/sizeof(req->env[0])) { + /* TODO: to many environment variables */ + return n; + } + } + return n; +} + +static int fcgi_read_request(fcgi_request *req) +{ + fcgi_header hdr; + int len, padding; + int n = 1; + char *s; + unsigned char buf[FCGI_MAX_LENGTH+8]; + + req->keep = 0; + req->in_len = 0; + req->out_hdr = NULL; + req->out_pos = req->out_buf; + memset(req->env, 0, sizeof(req->env)); + + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || + hdr.version < FCGI_VERSION_1) { + return 0; + } + + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; + padding = hdr.paddingLength; + + while (hdr.type == FCGI_STDIN && len == 0) { + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || + hdr.version < FCGI_VERSION_1) { + return 0; + } + + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; + padding = hdr.paddingLength; + } + + req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0; + + if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) { + if (safe_read(req, buf, len+padding) != len+padding) { + return 0; + } + + req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN); + switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) { + case FCGI_RESPONDER: + req->env[0] = fcgi_strndup("FCGI_ROLE=RESPONDER", sizeof("FCGI_ROLE=RESPONDER")-1); + break; + case FCGI_AUTHORIZER: + req->env[0] = fcgi_strndup("FCGI_ROLE=AUTHORIZER", sizeof("FCGI_ROLE=AUTHORIZER")-1); + break; + case FCGI_FILTER: + req->env[0] = fcgi_strndup("FCGI_ROLE=FILTER", sizeof("FCGI_ROLE=FILTER")-1); + break; + default: + return 0; + } + + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || + hdr.version < FCGI_VERSION_1) { + return 0; + } + + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; + padding = hdr.paddingLength; + + while (hdr.type == FCGI_PARAMS && len > 0) { + if (safe_read(req, buf, len+padding) != len+padding) { + req->keep = 0; + return 0; + } + n = fcgi_get_params(req, buf, buf+len, n); + + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || + hdr.version < FCGI_VERSION_1) { + req->keep = 0; + return 0; + } + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; + padding = hdr.paddingLength; + } + } else if (hdr.type == FCGI_GET_VALUES) { + int i, j; + int name_len; + unsigned char *p = buf + sizeof(fcgi_header); + + if (safe_read(req, buf, len+padding) != len+padding) { + return 0; + } + n = fcgi_get_params(req, buf, buf+len, 0); + for (i = 0; i < n; i++) { + if ((s = strchr(req->env[i], '=')) != NULL) { + *s = '\0'; + name_len = s - req->env[i]; + } else { + name_len = strlen(req->env[i]); + } + for (j = 0; j < sizeof(fcgi_mgmt_vars)/sizeof(fcgi_mgmt_vars[0]); j++) { + if (strncmp(req->env[i], fcgi_mgmt_vars[j].name, name_len) == 0) { + sprintf((char*)p, "%c%c%s%c", name_len, 1, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].val); + p += name_len+3; + } + } + } + len = p - buf - sizeof(fcgi_header); + len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len); + if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) { + return 0; + } + return 0; + } else { + return 0; + } + + return 1; +} + +int fcgi_read(fcgi_request *req, char *str, int len) +{ + int ret, n, rest; + fcgi_header hdr; + unsigned char buf[8]; + + n = 0; + rest = len; + while (rest > 0) { + if (req->in_len == 0) { + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || + hdr.version < FCGI_VERSION_1 || + hdr.type != FCGI_STDIN) { + req->keep = 0; + return 0; + } + req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; + req->in_pad = hdr.paddingLength; + if (req->in_len == 0) { + return n; + } + } + + if (req->in_len >= rest) { + ret = safe_read(req, str, rest); + } else { + ret = safe_read(req, str, req->in_len); + } + if (ret < 0) { + req->keep = 0; + return ret; + } else if (ret > 0) { + req->in_len -= ret; + rest -= ret; + n += ret; + str += ret; + if (req->in_len == 0) { + if (req->in_pad) { + if (safe_read(req, buf, req->in_pad) != req->in_pad) { + req->keep = 0; + return ret; + } + } + } else { + return n; + } + } else { + return n; + } + } + return n; +} + +static inline void fcgi_close(fcgi_request *req, int force, int destroy) +{ + if (destroy) { + char **env = req->env; + while (*env) { + free(*env++); + } + } + if ((force || !req->keep) && req->fd >= 0) { +#ifdef _WIN32 + HANDLE pipe = (HANDLE)_get_osfhandle(req->fd); + + if (!force) { + FlushFileBuffers(pipe); + } + DisconnectNamedPipe(pipe); + if (is_impersonate) { + RevertToSelf(); + } +#else +#if 1 + shutdown(req->fd, 2); +#else + close(req->fd); +#endif +#endif + req->fd = -1; + } +} + +int fcgi_accept_request(fcgi_request *req) +{ +#ifdef _WIN32 + HANDLE pipe; + OVERLAPPED ov; +#endif + fcgi_finish_request(req); + + while (1) { + if (req->fd < 0) { + while (1) { + if (in_shutdown) { + return -1; + } +#ifdef _WIN32 + pipe = (HANDLE)_get_osfhandle(req->listen_socket); + + FCGI_LOCK(req->listen_socket); + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(pipe, &ov)) { + errno = GetLastError(); + if (errno == ERROR_IO_PENDING) { + while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) { + if (in_shutdown) { + CloseHandle(ov.hEvent); + FCGI_UNLOCK(req->listen_socket); + return -1; + } + } + } else if (errno != ERROR_PIPE_CONNECTED) { + } + } + CloseHandle(ov.hEvent); + if (is_impersonate && !ImpersonateNamedPipeClient(pipe)) { + DisconnectNamedPipe(pipe); + req->fd = -1; + } else { + req->fd = req->listen_socket; + } + FCGI_UNLOCK(req->listen_socket); +#else + sa_t sa; + socklen_t len = sizeof(sa); + + FCGI_LOCK(req->listen_socket); + req->fd = accept(req->listen_socket, (struct sockaddr *)&sa, &len); + FCGI_UNLOCK(req->listen_socket); +#endif + + if (req->fd < 0 && (in_shutdown || errno != EINTR)) { + return -1; + } + +#ifdef _WIN32 + break; +#else + if (req->fd >= 0) { + struct timeval tv = {1,0}; + fd_set set; + + FD_ZERO(&set); + FD_SET(req->fd, &set); +try_again: + errno = 0; + if (select(req->fd + 1, &set, NULL, NULL, &tv) >= 0 && FD_ISSET(req->fd, &set)) { + break; + } + if (errno == EINTR) goto try_again; + fcgi_close(req, 1, 0); + } +#endif + } + } else if (in_shutdown) { + return -1; + } + if (fcgi_read_request(req)) { + return req->fd; + } else { + fcgi_close(req, 1, 1); + } + } +} + +static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type) +{ + req->out_hdr = (fcgi_header*) req->out_pos; + req->out_hdr->type = type; + req->out_pos += sizeof(fcgi_header); + return req->out_hdr; +} + +static inline void close_packet(fcgi_request *req) +{ + if (req->out_hdr) { + int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header)); + + req->out_pos += fcgi_make_header(req->out_hdr, req->out_hdr->type, req->id, len); + req->out_hdr = NULL; + } +} + +int fcgi_flush(fcgi_request *req, int close) +{ + int len; + + close_packet(req); + + len = req->out_pos - req->out_buf; + + if (close) { + fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos); + + fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request)); + rec->body.appStatusB3 = 0; + rec->body.appStatusB2 = 0; + rec->body.appStatusB1 = 0; + rec->body.appStatusB0 = 0; + rec->body.protocolStatus = FCGI_REQUEST_COMPLETE; + len += sizeof(fcgi_end_request_rec); + } + + if (safe_write(req, req->out_buf, len) != len) { + req->keep = 0; + return 0; + } + + req->out_pos = req->out_buf; + return 1; +} + +int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len) +{ + int limit, rest; + + if (len <= 0) { + return 0; + } + + if (req->out_hdr && req->out_hdr->type != type) { + close_packet(req); + } + rest = len; +#if 0 + /* Unoptinmzed, but clear version */ + while (rest > 0) { + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); + + if (!req->out_hdr) { + if (limit < sizeof(fcgi_header)) { + fcgi_flush(req, 0); + } + open_packet(req, type); + } + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); + if (rest < limit) { + memcpy(req->out_pos, str, rest); + req->out_pos += rest; + return len; + } else { + memcpy(req->out_pos, str, limit); + req->out_pos += limit; + rest -= limit; + str += limit; + fcgi_flush(req, 0); + } + } +#else + /* Optinmzed version */ + if (!req->out_hdr) { + rest += sizeof(fcgi_header); + } + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); + + if (rest < limit) { + if (!req->out_hdr) { + open_packet(req, type); + } + memcpy(req->out_pos, str, len); + req->out_pos += len; + } else if (rest - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) { + if (!req->out_hdr) { + open_packet(req, type); + } + memcpy(req->out_pos, str, limit); + req->out_pos += limit; + fcgi_flush(req, 0); + open_packet(req, type); + memcpy(req->out_pos, str + limit, len - limit); + req->out_pos += len - limit; + } else { + int pos = 0; + int pad; + + close_packet(req); + while ((len - pos) > 0xffff) { + open_packet(req, type); + fcgi_make_header(req->out_hdr, type, req->id, 0xfff8); + req->out_hdr = NULL; + fcgi_flush(req, 0); + if (safe_write(req, str + pos, 0xfff8) != 0xfff8) { + req->keep = 0; + return -1; + } + pos += 0xfff8; + } + + pad = (((len - pos) + 7) & ~7) - (len - pos); + rest = pad ? 8 - pad : 0; + + open_packet(req, type); + fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest); + req->out_hdr = NULL; + fcgi_flush(req, 0); + if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) { + req->keep = 0; + return -1; + } + if (pad) { + open_packet(req, type); + memcpy(req->out_pos, str + len - rest, rest); + req->out_pos += rest; + } + } +#endif + return len; +} + +int fcgi_finish_request(fcgi_request *req) +{ + fcgi_flush(req, 1); + fcgi_close(req, 0, 1); + return 1; +} + +char* fcgi_getenv_helper(char** env, const char *name, int len) +{ + if (name && env) { + while (*env) { + if ((strncmp(name, *env, len) == 0) && ((*env)[len] == '=')) { + return *env+len+1; + } + env++; + } + } + return NULL; +} + +char* fcgi_getenv(fcgi_request *req, const char* var, int var_len) +{ + if (!req) return NULL; + return fcgi_getenv_helper(req->env, var, var_len); +} + +void fcgi_putenv(fcgi_request *req, char* var, int var_len) +{ + if (var && req) { + char **env = req->env; + char *s = strchr(var, '='); + int len; + + if (!s) return ; + len = s - var + 1; + while (*env) { + if ((strncmp(var, *env, len) == 0)) { + free(*env); + *env = fcgi_strndup(var, var_len); + return; + } + env++; + } + *env = fcgi_strndup(var, var_len); + } +} + +int FCGX_FPrintF(FCGX_Stream stream, const char *format, ...) +{ + int result; + va_list args; + char buf[4096]; + + va_start(args, format); + result = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + + fcgi_write(stream.req, stream.type, buf, result); + return result; +} + +#ifdef _WIN32 +void OS_SetImpersonate(void) +{ + char *os_name; + + os_name = getenv("OS"); + if (os_name && stricmp(os_name, "Windows_NT") == 0) { + is_impersonate = 1; + } +} +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/sapi/cgi/fastcgi.h b/sapi/cgi/fastcgi.h new file mode 100644 index 0000000000..7c910e1abb --- /dev/null +++ b/sapi/cgi/fastcgi.h @@ -0,0 +1,183 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov <dmitry@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +/* FastCGI protocol */ + +#define FCGI_VERSION_1 1 + +#define FCGI_MAX_LENGTH 0xffff + +#define FCGI_KEEP_CONN 1 + +typedef enum _fcgi_role { + FCGI_RESPONDER = 1, + FCGI_AUTHORIZER = 2, + FCGI_FILTER = 3 +} fcgi_role; + +typedef enum _fcgi_request_type { + FCGI_BEGIN_REQUEST = 1, /* [in] */ + FCGI_ABORT_REQUEST = 2, /* [in] (not supported) */ + FCGI_END_REQUEST = 3, /* [out] */ + FCGI_PARAMS = 4, /* [in] environment variables */ + FCGI_STDIN = 5, /* [in] post data */ + FCGI_STDOUT = 6, /* [out] response */ + FCGI_STDERR = 7, /* [out] errors */ + FCGI_DATA = 8, /* [in] filter data (not supported) */ + FCGI_GET_VALUES = 9, /* [in] */ + FCGI_GET_VALUES_RESULT = 10 /* [out] */ +} fcgi_request_type; + +typedef enum _fcgi_protocol_status { + FCGI_REQUEST_COMPLETE = 0, + FCGI_CANT_MPX_CONN = 1, + FCGI_OVERLOADED = 2, + FCGI_UNKNOWN_ROLE = 3 +} dcgi_protocol_status; + +typedef struct _fcgi_header { + unsigned char version; + unsigned char type; + unsigned char requestIdB1; + unsigned char requestIdB0; + unsigned char contentLengthB1; + unsigned char contentLengthB0; + unsigned char paddingLength; + unsigned char reserved; +} fcgi_header; + +typedef struct _fcgi_begin_request { + unsigned char roleB1; + unsigned char roleB0; + unsigned char flags; + unsigned char reserved[5]; +} fcgi_begin_request; + +typedef struct _fcgi_begin_request_rec { + fcgi_header hdr; + fcgi_begin_request body; +} fcgi_begin_request_rec; + +typedef struct _fcgi_end_request { + unsigned char appStatusB3; + unsigned char appStatusB2; + unsigned char appStatusB1; + unsigned char appStatusB0; + unsigned char protocolStatus; + unsigned char reserved[3]; +} fcgi_end_request; + +typedef struct _fcgi_end_request_rec { + fcgi_header hdr; + fcgi_end_request body; +} fcgi_end_request_rec; + +/* FastCGI client API */ + +typedef struct _fcgi_request { + int listen_socket; + int fd; + int id; + int keep; + + int in_len; + int in_pad; + + fcgi_header *out_hdr; + unsigned char *out_pos; + unsigned char out_buf[1024*8]; + unsigned char reserved[sizeof(fcgi_end_request_rec)]; + + char *env[128]; +} fcgi_request; + +int fcgi_init(void); +int fcgi_is_fastcgi(void); +int fcgi_listen(const char *path, int backlog); +void fcgi_init_request(fcgi_request *req, int listen_socket); +int fcgi_accept_request(fcgi_request *req); +int fcgi_finish_request(fcgi_request *req); + +char* fcgi_getenv(fcgi_request *req, const char* var, int var_len); +void fcgi_putenv(fcgi_request *req, char* var, int var_len); + +int fcgi_read(fcgi_request *req, char *str, int len); + +int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len); +int fcgi_flush(fcgi_request *req, int close); + +/* Some defines for limited libfcgi comatibility */ + +typedef struct _FCGX_Stream { + fcgi_request *req; + fcgi_request_type type; +} FCGX_Stream; + +typedef struct _FCGX_Request { + fcgi_request req; + FCGX_Stream in; + FCGX_Stream out; + FCGX_Stream err; + char **envp; +} FCGX_Request; + +#define FCGX_Init() +#define FCGX_IsCGI() (!fcgi_is_fastcgi()) +#define FCGX_OpenSocket(path, backlog) fcgi_listen(path, backlog) + +#define FCGX_InitRequest(r, sock, flags) \ + do { \ + fcgi_init_request(&(r)->req, sock); \ + (r)->in.req = &(r)->req; \ + (r)->out.req = &(r)->req; \ + (r)->err.req = &(r)->req; \ + (r)->in.type = FCGI_STDIN; \ + (r)->out.type = FCGI_STDOUT; \ + (r)->err.type = FCGI_STDERR; \ + (r)->envp = (r)->req.env; \ + } while (0); + + +#define FCGX_Accept_r(r) fcgi_accept_request(&(r)->req) +#define FCGX_Finish_r(r) fcgi_finish_request(&(r)->req) + +#define FCGX_PutStr(str, len, stream) fcgi_write((stream).req, (stream).type, str, len) +#define FCGX_PutS(str, len, stream) fcgi_write((stream).req, (stream).type, str, len) +#define FCGX_FFlush(stream) fcgi_flush((stream).req, 0) +#define FCGX_GetStr(str, len, stream) fcgi_read((stream).req, str, len) + +#define FCGX_GetParam(var, envp) fcgi_getenv_helper(envp, var, strlen(var)); + +#define FCGX_PutEnv(r, var) fcgi_putenv(&(r)->req, var, strlen(var)); + +int FCGX_FPrintF(FCGX_Stream stream, const char *format, ...); + +/* Internal helper functions. They shouldn't be used directly. */ + +char* fcgi_getenv_helper(char** env, const char *name, int len); + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |