From 99df545eab3cf415cd6b6744ccf60408b1171086 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 22 May 2019 20:41:59 +0200 Subject: [PATCH 01/67] Fixed Uri class Added tests for Uri class Improved build process by copying pecl.m4 from pecl/http. --- .gitignore | 4 +- CMakeLists.txt | 3 +- autoconf/pecl.m4 | 415 +++++++++++++++++++++++++++++++++ config.m4 | 23 +- macros.h | 7 +- tests/skeleton_nop.phpt | 12 - tests/uri/__construct-001.phpt | 23 ++ tests/uri/__construct-002.phpt | 23 ++ tests/uri/__construct-003.phpt | 23 ++ tests/uri/__construct-004.phpt | 23 ++ tests/uri/__construct-005.phpt | 23 ++ tests/uri/__construct-006.phpt | 23 ++ tests/uri/__construct-007.phpt | 23 ++ tests/uri/__construct-008.phpt | 23 ++ uri.c | 72 +++++- 15 files changed, 684 insertions(+), 36 deletions(-) create mode 100644 autoconf/pecl.m4 delete mode 100644 tests/skeleton_nop.phpt create mode 100644 tests/uri/__construct-001.phpt create mode 100644 tests/uri/__construct-002.phpt create mode 100644 tests/uri/__construct-003.phpt create mode 100644 tests/uri/__construct-004.phpt create mode 100644 tests/uri/__construct-005.phpt create mode 100644 tests/uri/__construct-006.phpt create mode 100644 tests/uri/__construct-007.phpt create mode 100644 tests/uri/__construct-008.phpt diff --git a/.gitignore b/.gitignore index 4c82adf..79edfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -25,9 +25,9 @@ modules/ .libs/ *.la *.lo +tests/**/*.* +!tests/**/*.phpt php_test_results_*.txt -tests/* -!tests/*.phpt http_message.loT *.loT configure.ac diff --git a/CMakeLists.txt b/CMakeLists.txt index 685f779..1a7f3ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.8) -project(http_message) +project(http_message C) add_custom_target(extension COMMAND phpize && ./configure && make && make install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) @@ -18,6 +18,7 @@ message("Using source directory: ${PHP_SOURCE}") include_directories(${PHP_SOURCE}) include_directories(${PHP_SOURCE}/main) include_directories(${PHP_SOURCE}/Zend) +include_directories(${PHP_SOURCE}/TSRM) include_directories(${PROJECT_SOURCE_DIR}) add_executable(http_message ${SOURCE_FILES}) diff --git a/autoconf/pecl.m4 b/autoconf/pecl.m4 new file mode 100644 index 0000000..ffa45ac --- /dev/null +++ b/autoconf/pecl.m4 @@ -0,0 +1,415 @@ + +yes() { + true +} +no() { + false +} +dnl +dnl PECL_INIT(name) +dnl +dnl Start configuring the PECL extension. +dnl +AC_DEFUN([PECL_INIT], [dnl + m4_define([PECL_NAME],[$1])dnl +])dnl +dnl +dnl +dnl PECL_VAR(name) +dnl +AC_DEFUN([PECL_VAR], [dnl +AS_TR_CPP([PHP_]PECL_NAME[_$1])dnl +])dnl +dnl +dnl PECL_CACHE_VAR(name) +dnl +AC_DEFUN([PECL_CACHE_VAR], [dnl +AS_TR_SH([PECL_cv_$1])dnl +])dnl +dnl +dnl PECL_SAVE_VAR(name) +dnl +AC_DEFUN([PECL_SAVE_VAR], [dnl +AS_TR_SH([PECL_sv_$1])dnl +])dnl +dnl +dnl PECL_DEFINE(what, to[, desc]) +dnl +AC_DEFUN([PECL_DEFINE], [dnl + AC_DEFINE(PECL_VAR([$1]), ifelse([$2],,1,[$2]), ifelse([$3],,[ ],[$3])) +])dnl +dnl +dnl PECL_DEFINE_UQ(what, to[, desc]) +dnl +AC_DEFUN([PECL_DEFINE_UQ], [dnl + AC_DEFINE_UNQUOTED(PECL_VAR([$1]), [$2], ifelse([$3],,[ ],[$3])) +])dnl +dnl +dnl PECL_DEFINE_SH(what, to[, desc]) +dnl +AC_DEFUN([PECL_DEFINE_SH], [dnl + PECL_VAR([$1])=$2 + PECL_DEFINE_UQ([$1], [$2], [$3]) +]) +dnl +dnl PECL_DEFINE_FN(fn) +dnl +AC_DEFUN([PECL_DEFINE_FN], [ + AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1], [ ]) +]) +dnl +dnl PECL_SAVE_ENV(var, ns) +dnl +AC_DEFUN([PECL_SAVE_ENV], [ + PECL_SAVE_VAR([$2_$1])=[$]$1 +]) +dnl +dnl PECL_RESTORE_ENV(var, ns) +dnl +AC_DEFUN([PECL_RESTORE_ENV], [ + $1=$PECL_SAVE_VAR([$2_$1]) +]) +dnl +dnl PECL_EVAL_LIBLINE(libline) +dnl +AC_DEFUN([PECL_EVAL_LIBLINE], [ + PECL_SAVE_ENV(ext_shared, pecl) + ext_shared=no + PHP_EVAL_LIBLINE([$1], _pecl_eval_libline_dummy) + PECL_RESTORE_ENV(ext_shared, pecl) +]) +dnl +dnl PECL_PROG_EGREP +dnl +dnl Checks for an egrep. Defines $EGREP. +dnl +AC_DEFUN([PECL_PROG_EGREP], [ + ifdef([AC_PROG_EGREP], [ + AC_PROG_EGREP + ], [ + AC_CHECK_PROG(EGREP, egrep, egrep) + ]) +]) +dnl +dnl PECL_PROG_AWK +dnl +dnl Checks for an awk. Defines $AWK. +dnl +AC_DEFUN([PECL_PROG_AWK], [ + ifdef([AC_PROG_AWK], [ + AC_PROG_AWK + ], [ + AC_CHECK_PROG(AWK, awk, awk) + ]) +]) +dnl +dnl PECL_PROG_SED +dnl +dnl Checks for the sed program. Defines $SED. +dnl +AC_DEFUN([PECL_PROG_SED], [ + ifdef([AC_PROG_SED], [ + AC_PROG_SED + ], [ + ifdef([LT_AC_PROG_SED], [ + LT_AC_PROG_SED + ], [ + AC_CHECK_PROG(SED, sed, sed) + ]) + ]) +]) +dnl +dnl PECL_PROG_PKGCONFIG +dnl +dnl Checks for pkg-config program and defines $PKG_CONFIG (to false if not found). +dnl +AC_DEFUN([PECL_PROG_PKGCONFIG], [ + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG([PKG_CONFIG], [pkg-config], [false]) + fi +]) +dnl +dnl PECL_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]]) +dnl +dnl Check whether ext/$name is enabled in $PHP_EXECUTABLE (PECL build) +dnl or if $PHP_ is defined to anything else than "no" (in-tree build). +dnl Defines shell var PECL_VAR(HAVE_EXT_) to true or false. +dnl +AC_DEFUN([PECL_HAVE_PHP_EXT], [ + AC_REQUIRE([PECL_PROG_EGREP])dnl + AC_CACHE_CHECK([whether ext/$1 is enabled], PECL_CACHE_VAR([HAVE_EXT_$1]), [ + PECL_CACHE_VAR([HAVE_EXT_$1])=no + if test -x "$PHP_EXECUTABLE"; then + if $PHP_EXECUTABLE -m | $EGREP -q ^$1\$; then + PECL_CACHE_VAR([HAVE_EXT_$1])=yes + fi + elif test -n "$AS_TR_CPP([PHP_$1])" && test "$AS_TR_CPP([PHP_$1])" != "no"; then + PECL_CACHE_VAR([HAVE_EXT_$1])=yes + fi + ]) + if $PECL_CACHE_VAR([HAVE_EXT_$1]); then + PECL_VAR([HAVE_EXT_$1])=true + PECL_DEFINE([HAVE_EXT_$1]) + $2 + else + PECL_VAR([HAVE_EXT_$1])=false + $3 + fi +]) +dnl +dnl PECL_HAVE_PHP_EXT_HEADER(ext[, header]) +dnl +dnl Check where to find a header for ext and add the found dir to $INCLUDES. +dnl If header is not specified php_.h is assumed. +dnl Defines shell var PHP__EXT__INCDIR to the found dir. +dnl Defines PHP__HAVE_
to the found path. +dnl +AC_DEFUN([PECL_HAVE_PHP_EXT_HEADER], [dnl + AC_REQUIRE([PECL_PROG_SED])dnl + m4_define([EXT_HEADER], ifelse([$2],,php_$1.h,[$2]))dnl + AC_CACHE_CHECK([for EXT_HEADER of ext/$1], PECL_CACHE_VAR([EXT_$1]_INCDIR), [ + for i in $(printf "%s" "$INCLUDES" | $SED -e's/-I//g') $abs_srcdir ../$1; do + if test -d $i; then + for j in $i/EXT_HEADER $i/ext/$1/EXT_HEADER; do + if test -f $j; then + PECL_CACHE_VAR([EXT_$1]_INCDIR)=$(dirname "$j") + break + fi + done + fi + done + ]) + PECL_VAR([EXT_$1]_INCDIR)=$PECL_CACHE_VAR([EXT_$1]_INCDIR) + PHP_ADD_INCLUDE([$PECL_VAR([EXT_$1]_INCDIR)]) + PECL_DEFINE_UQ([HAVE_]EXT_HEADER, "$PECL_VAR([EXT_$1]_INCDIR)/EXT_HEADER") +]) +dnl +dnl PECL_HAVE_CONST(header, const[, type=int[, code-if-yes[, code-if-mno]]]) +dnl +AC_DEFUN([PECL_HAVE_CONST], [dnl + AC_REQUIRE([PECL_PROG_EGREP])dnl + AC_CACHE_CHECK([for $2 in $1], PECL_CACHE_VAR([HAVE_$1_$2]), [ + AC_TRY_COMPILE([ + #include "$1" + ], [ + ]ifelse([$3],,int,[$3])[ _c = $2; + (void) _c; + ], [ + PECL_CACHE_VAR([HAVE_$1_$2])=yes + ], [ + PECL_CACHE_VAR([HAVE_$1_$2])=no + ]) + ]) + if $PECL_CACHE_VAR([HAVE_$1_$2]); then + PECL_DEFINE([HAVE_$2]) + $4 + else + ifelse([$5],,:,[$5]) + fi +]) +dnl +dnl _PECL_TR_VERSION(version) +dnl +AC_DEFUN([_PECL_TR_VERSION], [dnl +AC_REQUIRE([PECL_PROG_AWK])dnl +$(printf "%s" $1 | $AWK -F "[.]" '{print $[]1*1000000 + $[]2*10000 + $[]3*100 + $[]4}') +]) +dnl +dnl PECL_CHECKED_VERSION(name) +dnl +dnl Shell var name of an already checked version. +dnl +AC_DEFUN([PECL_CHECKED_VERSION], [PECL_VAR([$1][_VERSION])]) +dnl +dnl PECL_HAVE_VERSION(name, min-version[, code-if-yes[, code-if-not]]) +dnl +dnl Perform a min-version check while in an PECL_CHECK_* block. +dnl Expands AC_MSG_ERROR when code-if-not is empty and the version check fails. +dnl +AC_DEFUN([PECL_HAVE_VERSION], [ + aversion=_PECL_TR_VERSION([$PECL_CHECKED_VERSION([$1])]) + mversion=_PECL_TR_VERSION([$2]) + AC_MSG_CHECKING([whether $1 version $PECL_CHECKED_VERSION([$1]) >= $2]) + if test -z "$aversion" || test "$aversion" -lt "$mversion"; then + ifelse($4,,AC_MSG_ERROR([no]), [ + AC_MSG_RESULT([no]) + $4 + ]) + else + AC_MSG_RESULT([ok]) + $3 + fi +]) +dnl +dnl PECL_CHECK_CUSTOM(name, path, header, lib, version) +dnl +AC_DEFUN([PECL_CHECK_CUSTOM], [ + PECL_SAVE_ENV([CPPFLAGS], [$1]) + PECL_SAVE_ENV([LDFLAGS], [$1]) + PECL_SAVE_ENV([LIBS], [$1]) + + AC_MSG_CHECKING([for $1]) + AC_CACHE_VAL(PECL_CACHE_VAR([$1_prefix]), [ + for path in $2 /usr/local /usr /opt; do + if test "$path" = "" || test "$path" = "yes" || test "$path" = "no"; then + continue + elif test -f "$path/include/$3"; then + PECL_CACHE_VAR([$1_prefix])="$path" + break + fi + done + ]) + if test -n "$PECL_CACHE_VAR([$1_prefix])"; then + CPPFLAGS="-I$PECL_CACHE_VAR([$1_prefix])/include" + LDFLAGS="-L$PECL_CACHE_VAR([$1_prefix])/$PHP_LIBDIR" + LIBS="-l$4" + PECL_EVAL_LIBLINE([$LDFLAGS $LIBS]) + + AC_CACHE_VAL(PECL_CACHE_VAR([$1_version]), [ + pushd $PECL_CACHE_VAR([$1_prefix]) >/dev/null + PECL_CACHE_VAR([$1_version])=$5 + popd >/dev/null + ]) + PECL_CHECKED_VERSION([$1])=$PECL_CACHE_VAR([$1_version]) + + if test -n "$PECL_CHECKED_VERSION([$1])"; then + PECL_VAR([HAVE_$1])=true + PECL_DEFINE([HAVE_$1]) + PECL_DEFINE_UQ($1[_VERSION], "$PECL_CHECKED_VERSION([$1])") + else + PECL_VAR([HAVE_$1])=false + fi + else + PECL_VAR([HAVE_$1])=false + fi + AC_MSG_RESULT([${PECL_CHECKED_VERSION([$1]):-no}]) +]) +dnl +dnl PECL_CHECK_CONFIG(name, prog-config, version-flag, cppflags-flag, ldflags-flag, libs-flag) +dnl +AC_DEFUN([PECL_CHECK_CONFIG], [ + PECL_SAVE_ENV([CPPFLAGS], [$1]) + PECL_SAVE_ENV([LDFLAGS], [$1]) + PECL_SAVE_ENV([LIBS], [$1]) + + + AC_MSG_CHECKING([for $1]) + ifelse($2, [$PKG_CONFIG $1], [ + AC_CACHE_VAL(PECL_CACHE_VAR([$1_exists]), [ + if $($2 --exists); then + PECL_CACHE_VAR([$1_exists])=yes + else + PECL_CACHE_VAR([$1_exists])=no + fi + ]) + if $PECL_CACHE_VAR([$1_exists]); then + ]) + AC_CACHE_VAL(PECL_CACHE_VAR([$1_version]), [ + PECL_CACHE_VAR([$1_version])=$($2 $3) + ]) + PECL_CHECKED_VERSION([$1])=$PECL_CACHE_VAR([$1_version]) + AC_CACHE_VAL(PECL_CACHE_VAR([$1_cppflags]), [ + PECL_CACHE_VAR([$1_cppflags])=$($2 $4) + ]) + CPPFLAGS=$PECL_CACHE_VAR([$1_cppflags]) + AC_CACHE_VAL(PECL_CACHE_VAR([$1_ldflags]), [ + PECL_CACHE_VAR([$1_ldflags])=$($2 $5) + ]) + LDFLAGS=$PECL_CACHE_VAR([$1_ldflags]) + AC_CACHE_VAL(PECL_CACHE_VAR([$1_libs]), [ + PECL_CACHE_VAR([$1_libs])=$($2 $6) + ]) + LIBS=$PECL_CACHE_VAR([$1_libs]) + PECL_EVAL_LIBLINE([$LDFLAGS $LIBS]) + ifelse($2, [$PKG_CONFIG $1], [ + fi + ]) + + if test -n "$PECL_CHECKED_VERSION([$1])"; then + PECL_VAR([HAVE_$1])=true + PECL_DEFINE([HAVE_$1]) + PECL_DEFINE_UQ([$1_VERSION], "$PECL_CHECKED_VERSION([$1])") + else + PECL_VAR([HAVE_$1])=false + fi + + AC_MSG_RESULT([${PECL_CHECKED_VERSION([$1]):-no}]) +]) +dnl +dnl PECL_CHECK_PKGCONFIG(pkg[, additional-pkg-config-path]) +dnl +AC_DEFUN([PECL_CHECK_PKGCONFIG], [dnl + AC_REQUIRE([PECL_PROG_PKGCONFIG])dnl + ifelse($2,,, [ + PECL_SAVE_VAR(pkgconfig_path)="$PKG_CONFIG_PATH" + if test -d "$2"; then + export PKG_CONFIG_PATH="$2/lib/pkgconfig:$PKG_CONFIG_PATH" + fi + ]) + PECL_CHECK_CONFIG([$1], [$PKG_CONFIG $1], [--modversion], [--cflags-only-I], [--libs-only-L], [--libs-only-l]) + ifelse($2,,, [ + PKG_CONFIG_PATH="$PECL_SAVE_VAR(pkgconfig_path)" + ]) +]) +dnl +dnl PECL_CHECK_DONE(name, success[, incline, libline]) +dnl +AC_DEFUN([PECL_CHECK_DONE], [ + if $2; then + incline=$CPPFLAGS + libline="$LDFLAGS $LIBS" + PECL_DEFINE([HAVE_$1]) + else + incline=$3 + libline=$4 + fi + + PECL_RESTORE_ENV([CPPFLAGS], [$1]) + PECL_RESTORE_ENV([LDFLAGS], [$1]) + PECL_RESTORE_ENV([LIBS], [$1]) + + PHP_EVAL_INCLINE([$incline]) + PHP_EVAL_LIBLINE([$libline], AS_TR_CPP(PECL_NAME[_SHARED_LIBADD])) +]) + +dnl +dnl PECL_CHECK_CA([additional-ca-paths,[ additional-ca-bundles]]) +dnl +AC_DEFUN([PECL_CHECK_CA], [ + AC_CACHE_CHECK([for default CA path], PECL_CACHE_VAR([CAPATH]), [ + PECL_VAR([CAPATH])= + for ca_path in $1 \ + /etc/ssl/certs \ + /System/Library/OpenSSL + do + # check if it's actually a hashed directory + if test -d "$ca_path" && ls "$ca_path"/@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@@<:@0-9a-f@:>@.0 >/dev/null 2>&1; then + PECL_CACHE_VAR([CAPATH])=$ca_path + break + fi + done + ]) + if test -n "$PECL_CACHE_VAR([CAPATH])"; then + PECL_DEFINE_SH([CAPATH], "$PECL_CACHE_VAR([CAPATH])") + fi + + AC_CACHE_CHECK([for default CA info], PECL_CACHE_VAR([CAINFO]), [ + for ca_info in $2 \ + /etc/ssl/{cert,ca-bundle}.pem \ + /{etc,usr/share}/ssl/certs/ca-{bundle,ceritifcates}.crt \ + /etc/{pki/ca-trust,ca-certificates}/extracted/pem/tls-ca-bundle.pem \ + /etc/pki/tls/certs/ca-bundle{,.trust}.crt \ + /usr/local/etc/{,open}ssl/cert.pem \ + /usr/local/share/certs/ca-root-nss.crt \ + /{usr,usr/local,opt}/local/share/curl/curl-ca-bundle.crt + do + if test -f "$ca_info"; then + PECL_CACHE_VAR([CAINFO])=$ca_info + break + fi + done + ]) + if test -n "$PECL_CACHE_VAR([CAINFO])"; then + PECL_DEFINE_SH([CAINFO], "$PECL_CACHE_VAR([CAINFO])") + fi +]) diff --git a/config.m4 b/config.m4 index fd7df05..1a4d31f 100644 --- a/config.m4 +++ b/config.m4 @@ -1,14 +1,23 @@ dnl $Id$ dnl config.m4 for extension http_message -PHP_ARG_WITH(http_message, for http_message support, -[ --with-http_message Include http_message support]) +sinclude(./autoconf/pecl.m4) + +PECL_INIT([http_message]) + +PHP_ARG_WITH(http-message, for http_message support, +[ --with-http-message Include http_message support]) if test "$PHP_HTTP_MESSAGE" != "no"; then - # TODO: Load external depenencies here + PECL_HAVE_PHP_EXT([psr], [ + PECL_HAVE_PHP_EXT_HEADER([psr]) + ], [ + AC_MSG_ERROR([please install and enable pecl/psr]) + ]) - AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message support]) - PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c, - $ext_shared) -fi + AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message support]) + PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c, + $ext_shared) + PHP_ADD_EXTENSION_DEP([http_message], [psr], true) +fi diff --git a/macros.h b/macros.h index 43ade64..6066ba8 100644 --- a/macros.h +++ b/macros.h @@ -36,10 +36,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, 0, 0) ZEND_END_ARG_INFO() #define INIT_ARRAY_PROPERTY(className, property, rv) \ - array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)); + array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)) -#define SET_STRING_PROPERTY(className, property, value) \ - zend_update_property_stringl(className, getThis(), ZEND_STRL(property), value ?: "", value ? strlen(value) : 0); +#define SET_STRING_PROPERTY(className, property, val) \ + if (val != NULL) \ + zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) #define HTTP_MESSAGE_ME(className, method) \ PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) diff --git a/tests/skeleton_nop.phpt b/tests/skeleton_nop.phpt deleted file mode 100644 index 0732b1b..0000000 --- a/tests/skeleton_nop.phpt +++ /dev/null @@ -1,12 +0,0 @@ ---TEST-- -TODO: Add tests for your functions ---SKIPIF-- - ---FILE-- - ---EXPECT-- -string(11) "Hello World" - diff --git a/tests/uri/__construct-001.phpt b/tests/uri/__construct-001.phpt new file mode 100644 index 0000000..b4754b2 --- /dev/null +++ b/tests/uri/__construct-001.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri without arguments +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(0) "" + protected $userInfo => + string(0) "" + protected $host => + string(0) "" + protected $port => + NULL + protected $path => + string(0) "" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-002.phpt b/tests/uri/__construct-002.phpt new file mode 100644 index 0000000..aa808b6 --- /dev/null +++ b/tests/uri/__construct-002.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with a basic url +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(5) "https" + protected $userInfo => + string(0) "" + protected $host => + string(15) "www.example.com" + protected $port => + NULL + protected $path => + string(1) "/" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-003.phpt b/tests/uri/__construct-003.phpt new file mode 100644 index 0000000..a80e567 --- /dev/null +++ b/tests/uri/__construct-003.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with a full url +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(4) "http" + protected $userInfo => + string(4) "acme" + protected $host => + string(15) "www.example.com" + protected $port => + int(8000) + protected $path => + string(4) "/foo" + protected $query => + string(9) "answer=42" + protected $fragment => + string(8) "question" +} diff --git a/tests/uri/__construct-004.phpt b/tests/uri/__construct-004.phpt new file mode 100644 index 0000000..2ae5049 --- /dev/null +++ b/tests/uri/__construct-004.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with username and password +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(5) "https" + protected $userInfo => + string(11) "acme:secure" + protected $host => + string(15) "www.example.com" + protected $port => + NULL + protected $path => + string(1) "/" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-005.phpt b/tests/uri/__construct-005.phpt new file mode 100644 index 0000000..5d5dd6c --- /dev/null +++ b/tests/uri/__construct-005.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with a basic url without a path +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(5) "https" + protected $userInfo => + string(0) "" + protected $host => + string(15) "www.example.com" + protected $port => + NULL + protected $path => + string(0) "" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-006.phpt b/tests/uri/__construct-006.phpt new file mode 100644 index 0000000..c67341b --- /dev/null +++ b/tests/uri/__construct-006.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with a domain name +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(0) "" + protected $userInfo => + string(0) "" + protected $host => + string(0) "www.example.com" + protected $port => + NULL + protected $path => + string(0) "" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-007.phpt b/tests/uri/__construct-007.phpt new file mode 100644 index 0000000..8a81592 --- /dev/null +++ b/tests/uri/__construct-007.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with an absolute path +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(0) "" + protected $userInfo => + string(0) "" + protected $host => + string(0) "" + protected $port => + NULL + protected $path => + string(0) "/foo" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/tests/uri/__construct-008.phpt b/tests/uri/__construct-008.phpt new file mode 100644 index 0000000..b3c7d5a --- /dev/null +++ b/tests/uri/__construct-008.phpt @@ -0,0 +1,23 @@ +--TEST-- +Create Uri with a relative path +--FILE-- + +--EXPECT-- +class HttpMessage\Uri#1 (7) { + protected $scheme => + string(0) "" + protected $userInfo => + string(0) "" + protected $host => + string(0) "" + protected $port => + NULL + protected $path => + string(0) "foo" + protected $query => + string(0) "" + protected $fragment => + string(0) "" +} diff --git a/uri.c b/uri.c index 026f217..c824c64 100644 --- a/uri.c +++ b/uri.c @@ -37,6 +37,7 @@ #include "php_http_message.h" #include "macros.h" #include "zend_exceptions.h" +#include "zend_smart_str.h" #include "ext/standard/info.h" #include "ext/standard/url.h" #include "ext/psr/psr_http_message.h" @@ -45,7 +46,6 @@ zend_class_entry *HttpMessage_Uri_ce; - /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUri_construct, 0, 0, 0) @@ -55,12 +55,12 @@ ZEND_END_ARG_INFO() PHP_METHOD(Uri, __construct) { php_url *info; - char *value; + char *value, *userinfo; size_t value_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_STRING(value, value_len) + Z_PARAM_OPTIONAL + Z_PARAM_STRING(value, value_len) ZEND_PARSE_PARAMETERS_END(); if (value_len > 0) { @@ -68,7 +68,6 @@ PHP_METHOD(Uri, __construct) SET_STRING_PROPERTY(HttpMessage_Uri_ce, "scheme", info->scheme); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "host", info->host); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "userInfo", info->user); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "path", info->path); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "query", info->query); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "fragment", info->fragment); @@ -76,18 +75,73 @@ PHP_METHOD(Uri, __construct) if (info->port > 0) { zend_update_property_long(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), info->port); } + + if (info->pass == NULL) { + SET_STRING_PROPERTY(HttpMessage_Uri_ce, "userInfo", info->user); + } else { + userinfo = emalloc(strlen(info->user) + strlen(info->pass) + 2); + sprintf(userinfo, "%s:%s", info->user, info->pass); + SET_STRING_PROPERTY(HttpMessage_Uri_ce, "userInfo", userinfo); + efree(userinfo); + } } } /* __toString */ - ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUri_toString, 0, 0, 0) ZEND_END_ARG_INFO() PHP_METHOD(Uri, __toString) { + zval rv, *scheme, *userinfo, *host, *port, *path, *query, *fragment; + smart_str buf = {0}; + + scheme = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("scheme"), 0, &rv); + userinfo = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); + host = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); + port = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); + path = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("path"), 0, &rv); + query = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("query"), 0, &rv); + fragment = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("fragment"), 0, &rv); + + if (Z_STRLEN(*scheme) > 0) { + smart_str_appendl(&buf, Z_STRVAL(*scheme), Z_STRLEN(*scheme)); + smart_str_appends(&buf, ":"); + } + + if (Z_STRLEN(*host) > 0) { + smart_str_appends(&buf, "//"); + + if (Z_STRLEN(*userinfo) > 0) { + smart_str_appendl(&buf, Z_STRVAL(*userinfo), Z_STRLEN(*userinfo)); + smart_str_appends(&buf, "@"); + } + + smart_str_appendl(&buf, Z_STRVAL(*host), Z_STRLEN(*host)); + + if (Z_TYPE(*port) == IS_LONG) { + smart_str_appends(&buf, ":"); + smart_str_append_long(&buf, Z_LVAL(*port)); + } + } + + // Todo sanitize path + smart_str_appendl(&buf, Z_STRVAL(*path), Z_STRLEN(*path)); + + if (Z_STRLEN(*query) > 0) { + smart_str_appends(&buf, "?"); + smart_str_appendl(&buf, Z_STRVAL(*query), Z_STRLEN(*query)); + } + + if (Z_STRLEN(*fragment) > 0) { + smart_str_appends(&buf, "#"); + smart_str_appendl(&buf, Z_STRVAL(*fragment), Z_STRLEN(*fragment)); + } + + RETVAL_STR_COPY(buf.s); + zend_string_release(buf.s); } @@ -121,11 +175,7 @@ PHP_METHOD(Uri, withScheme) PHP_METHOD(Uri, getAuthority) { - zval rv, *value; - - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); - - RETURN_ZVAL(value, 1, 0); + zval rv; } From 493a29ff9cd6df5d4bb26b3c7128153313eb69af Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 22 May 2019 21:40:14 +0200 Subject: [PATCH 02/67] Fixed Uri tests --- config.m4 | 2 ++ http_message.c | 8 +++++++- tests/uri/__construct-001.phpt | 16 ++++++++-------- tests/uri/__construct-002.phpt | 18 +++++++++--------- tests/uri/__construct-003.phpt | 16 ++++++++-------- tests/uri/__construct-004.phpt | 18 +++++++++--------- tests/uri/__construct-005.phpt | 16 ++++++++-------- tests/uri/__construct-006.phpt | 22 +++++++++++----------- tests/uri/__construct-007.phpt | 20 ++++++++++---------- tests/uri/__construct-008.phpt | 18 +++++++++--------- 10 files changed, 81 insertions(+), 73 deletions(-) diff --git a/config.m4 b/config.m4 index 1a4d31f..effe0a6 100644 --- a/config.m4 +++ b/config.m4 @@ -20,4 +20,6 @@ if test "$PHP_HTTP_MESSAGE" != "no"; then $ext_shared) PHP_ADD_EXTENSION_DEP([http_message], [psr], true) + + PHP_ADD_MAKEFILE_FRAGMENT fi diff --git a/http_message.c b/http_message.c index c8463d7..f4cf620 100644 --- a/http_message.c +++ b/http_message.c @@ -40,8 +40,14 @@ #if HAVE_HTTP_MESSAGE +static const zend_module_dep deps[] = { + ZEND_MOD_REQUIRED("psr") +}; + zend_module_entry http_message_module_entry = { - STANDARD_MODULE_HEADER, + STANDARD_MODULE_HEADER_EX, + NULL, + deps, PHP_HTTP_MESSAGE_EXTNAME, NULL, PHP_MINIT(http_message), diff --git a/tests/uri/__construct-001.phpt b/tests/uri/__construct-001.phpt index b4754b2..fe96837 100644 --- a/tests/uri/__construct-001.phpt +++ b/tests/uri/__construct-001.phpt @@ -5,19 +5,19 @@ Create Uri without arguments var_dump(new HttpMessage\Uri()); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(0) "" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => + ["host":protected]=> string(0) "" - protected $port => + ["port":protected]=> NULL - protected $path => + ["path":protected]=> string(0) "" - protected $query => + ["query":protected]=> string(0) "" - protected $fragment => + ["fragment":protected]=> string(0) "" } diff --git a/tests/uri/__construct-002.phpt b/tests/uri/__construct-002.phpt index aa808b6..25079c9 100644 --- a/tests/uri/__construct-002.phpt +++ b/tests/uri/__construct-002.phpt @@ -5,19 +5,19 @@ Create Uri with a basic url var_dump(new HttpMessage\Uri('https://www.example.com/')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(5) "https" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => + ["host":protected]=> string(15) "www.example.com" - protected $port => + ["port":protected]=> NULL - protected $path => - string(1) "/" - protected $query => + ["path":protected]=> string(0) "" - protected $fragment => + ["query":protected]=> + string(0) "" + ["fragment":protected]=> string(0) "" } diff --git a/tests/uri/__construct-003.phpt b/tests/uri/__construct-003.phpt index a80e567..1fbc37a 100644 --- a/tests/uri/__construct-003.phpt +++ b/tests/uri/__construct-003.phpt @@ -5,19 +5,19 @@ Create Uri with a full url var_dump(new HttpMessage\Uri('http://acme@www.example.com:8000/foo?answer=42#question')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(4) "http" - protected $userInfo => + ["userInfo":protected]=> string(4) "acme" - protected $host => + ["host":protected]=> string(15) "www.example.com" - protected $port => + ["port":protected]=> int(8000) - protected $path => + ["path":protected]=> string(4) "/foo" - protected $query => + ["query":protected]=> string(9) "answer=42" - protected $fragment => + ["fragment":protected]=> string(8) "question" } diff --git a/tests/uri/__construct-004.phpt b/tests/uri/__construct-004.phpt index 2ae5049..7d3e8ff 100644 --- a/tests/uri/__construct-004.phpt +++ b/tests/uri/__construct-004.phpt @@ -5,19 +5,19 @@ Create Uri with username and password var_dump(new HttpMessage\Uri('https://acme:secure@www.example.com/')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(5) "https" - protected $userInfo => + ["userInfo":protected]=> string(11) "acme:secure" - protected $host => + ["host":protected]=> string(15) "www.example.com" - protected $port => + ["port":protected]=> NULL - protected $path => - string(1) "/" - protected $query => + ["path":protected]=> string(0) "" - protected $fragment => + ["query":protected]=> + string(0) "" + ["fragment":protected]=> string(0) "" } diff --git a/tests/uri/__construct-005.phpt b/tests/uri/__construct-005.phpt index 5d5dd6c..63a6683 100644 --- a/tests/uri/__construct-005.phpt +++ b/tests/uri/__construct-005.phpt @@ -5,19 +5,19 @@ Create Uri with a basic url without a path var_dump(new HttpMessage\Uri('https://www.example.com/')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(5) "https" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => + ["host":protected]=> string(15) "www.example.com" - protected $port => + ["port":protected]=> NULL - protected $path => + ["path":protected]=> string(0) "" - protected $query => + ["query":protected]=> string(0) "" - protected $fragment => + ["fragment":protected]=> string(0) "" } diff --git a/tests/uri/__construct-006.phpt b/tests/uri/__construct-006.phpt index c67341b..09c478e 100644 --- a/tests/uri/__construct-006.phpt +++ b/tests/uri/__construct-006.phpt @@ -5,19 +5,19 @@ Create Uri with a domain name var_dump(new HttpMessage\Uri('www.example.com')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(0) "" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => - string(0) "www.example.com" - protected $port => - NULL - protected $path => + ["host":protected]=> string(0) "" - protected $query => + ["port":protected]=> + NULL + ["path":protected]=> + string(15) "www.example.com" + ["query":protected]=> string(0) "" - protected $fragment => + ["fragment":protected]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/uri/__construct-007.phpt b/tests/uri/__construct-007.phpt index 8a81592..303af4f 100644 --- a/tests/uri/__construct-007.phpt +++ b/tests/uri/__construct-007.phpt @@ -5,19 +5,19 @@ Create Uri with an absolute path var_dump(new HttpMessage\Uri('/foo')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(0) "" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => + ["host":protected]=> string(0) "" - protected $port => + ["port":protected]=> NULL - protected $path => - string(0) "/foo" - protected $query => + ["path":protected]=> + string(4) "/foo" + ["query":protected]=> string(0) "" - protected $fragment => + ["fragment":protected]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/uri/__construct-008.phpt b/tests/uri/__construct-008.phpt index b3c7d5a..a30eaec 100644 --- a/tests/uri/__construct-008.phpt +++ b/tests/uri/__construct-008.phpt @@ -5,19 +5,19 @@ Create Uri with a relative path var_dump(new HttpMessage\Uri('foo')); ?> --EXPECT-- -class HttpMessage\Uri#1 (7) { - protected $scheme => +object(HttpMessage\Uri)#1 (7) { + ["scheme":protected]=> string(0) "" - protected $userInfo => + ["userInfo":protected]=> string(0) "" - protected $host => + ["host":protected]=> string(0) "" - protected $port => + ["port":protected]=> NULL - protected $path => - string(0) "foo" - protected $query => + ["path":protected]=> + string(3) "foo" + ["query":protected]=> string(0) "" - protected $fragment => + ["fragment":protected]=> string(0) "" } From c9f044873c4a8080ed4bc651cc9d17bb48836cfd Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 22 May 2019 22:09:02 +0200 Subject: [PATCH 03/67] Added missing Makefile.frag --- .gitignore | 1 + Makefile.frag | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 Makefile.frag diff --git a/.gitignore b/.gitignore index 79edfd5..d81a2f5 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ mkinstalldirs run-tests.php Makefile Makefile.* +!Makefile.frag libtool *~ modules/ diff --git a/Makefile.frag b/Makefile.frag new file mode 100644 index 0000000..16dd4cb --- /dev/null +++ b/Makefile.frag @@ -0,0 +1,19 @@ +PHP_TEST_SHARED_EXTENSIONS = ` \ + echo "-d extension=$(EXTENSION_DIR)/psr.so"; \ + if test "x$(PHP_MODULES)" != "x"; then \ + for i in $(PHP_MODULES)""; do \ + . $$i; $(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \ + done; \ + fi; \ + if test "x$(PHP_ZEND_EX)" != "x"; then \ + for i in $(PHP_ZEND_EX)""; do \ + . $$i; $(top_srcdir)/build/shtool echo -n -- " -d $(ZEND_EXT_TYPE)=$(top_builddir)/modules/$$dlname"; \ + done; \ + fi` + +mrproper: clean + rm -rf autom4te.cache build modules vendor + rm -f acinclude.m4 aclocal.m4 config.guess config.h config.h.in config.log config.nice config.status config.sub \ + configure configure.ac install-sh libtool ltmain.sh Makefile Makefile.fragments Makefile.global \ + Makefile.objects missing mkinstalldirs run-tests.php + From a5c8c98459566a197d1986cce0ce57261189db76 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 23 May 2019 05:24:00 +0200 Subject: [PATCH 04/67] Added all tests for Uri class Fixes for Uri class --- phpunit.xml.dist | 16 ---- .../__construct_001.phpt} | 0 .../__construct_002.phpt} | 0 .../__construct_003.phpt} | 0 .../__construct_004.phpt} | 0 .../__construct_005.phpt} | 0 .../__construct_006.phpt} | 0 .../__construct_007.phpt} | 0 .../__construct_008.phpt} | 0 tests/Uri/__construct_error.phpt | 19 +++++ tests/Uri/__toString_001.phpt | 9 ++ tests/Uri/__toString_002.phpt | 9 ++ tests/Uri/__toString_003.phpt | 9 ++ tests/Uri/__toString_004.phpt | 12 +++ tests/Uri/__toString_005.phpt | 10 +++ tests/Uri/__toString_006.phpt | 14 ++++ tests/Uri/__toString_007.phpt | 12 +++ tests/Uri/__toString_008.phpt | 12 +++ tests/Uri/__toString_009.phpt | 11 +++ tests/Uri/authority_001.phpt | 9 ++ tests/Uri/authority_002.phpt | 9 ++ tests/Uri/authority_003.phpt | 10 +++ tests/Uri/fragment_001.phpt | 14 ++++ tests/Uri/fragment_002.phpt | 16 ++++ tests/Uri/fragment_error.phpt | 19 +++++ tests/Uri/host_001.phpt | 10 +++ tests/Uri/host_002.phpt | 16 ++++ tests/Uri/host_error.phpt | 19 +++++ tests/Uri/path_001.phpt | 18 ++++ tests/Uri/path_002.phpt | 22 +++++ tests/Uri/path_error.phpt | 19 +++++ tests/Uri/port_001.phpt | 12 +++ tests/Uri/port_002.phpt | 24 ++++++ tests/Uri/port_error.phpt | 19 +++++ tests/Uri/query_001.phpt | 14 ++++ tests/Uri/query_002.phpt | 16 ++++ tests/Uri/query_error.phpt | 19 +++++ tests/Uri/scheme_001.phpt | 16 ++++ tests/Uri/scheme_002.phpt | 16 ++++ tests/Uri/scheme_error.phpt | 19 +++++ tests/Uri/userInfo_001.phpt | 12 +++ tests/Uri/userInfo_002.phpt | 16 ++++ tests/Uri/userInfo_error.phpt | 19 +++++ uri.c | 84 +++++++++++++++---- 44 files changed, 569 insertions(+), 31 deletions(-) delete mode 100644 phpunit.xml.dist rename tests/{uri/__construct-001.phpt => Uri/__construct_001.phpt} (100%) rename tests/{uri/__construct-002.phpt => Uri/__construct_002.phpt} (100%) rename tests/{uri/__construct-003.phpt => Uri/__construct_003.phpt} (100%) rename tests/{uri/__construct-004.phpt => Uri/__construct_004.phpt} (100%) rename tests/{uri/__construct-005.phpt => Uri/__construct_005.phpt} (100%) rename tests/{uri/__construct-006.phpt => Uri/__construct_006.phpt} (100%) rename tests/{uri/__construct-007.phpt => Uri/__construct_007.phpt} (100%) rename tests/{uri/__construct-008.phpt => Uri/__construct_008.phpt} (100%) create mode 100644 tests/Uri/__construct_error.phpt create mode 100644 tests/Uri/__toString_001.phpt create mode 100644 tests/Uri/__toString_002.phpt create mode 100644 tests/Uri/__toString_003.phpt create mode 100644 tests/Uri/__toString_004.phpt create mode 100644 tests/Uri/__toString_005.phpt create mode 100644 tests/Uri/__toString_006.phpt create mode 100644 tests/Uri/__toString_007.phpt create mode 100644 tests/Uri/__toString_008.phpt create mode 100644 tests/Uri/__toString_009.phpt create mode 100644 tests/Uri/authority_001.phpt create mode 100644 tests/Uri/authority_002.phpt create mode 100644 tests/Uri/authority_003.phpt create mode 100644 tests/Uri/fragment_001.phpt create mode 100644 tests/Uri/fragment_002.phpt create mode 100644 tests/Uri/fragment_error.phpt create mode 100644 tests/Uri/host_001.phpt create mode 100644 tests/Uri/host_002.phpt create mode 100644 tests/Uri/host_error.phpt create mode 100644 tests/Uri/path_001.phpt create mode 100644 tests/Uri/path_002.phpt create mode 100644 tests/Uri/path_error.phpt create mode 100644 tests/Uri/port_001.phpt create mode 100644 tests/Uri/port_002.phpt create mode 100644 tests/Uri/port_error.phpt create mode 100644 tests/Uri/query_001.phpt create mode 100644 tests/Uri/query_002.phpt create mode 100644 tests/Uri/query_error.phpt create mode 100644 tests/Uri/scheme_001.phpt create mode 100644 tests/Uri/scheme_002.phpt create mode 100644 tests/Uri/scheme_error.phpt create mode 100644 tests/Uri/userInfo_001.phpt create mode 100644 tests/Uri/userInfo_002.phpt create mode 100644 tests/Uri/userInfo_error.phpt diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 813111e..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - tests/phpunit/ - - - - diff --git a/tests/uri/__construct-001.phpt b/tests/Uri/__construct_001.phpt similarity index 100% rename from tests/uri/__construct-001.phpt rename to tests/Uri/__construct_001.phpt diff --git a/tests/uri/__construct-002.phpt b/tests/Uri/__construct_002.phpt similarity index 100% rename from tests/uri/__construct-002.phpt rename to tests/Uri/__construct_002.phpt diff --git a/tests/uri/__construct-003.phpt b/tests/Uri/__construct_003.phpt similarity index 100% rename from tests/uri/__construct-003.phpt rename to tests/Uri/__construct_003.phpt diff --git a/tests/uri/__construct-004.phpt b/tests/Uri/__construct_004.phpt similarity index 100% rename from tests/uri/__construct-004.phpt rename to tests/Uri/__construct_004.phpt diff --git a/tests/uri/__construct-005.phpt b/tests/Uri/__construct_005.phpt similarity index 100% rename from tests/uri/__construct-005.phpt rename to tests/Uri/__construct_005.phpt diff --git a/tests/uri/__construct-006.phpt b/tests/Uri/__construct_006.phpt similarity index 100% rename from tests/uri/__construct-006.phpt rename to tests/Uri/__construct_006.phpt diff --git a/tests/uri/__construct-007.phpt b/tests/Uri/__construct_007.phpt similarity index 100% rename from tests/uri/__construct-007.phpt rename to tests/Uri/__construct_007.phpt diff --git a/tests/uri/__construct-008.phpt b/tests/Uri/__construct_008.phpt similarity index 100% rename from tests/uri/__construct-008.phpt rename to tests/Uri/__construct_008.phpt diff --git a/tests/Uri/__construct_error.phpt b/tests/Uri/__construct_error.phpt new file mode 100644 index 0000000..6b60d31 --- /dev/null +++ b/tests/Uri/__construct_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Create Uri errors +--FILE-- + 'https']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\Uri('https://'); +} catch (UnexpectedValueException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Uri::__construct() must be of the type string, array given +Invalid uri diff --git a/tests/Uri/__toString_001.phpt b/tests/Uri/__toString_001.phpt new file mode 100644 index 0000000..88b4d22 --- /dev/null +++ b/tests/Uri/__toString_001.phpt @@ -0,0 +1,9 @@ +--TEST-- +Cast Uri to string with full url +--FILE-- + +--EXPECT-- +string(55) "http://acme:secure@www.example.com:8000/foo?q=42#answer" diff --git a/tests/Uri/__toString_002.phpt b/tests/Uri/__toString_002.phpt new file mode 100644 index 0000000..daee820 --- /dev/null +++ b/tests/Uri/__toString_002.phpt @@ -0,0 +1,9 @@ +--TEST-- +Cast Uri to string without url +--FILE-- + +--EXPECT-- +string(0) "" diff --git a/tests/Uri/__toString_003.phpt b/tests/Uri/__toString_003.phpt new file mode 100644 index 0000000..0703810 --- /dev/null +++ b/tests/Uri/__toString_003.phpt @@ -0,0 +1,9 @@ +--TEST-- +Cast Uri to string with basic url +--FILE-- + +--EXPECT-- +string(24) "https://www.example.com/" diff --git a/tests/Uri/__toString_004.phpt b/tests/Uri/__toString_004.phpt new file mode 100644 index 0000000..f58a217 --- /dev/null +++ b/tests/Uri/__toString_004.phpt @@ -0,0 +1,12 @@ +--TEST-- +Cast Uri to string with only user info and port +--FILE-- +withUserInfo('foo:bar') + ->withPort(8000); + +var_dump((string)$uri); +?> +--EXPECT-- +string(0) "" diff --git a/tests/Uri/__toString_005.phpt b/tests/Uri/__toString_005.phpt new file mode 100644 index 0000000..fe06f1d --- /dev/null +++ b/tests/Uri/__toString_005.phpt @@ -0,0 +1,10 @@ +--TEST-- +Cast Uri to string with paths +--FILE-- + +--EXPECT-- +string(3) "foo" +string(4) "/foo" diff --git a/tests/Uri/__toString_006.phpt b/tests/Uri/__toString_006.phpt new file mode 100644 index 0000000..2e2b0ff --- /dev/null +++ b/tests/Uri/__toString_006.phpt @@ -0,0 +1,14 @@ +--TEST-- +Cast Uri to string with query or fragment +--FILE-- + +--EXPECT-- +string(5) "?q=42" +string(7) "#answer" +string(12) "?q=42#answer" +string(16) "/foo?q=42#answer" diff --git a/tests/Uri/__toString_007.phpt b/tests/Uri/__toString_007.phpt new file mode 100644 index 0000000..107e538 --- /dev/null +++ b/tests/Uri/__toString_007.phpt @@ -0,0 +1,12 @@ +--TEST-- +Cast Uri to string with authority but without schema +--FILE-- +withHost('www.example.com'); + +var_dump((string)$uri); +var_dump((string)($uri->withUserInfo('user:pass'))); +?> +--EXPECT-- +string(17) "//www.example.com" +string(27) "//user:pass@www.example.com" diff --git a/tests/Uri/__toString_008.phpt b/tests/Uri/__toString_008.phpt new file mode 100644 index 0000000..d626603 --- /dev/null +++ b/tests/Uri/__toString_008.phpt @@ -0,0 +1,12 @@ +--TEST-- +Cast Uri to string with authority but without schema +--FILE-- +withPath('/foo'))); +var_dump((string)((new HttpMessage\Uri)->withPath('//foo'))); +var_dump((string)((new HttpMessage\Uri)->withPath('/////foo'))); +?> +--EXPECT-- +string(4) "/foo" +string(4) "/foo" +string(4) "/foo" diff --git a/tests/Uri/__toString_009.phpt b/tests/Uri/__toString_009.phpt new file mode 100644 index 0000000..8d9299b --- /dev/null +++ b/tests/Uri/__toString_009.phpt @@ -0,0 +1,11 @@ +--TEST-- +Cast Uri to string with authority but without schema +--FILE-- +withPath('foo'))); +var_dump((string)($uri->withPath('//foo'))); +?> +--EXPECT-- +string(26) "http://www.example.com/foo" +string(27) "http://www.example.com//foo" diff --git a/tests/Uri/authority_001.phpt b/tests/Uri/authority_001.phpt new file mode 100644 index 0000000..59bc9b7 --- /dev/null +++ b/tests/Uri/authority_001.phpt @@ -0,0 +1,9 @@ +--TEST-- +Uri::getAuthority() +--FILE-- +getAuthority()); +?> +--EXPECT-- +string(32) "acme:secure@www.example.com:8000" diff --git a/tests/Uri/authority_002.phpt b/tests/Uri/authority_002.phpt new file mode 100644 index 0000000..ec9c51e --- /dev/null +++ b/tests/Uri/authority_002.phpt @@ -0,0 +1,9 @@ +--TEST-- +Uri::getAuthority() +--FILE-- +getAuthority()); +?> +--EXPECT-- +string(0) "" diff --git a/tests/Uri/authority_003.phpt b/tests/Uri/authority_003.phpt new file mode 100644 index 0000000..05ead0e --- /dev/null +++ b/tests/Uri/authority_003.phpt @@ -0,0 +1,10 @@ +--TEST-- +Uri::getAuthority() +--FILE-- +getAuthority()); +?> +--EXPECT-- +string(15) "www.example.com" + diff --git a/tests/Uri/fragment_001.phpt b/tests/Uri/fragment_001.phpt new file mode 100644 index 0000000..11c0071 --- /dev/null +++ b/tests/Uri/fragment_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Uri::getFragment() +--FILE-- +getFragment()); +var_dump((new HttpMessage\Uri('http://example.com/#foo'))->getFragment()); +var_dump((new HttpMessage\Uri('#foo'))->getFragment()); +var_dump((new HttpMessage\Uri('?a=1#foo'))->getFragment()); +?> +--EXPECT-- +string(0) "" +string(3) "foo" +string(3) "foo" +string(3) "foo" diff --git a/tests/Uri/fragment_002.phpt b/tests/Uri/fragment_002.phpt new file mode 100644 index 0000000..892e1b4 --- /dev/null +++ b/tests/Uri/fragment_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::withFragment() +--FILE-- +withFragment("foo"); +$bar = $foo->withFragment("!bar"); + +var_dump($blank->getFragment()); +var_dump($foo->getFragment()); +var_dump($bar->getFragment()); +?> +--EXPECT-- +string(0) "" +string(3) "foo" +string(4) "!bar" diff --git a/tests/Uri/fragment_error.phpt b/tests/Uri/fragment_error.phpt new file mode 100644 index 0000000..88a7a65 --- /dev/null +++ b/tests/Uri/fragment_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withFragment() errors +--FILE-- +withFragment(['fragment' => 'foo']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withFragment(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withFragment() expects parameter 1 to be string, array given +HttpMessage\Uri::withFragment() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/host_001.phpt b/tests/Uri/host_001.phpt new file mode 100644 index 0000000..32fd98e --- /dev/null +++ b/tests/Uri/host_001.phpt @@ -0,0 +1,10 @@ +--TEST-- +Uri::getHost() +--FILE-- +getHost()); +var_dump((new HttpMessage\Uri('http://www.example.com/'))->getHost()); +?> +--EXPECT-- +string(0) "" +string(15) "www.example.com" diff --git a/tests/Uri/host_002.phpt b/tests/Uri/host_002.phpt new file mode 100644 index 0000000..af9bae5 --- /dev/null +++ b/tests/Uri/host_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::withHost() +--FILE-- +withHost("www.example.com"); +$dotNet = $dotCom->withHost("www.example.net"); + +var_dump($blank->getHost()); +var_dump($dotCom->getHost()); +var_dump($dotNet->getHost()); +?> +--EXPECT-- +string(0) "" +string(15) "www.example.com" +string(15) "www.example.net" diff --git a/tests/Uri/host_error.phpt b/tests/Uri/host_error.phpt new file mode 100644 index 0000000..b0f660d --- /dev/null +++ b/tests/Uri/host_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withHost() errors +--FILE-- +withHost(['host' => 'www.example.com']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withHost(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withHost() expects parameter 1 to be string, array given +HttpMessage\Uri::withHost() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/path_001.phpt b/tests/Uri/path_001.phpt new file mode 100644 index 0000000..683b6db --- /dev/null +++ b/tests/Uri/path_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +Uri::getPath() +--FILE-- +getPath()); +var_dump((new HttpMessage\Uri('http://example.com/'))->getPath()); +var_dump((new HttpMessage\Uri('http://example.com/'))->getPath()); +var_dump((new HttpMessage\Uri('http://example.com/foo'))->getPath()); +var_dump((new HttpMessage\Uri('/'))->getPath()); +var_dump((new HttpMessage\Uri('/foo'))->getPath()); +?> +--EXPECT-- +string(0) "" +string(0) "" +string(1) "/" +string(4) "/foo" +string(1) "/" +string(4) "/foo" diff --git a/tests/Uri/path_002.phpt b/tests/Uri/path_002.phpt new file mode 100644 index 0000000..dc24c83 --- /dev/null +++ b/tests/Uri/path_002.phpt @@ -0,0 +1,22 @@ +--TEST-- +Uri::withPath() +--FILE-- +withPath("/"); +$absolute = $root->withPath("/foo"); +$relative = $absolute->withPath("foo"); +$double = $absolute->withPath("//foo"); + +var_dump($blank->getPath()); +var_dump($root->getPath()); +var_dump($absolute->getPath()); +var_dump($relative->getPath()); +var_dump($double->getPath()); +?> +--EXPECT-- +string(0) "" +string(1) "/" +string(4) "/foo" +string(3) "foo" +string(5) "//foo" diff --git a/tests/Uri/path_error.phpt b/tests/Uri/path_error.phpt new file mode 100644 index 0000000..77943e1 --- /dev/null +++ b/tests/Uri/path_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withPath() errors +--FILE-- +withPath(['path' => '/foo']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withPath(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withPath() expects parameter 1 to be string, array given +HttpMessage\Uri::withPath() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/port_001.phpt b/tests/Uri/port_001.phpt new file mode 100644 index 0000000..3ac26ab --- /dev/null +++ b/tests/Uri/port_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::getPort() +--FILE-- +getPort()); +var_dump((new HttpMessage\Uri('http://www.example.com/'))->getPort()); +var_dump((new HttpMessage\Uri('http://www.example.com/'))->getPort()); +?> +--EXPECT-- +NULL +NULL +int(80) diff --git a/tests/Uri/port_002.phpt b/tests/Uri/port_002.phpt new file mode 100644 index 0000000..b4e40ff --- /dev/null +++ b/tests/Uri/port_002.phpt @@ -0,0 +1,24 @@ +--TEST-- +Uri::withPort() +--FILE-- +withPort(80); +$port8000 = $port80->withPort(8000); +$noPort = $port80->withPort(null); + +var_dump($blank->getPort()); +var_dump($port80->getPort()); +var_dump($port8000->getPort()); +var_dump($noPort->getPort()); + +var_dump((string)$port80); +var_dump((string)$noPort); +?> +--EXPECT-- +NULL +int(80) +int(8000) +NULL +string(21) "http://example.com/" +string(18) "http://example.com/" \ No newline at end of file diff --git a/tests/Uri/port_error.phpt b/tests/Uri/port_error.phpt new file mode 100644 index 0000000..0a01b32 --- /dev/null +++ b/tests/Uri/port_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withPort() errors +--FILE-- +withPort(['port' => 80]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withPort(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withPort() expects parameter 1 to be integer, array given +HttpMessage\Uri::withPort() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/query_001.phpt b/tests/Uri/query_001.phpt new file mode 100644 index 0000000..88bfacb --- /dev/null +++ b/tests/Uri/query_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Uri::getQuery() +--FILE-- +getQuery()); +var_dump((new HttpMessage\Uri('http://example.com/?foo=1&bar=2'))->getQuery()); +var_dump((new HttpMessage\Uri('?foo=1&bar=2'))->getQuery()); +var_dump((new HttpMessage\Uri('https://www.example.com/'))->getQuery()); +?> +--EXPECT-- +string(0) "" +string(11) "foo=1&bar=2" +string(11) "foo=1&bar=2" +string(0) "" diff --git a/tests/Uri/query_002.phpt b/tests/Uri/query_002.phpt new file mode 100644 index 0000000..2f92b8d --- /dev/null +++ b/tests/Uri/query_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::withQuery() +--FILE-- +withQuery("foo=1"); +$fooBar = $foo->withQuery("foo=1&bar=2"); + +var_dump($blank->getQuery()); +var_dump($foo->getQuery()); +var_dump($fooBar->getQuery()); +?> +--EXPECT-- +string(0) "" +string(5) "foo=1" +string(11) "foo=1&bar=2" diff --git a/tests/Uri/query_error.phpt b/tests/Uri/query_error.phpt new file mode 100644 index 0000000..969f603 --- /dev/null +++ b/tests/Uri/query_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withQuery() errors +--FILE-- +withQuery(['foo' => 1]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withQuery(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withQuery() expects parameter 1 to be string, array given +HttpMessage\Uri::withQuery() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/scheme_001.phpt b/tests/Uri/scheme_001.phpt new file mode 100644 index 0000000..12485b3 --- /dev/null +++ b/tests/Uri/scheme_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::getScheme() +--FILE-- +getScheme()); +var_dump((new HttpMessage\Uri('http:'))->getScheme()); +var_dump((new HttpMessage\Uri('mailto:john@example.com'))->getScheme()); +var_dump((new HttpMessage\Uri('https://www.example.com/'))->getScheme()); +var_dump((new HttpMessage\Uri('ftp://www.example.com'))->getScheme()); +?> +--EXPECT-- +string(0) "" +string(4) "http" +string(6) "mailto" +string(5) "https" +string(3) "ftp" diff --git a/tests/Uri/scheme_002.phpt b/tests/Uri/scheme_002.phpt new file mode 100644 index 0000000..dddb322 --- /dev/null +++ b/tests/Uri/scheme_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::withScheme() +--FILE-- +withScheme("https"); +$mailto = $https->withScheme("mailto"); + +var_dump($blank->getScheme()); +var_dump($https->getScheme()); +var_dump($mailto->getScheme()); +?> +--EXPECT-- +string(0) "" +string(5) "https" +string(6) "mailto" diff --git a/tests/Uri/scheme_error.phpt b/tests/Uri/scheme_error.phpt new file mode 100644 index 0000000..f2e387b --- /dev/null +++ b/tests/Uri/scheme_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withHost() errors +--FILE-- +withScheme(['scheme' => 'http']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withScheme(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withScheme() expects parameter 1 to be string, array given +HttpMessage\Uri::withScheme() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/userInfo_001.phpt b/tests/Uri/userInfo_001.phpt new file mode 100644 index 0000000..e361643 --- /dev/null +++ b/tests/Uri/userInfo_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::getUserInfo() +--FILE-- +getUserInfo()); +var_dump((new HttpMessage\Uri('http://user@www.example.com/'))->getUserInfo()); +var_dump((new HttpMessage\Uri('http://user:pass@www.example.com/'))->getUserInfo()); +?> +--EXPECT-- +string(0) "" +string(4) "user" +string(9) "user:pass" diff --git a/tests/Uri/userInfo_002.phpt b/tests/Uri/userInfo_002.phpt new file mode 100644 index 0000000..691ba6c --- /dev/null +++ b/tests/Uri/userInfo_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Uri::withScheme() +--FILE-- +withUserInfo("user"); +$userPass = $user->withUserInfo("user:pass"); + +var_dump($blank->getUserInfo()); +var_dump($user->getUserInfo()); +var_dump($userPass->getUserInfo()); +?> +--EXPECT-- +string(0) "" +string(4) "user" +string(9) "user:pass" diff --git a/tests/Uri/userInfo_error.phpt b/tests/Uri/userInfo_error.phpt new file mode 100644 index 0000000..1c9e751 --- /dev/null +++ b/tests/Uri/userInfo_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Uri::withUserInfo() errors +--FILE-- +withUserInfo(['userInfo' => 'user']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + (new HttpMessage\Uri)->withUserInfo(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withUserInfo() expects parameter 1 to be string, array given +HttpMessage\Uri::withUserInfo() expects exactly 1 parameter, 0 given diff --git a/uri.c b/uri.c index c824c64..900f7a1 100644 --- a/uri.c +++ b/uri.c @@ -41,6 +41,7 @@ #include "ext/standard/info.h" #include "ext/standard/url.h" #include "ext/psr/psr_http_message.h" +#include "ext/spl/spl_exceptions.h" #if HAVE_HTTP_MESSAGE @@ -66,6 +67,11 @@ PHP_METHOD(Uri, __construct) if (value_len > 0) { info = php_url_parse_ex(value, value_len); + if (info == NULL) { + zend_throw_exception(spl_ce_UnexpectedValueException, "Invalid uri", 0); + return; + } + SET_STRING_PROPERTY(HttpMessage_Uri_ce, "scheme", info->scheme); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "host", info->host); SET_STRING_PROPERTY(HttpMessage_Uri_ce, "path", info->path); @@ -97,6 +103,8 @@ PHP_METHOD(Uri, __toString) { zval rv, *scheme, *userinfo, *host, *port, *path, *query, *fragment; smart_str buf = {0}; + char *path_ptr; + size_t path_len = 0; scheme = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("scheme"), 0, &rv); userinfo = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); @@ -106,6 +114,8 @@ PHP_METHOD(Uri, __toString) query = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("query"), 0, &rv); fragment = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("fragment"), 0, &rv); + smart_str_alloc(&buf, 0, 0); + if (Z_STRLEN(*scheme) > 0) { smart_str_appendl(&buf, Z_STRVAL(*scheme), Z_STRLEN(*scheme)); smart_str_appends(&buf, ":"); @@ -127,8 +137,23 @@ PHP_METHOD(Uri, __toString) } } - // Todo sanitize path - smart_str_appendl(&buf, Z_STRVAL(*path), Z_STRLEN(*path)); + if (Z_STRLEN(*path) > 0) { + if (Z_STRLEN(*host) > 0 && *Z_STRVAL(*path) != '/') { + smart_str_appends(&buf, "/"); + } + + path_ptr = Z_STRVAL(*path); + path_len = Z_STRLEN(*path); + + if (Z_STRLEN(*host) == 0) { + while (path_len > 1 && *path_ptr == '/' && *(path_ptr + 1) == '/') { + path_ptr++; + path_len--; + } + } + + smart_str_appendl(&buf, path_ptr, path_len); + } if (Z_STRLEN(*query) > 0) { smart_str_appends(&buf, "?"); @@ -151,7 +176,7 @@ PHP_METHOD(Uri, getScheme) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("schema"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("scheme"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -163,11 +188,11 @@ PHP_METHOD(Uri, withScheme) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("schema"), value, value_len); + zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("scheme"), value, value_len); } @@ -175,7 +200,31 @@ PHP_METHOD(Uri, withScheme) PHP_METHOD(Uri, getAuthority) { - zval rv; + zval rv, *userinfo, *host, *port; + smart_str buf = {0}; + + userinfo = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); + host = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); + port = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); + + if (Z_STRLEN(*host) == 0) { + RETURN_EMPTY_STRING(); + } + + if (Z_STRLEN(*userinfo) > 0) { + smart_str_appendl(&buf, Z_STRVAL(*userinfo), Z_STRLEN(*userinfo)); + smart_str_appends(&buf, "@"); + } + + smart_str_appendl(&buf, Z_STRVAL(*host), Z_STRLEN(*host)); + + if (Z_TYPE(*port) == IS_LONG) { + smart_str_appends(&buf, ":"); + smart_str_append_long(&buf, Z_LVAL(*port)); + } + + RETVAL_STR_COPY(buf.s); + zend_string_release(buf.s); } @@ -197,7 +246,7 @@ PHP_METHOD(Uri, withUserInfo) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -223,7 +272,7 @@ PHP_METHOD(Uri, withHost) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -245,14 +294,19 @@ PHP_METHOD(Uri, getPort) PHP_METHOD(Uri, withPort) { long value; + zend_bool is_null; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_LONG(value) - ZEND_PARSE_PARAMETERS_END_EX(); + Z_PARAM_LONG_EX(value, is_null, 1, 0) + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_long(HttpMessage_Uri_ce, return_value, ZEND_STRL("port"), value); + if (is_null) { + zend_update_property_null(HttpMessage_Uri_ce, return_value, ZEND_STRL("port")); + } else { + zend_update_property_long(HttpMessage_Uri_ce, return_value, ZEND_STRL("port"), value); + } } @@ -274,7 +328,7 @@ PHP_METHOD(Uri, withPath) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -300,7 +354,7 @@ PHP_METHOD(Uri, withQuery) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -308,7 +362,7 @@ PHP_METHOD(Uri, withQuery) } -/* query */ +/* fragment */ PHP_METHOD(Uri, getFragment) { @@ -326,7 +380,7 @@ PHP_METHOD(Uri, withFragment) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); From be4a68b4d55d933f4eae29c06b8be9d2963dfd19 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 29 May 2019 05:54:53 +0200 Subject: [PATCH 05/67] Split up error tests --- tests/Stream/__construct_001.phpt | 0 tests/Stream/__construct_002.phpt | 29 +++++++++++++++++++ tests/Stream/__construct_err01.phpt | 16 ++++++++++ ...ruct_error.phpt => __construct_err01.phpt} | 9 +----- tests/Uri/__construct_err02.phpt | 12 ++++++++ ...ragment_error.phpt => fragment_err01.phpt} | 9 +----- tests/Uri/fragment_err02.phpt | 12 ++++++++ .../Uri/{path_error.phpt => path_err01.phpt} | 9 +----- tests/Uri/path_err02.phpt | 12 ++++++++ .../Uri/{port_error.phpt => port_err01.phpt} | 9 +----- tests/Uri/port_err02.phpt | 12 ++++++++ .../{query_error.phpt => query_err01.phpt} | 9 +----- tests/Uri/query_err02.phpt | 12 ++++++++ .../{scheme_error.phpt => scheme_err01.phpt} | 9 +----- tests/Uri/scheme_err02.phpt | 12 ++++++++ ...serInfo_error.phpt => userInfo_err01.phpt} | 9 +----- tests/Uri/userInfo_err02.phpt | 12 ++++++++ 17 files changed, 136 insertions(+), 56 deletions(-) create mode 100644 tests/Stream/__construct_001.phpt create mode 100644 tests/Stream/__construct_002.phpt create mode 100644 tests/Stream/__construct_err01.phpt rename tests/Uri/{__construct_error.phpt => __construct_err01.phpt} (62%) create mode 100644 tests/Uri/__construct_err02.phpt rename tests/Uri/{fragment_error.phpt => fragment_err01.phpt} (54%) create mode 100644 tests/Uri/fragment_err02.phpt rename tests/Uri/{path_error.phpt => path_err01.phpt} (55%) create mode 100644 tests/Uri/path_err02.phpt rename tests/Uri/{port_error.phpt => port_err01.phpt} (54%) create mode 100644 tests/Uri/port_err02.phpt rename tests/Uri/{query_error.phpt => query_err01.phpt} (54%) create mode 100644 tests/Uri/query_err02.phpt rename tests/Uri/{scheme_error.phpt => scheme_err01.phpt} (55%) create mode 100644 tests/Uri/scheme_err02.phpt rename tests/Uri/{userInfo_error.phpt => userInfo_err01.phpt} (55%) create mode 100644 tests/Uri/userInfo_err02.phpt diff --git a/tests/Stream/__construct_001.phpt b/tests/Stream/__construct_001.phpt new file mode 100644 index 0000000..e69de29 diff --git a/tests/Stream/__construct_002.phpt b/tests/Stream/__construct_002.phpt new file mode 100644 index 0000000..2ece024 --- /dev/null +++ b/tests/Stream/__construct_002.phpt @@ -0,0 +1,29 @@ +--TEST-- +Create Stream without arguments +--FILE-- +detach(); +var_dump(stream_get_meta_data($resource)); +?> +--EXPECTF-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(%d) of type (stream) +} +array(6) { + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(4) "TEMP" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(10) "php://temp" +} \ No newline at end of file diff --git a/tests/Stream/__construct_err01.phpt b/tests/Stream/__construct_err01.phpt new file mode 100644 index 0000000..f673d18 --- /dev/null +++ b/tests/Stream/__construct_err01.phpt @@ -0,0 +1,16 @@ +--TEST-- +Create Stream with resource +--FILE-- +detach() === $resource); +?> +--EXPECTF-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(%d) of type (stream) +} +bool(true) \ No newline at end of file diff --git a/tests/Uri/__construct_error.phpt b/tests/Uri/__construct_err01.phpt similarity index 62% rename from tests/Uri/__construct_error.phpt rename to tests/Uri/__construct_err01.phpt index 6b60d31..240e680 100644 --- a/tests/Uri/__construct_error.phpt +++ b/tests/Uri/__construct_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Create Uri errors +Create Uri error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - new HttpMessage\Uri('https://'); -} catch (UnexpectedValueException $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- Argument 1 passed to HttpMessage\Uri::__construct() must be of the type string, array given -Invalid uri diff --git a/tests/Uri/__construct_err02.phpt b/tests/Uri/__construct_err02.phpt new file mode 100644 index 0000000..46115ea --- /dev/null +++ b/tests/Uri/__construct_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Create Uri error: Invalid uri +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Invalid uri diff --git a/tests/Uri/fragment_error.phpt b/tests/Uri/fragment_err01.phpt similarity index 54% rename from tests/Uri/fragment_error.phpt rename to tests/Uri/fragment_err01.phpt index 88a7a65..d6f4503 100644 --- a/tests/Uri/fragment_error.phpt +++ b/tests/Uri/fragment_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withFragment() errors +Uri::withFragment() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withFragment(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withFragment() expects parameter 1 to be string, array given -HttpMessage\Uri::withFragment() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/fragment_err02.phpt b/tests/Uri/fragment_err02.phpt new file mode 100644 index 0000000..8e52621 --- /dev/null +++ b/tests/Uri/fragment_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withFragment() error: missing argument +--FILE-- +withFragment(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withFragment() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/path_error.phpt b/tests/Uri/path_err01.phpt similarity index 55% rename from tests/Uri/path_error.phpt rename to tests/Uri/path_err01.phpt index 77943e1..a8c0c55 100644 --- a/tests/Uri/path_error.phpt +++ b/tests/Uri/path_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withPath() errors +Uri::withPath() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withPath(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withPath() expects parameter 1 to be string, array given -HttpMessage\Uri::withPath() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/path_err02.phpt b/tests/Uri/path_err02.phpt new file mode 100644 index 0000000..c588d02 --- /dev/null +++ b/tests/Uri/path_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withPath() error: missing argument +--FILE-- +withPath(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withPath() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/port_error.phpt b/tests/Uri/port_err01.phpt similarity index 54% rename from tests/Uri/port_error.phpt rename to tests/Uri/port_err01.phpt index 0a01b32..66788d3 100644 --- a/tests/Uri/port_error.phpt +++ b/tests/Uri/port_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withPort() errors +Uri::withPort() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withPort(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withPort() expects parameter 1 to be integer, array given -HttpMessage\Uri::withPort() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/port_err02.phpt b/tests/Uri/port_err02.phpt new file mode 100644 index 0000000..f50945c --- /dev/null +++ b/tests/Uri/port_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withPort() error: missing argument +--FILE-- +withPort(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withPort() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/query_error.phpt b/tests/Uri/query_err01.phpt similarity index 54% rename from tests/Uri/query_error.phpt rename to tests/Uri/query_err01.phpt index 969f603..b1e084d 100644 --- a/tests/Uri/query_error.phpt +++ b/tests/Uri/query_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withQuery() errors +Uri::withQuery() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withQuery(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withQuery() expects parameter 1 to be string, array given -HttpMessage\Uri::withQuery() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/query_err02.phpt b/tests/Uri/query_err02.phpt new file mode 100644 index 0000000..c0fb791 --- /dev/null +++ b/tests/Uri/query_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withQuery() error: missing argument +--FILE-- +withQuery(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withQuery() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/scheme_error.phpt b/tests/Uri/scheme_err01.phpt similarity index 55% rename from tests/Uri/scheme_error.phpt rename to tests/Uri/scheme_err01.phpt index f2e387b..8530982 100644 --- a/tests/Uri/scheme_error.phpt +++ b/tests/Uri/scheme_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withHost() errors +Uri::withHost() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withScheme(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withScheme() expects parameter 1 to be string, array given -HttpMessage\Uri::withScheme() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/scheme_err02.phpt b/tests/Uri/scheme_err02.phpt new file mode 100644 index 0000000..71f1c24 --- /dev/null +++ b/tests/Uri/scheme_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withHost() error: missing argument +--FILE-- +withScheme(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withScheme() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/userInfo_error.phpt b/tests/Uri/userInfo_err01.phpt similarity index 55% rename from tests/Uri/userInfo_error.phpt rename to tests/Uri/userInfo_err01.phpt index 1c9e751..ca4499c 100644 --- a/tests/Uri/userInfo_error.phpt +++ b/tests/Uri/userInfo_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Uri::withUserInfo() errors +Uri::withUserInfo() error: invalid argument --FILE-- getMessage(), "\n"; } - -try { - (new HttpMessage\Uri)->withUserInfo(); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} ?> --EXPECT-- HttpMessage\Uri::withUserInfo() expects parameter 1 to be string, array given -HttpMessage\Uri::withUserInfo() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/userInfo_err02.phpt b/tests/Uri/userInfo_err02.phpt new file mode 100644 index 0000000..93409dd --- /dev/null +++ b/tests/Uri/userInfo_err02.phpt @@ -0,0 +1,12 @@ +--TEST-- +Uri::withUserInfo() error: missing argument +--FILE-- +withUserInfo(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Uri::withUserInfo() expects exactly 1 parameter, 0 given From 16c4c3669dc1e48cd3f25ff865683caa2b88d7c7 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 30 May 2019 00:14:39 +0200 Subject: [PATCH 06/67] Stream tests and fixes (WIP) --- macros.h | 5 ++++ stream.c | 39 +++++++++++++++++------------ tests/Stream/__construct_001.phpt | 16 ++++++++++++ tests/Stream/__construct_err01.phpt | 19 +++++++------- tests/Stream/close_001.phpt | 20 +++++++++++++++ tests/Stream/close_002.phpt | 22 ++++++++++++++++ tests/Stream/detach_001.phpt | 25 ++++++++++++++++++ tests/Stream/eof_001.phpt | 31 +++++++++++++++++++++++ tests/Stream/eof_002.phpt | 16 ++++++++++++ tests/Stream/eof_003.phpt | 16 ++++++++++++ tests/Stream/getSize_001.phpt | 31 +++++++++++++++++++++++ tests/Stream/getSize_002.phpt | 16 ++++++++++++ tests/Stream/isSeekable_001.phpt | 13 ++++++++++ tests/Stream/isSeekable_002.phpt | 13 ++++++++++ tests/Stream/isSeekable_003.phpt | 13 ++++++++++ tests/Stream/tell_001.phpt | 27 ++++++++++++++++++++ tests/Stream/tell_err01.phpt | 17 +++++++++++++ tests/Stream/tell_err02.phpt | 17 +++++++++++++ 18 files changed, 330 insertions(+), 26 deletions(-) create mode 100644 tests/Stream/close_001.phpt create mode 100644 tests/Stream/close_002.phpt create mode 100644 tests/Stream/detach_001.phpt create mode 100644 tests/Stream/eof_001.phpt create mode 100644 tests/Stream/eof_002.phpt create mode 100644 tests/Stream/eof_003.phpt create mode 100644 tests/Stream/getSize_001.phpt create mode 100644 tests/Stream/getSize_002.phpt create mode 100644 tests/Stream/isSeekable_001.phpt create mode 100644 tests/Stream/isSeekable_002.phpt create mode 100644 tests/Stream/isSeekable_003.phpt create mode 100644 tests/Stream/tell_001.phpt create mode 100644 tests/Stream/tell_err01.phpt create mode 100644 tests/Stream/tell_err02.phpt diff --git a/macros.h b/macros.h index 6066ba8..35d02ff 100644 --- a/macros.h +++ b/macros.h @@ -45,5 +45,10 @@ ZEND_END_ARG_INFO() #define HTTP_MESSAGE_ME(className, method) \ PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) +#define IS_STREAM_RESOURCE(zstream) \ + ( \ + Z_TYPE_P(zstream) == IS_RESOURCE && \ + (Z_RES_P(zstream)->type == php_file_le_stream() || Z_RES_P(zstream)->type == php_file_le_pstream()) \ + ) #endif //HTTP_MESSAGE_MACROS_H diff --git a/stream.c b/stream.c index 976c976..3a2d722 100644 --- a/stream.c +++ b/stream.c @@ -58,12 +58,12 @@ zend_bool string_contains_char(char *haystack, char chr) /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageStream_construct, 0, 0, 0) - ZEND_ARG_TYPE_INFO(0, uri, IS_RESOURCE, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_RESOURCE, 0) ZEND_END_ARG_INFO() PHP_METHOD(Stream, __construct) { - zval rv, *zstream = NULL, newstream; + zval *zstream = NULL, newstream; php_stream *stream; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) @@ -72,13 +72,17 @@ PHP_METHOD(Stream, __construct) ZEND_PARSE_PARAMETERS_END_EX(); if (zstream == NULL) { - RETURN_NULL(); + stream = php_stream_open_wrapper("php://temp", "w+", 0, NULL); + + if (stream == NULL) { + zend_throw_error(NULL, "Failed to open 'php://temp' stream"); + return; + } - stream = php_stream_fopen("php://temp", "r+", NULL); - ZVAL_RES(&newstream, (stream)->res); // php_stream_to_zval(stream, &newstream); // segfault ? + php_stream_to_zval(stream, &newstream); zstream = &newstream; - } else if (Z_RES_P(zstream)->type != php_file_le_stream() && Z_RES_P(zstream)->type != php_file_le_pstream()) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Resource is not a stream"); + } else if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Resource is not a stream"); } zend_update_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), zstream); @@ -95,11 +99,13 @@ PHP_METHOD(Stream, close) zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); if (Z_TYPE_P(zstream) != IS_RESOURCE) { - RETURN_NULL(); + return; } - php_stream_from_zval(stream, zstream); - php_stream_close(stream); + if (IS_STREAM_RESOURCE(zstream)) { + php_stream_from_zval(stream, zstream); + php_stream_close(stream); + } } PHP_METHOD(Stream, detach) @@ -107,10 +113,9 @@ PHP_METHOD(Stream, detach) zval rv, *zstream; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + ZVAL_COPY(return_value, zstream); zend_update_property_null(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream")); - - RETURN_ZVAL(zstream, 1, 0); } PHP_METHOD(Stream, getSize) @@ -120,7 +125,7 @@ PHP_METHOD(Stream, getSize) php_stream_statbuf ssb; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + if (!IS_STREAM_RESOURCE(zstream)) { RETURN_NULL(); } @@ -137,8 +142,10 @@ PHP_METHOD(Stream, tell) size_t pos; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "The stream has been detached"); + if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "The stream has been %s", + Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + return; } php_stream_from_zval(stream, zstream); @@ -154,7 +161,7 @@ PHP_METHOD(Stream, eof) zend_bool eof; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + if (!IS_STREAM_RESOURCE(zstream)) { RETURN_TRUE; } diff --git a/tests/Stream/__construct_001.phpt b/tests/Stream/__construct_001.phpt index e69de29..f673d18 100644 --- a/tests/Stream/__construct_001.phpt +++ b/tests/Stream/__construct_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +Create Stream with resource +--FILE-- +detach() === $resource); +?> +--EXPECTF-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(%d) of type (stream) +} +bool(true) \ No newline at end of file diff --git a/tests/Stream/__construct_err01.phpt b/tests/Stream/__construct_err01.phpt index f673d18..826145a 100644 --- a/tests/Stream/__construct_err01.phpt +++ b/tests/Stream/__construct_err01.phpt @@ -1,16 +1,15 @@ --TEST-- -Create Stream with resource +Create Stream error: closed stream --FILE-- detach() === $resource); -?> ---EXPECTF-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> - resource(%d) of type (stream) +try { + new HttpMessage\Stream($resource); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(); } -bool(true) \ No newline at end of file +?> +--EXPECT-- +Resource is not a stream diff --git a/tests/Stream/close_001.phpt b/tests/Stream/close_001.phpt new file mode 100644 index 0000000..946c19f --- /dev/null +++ b/tests/Stream/close_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +Stream::close() +--FILE-- +close(); +var_dump($stream); + +var_dump(get_resource_type($resource)); + +$stream->close(); // No error +?> +--EXPECT-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(5) of type (Unknown) +} +string(7) "Unknown" diff --git a/tests/Stream/close_002.phpt b/tests/Stream/close_002.phpt new file mode 100644 index 0000000..2074228 --- /dev/null +++ b/tests/Stream/close_002.phpt @@ -0,0 +1,22 @@ +--TEST-- +Stream::close() on already closed +--FILE-- +close(); +var_dump($stream); +?> +--EXPECTF-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(%d) of type (Unknown) +} +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + resource(%d) of type (Unknown) +} \ No newline at end of file diff --git a/tests/Stream/detach_001.phpt b/tests/Stream/detach_001.phpt new file mode 100644 index 0000000..7a21d83 --- /dev/null +++ b/tests/Stream/detach_001.phpt @@ -0,0 +1,25 @@ +--TEST-- +Stream::detach() +--FILE-- +detach(); +var_dump($stream); + +var_dump($ret === $resource); +var_dump(get_resource_type($resource)); + +var_dump($stream->detach()); + +$stream->close(); // Calling close() while detached should be ignored +?> +--EXPECT-- +object(HttpMessage\Stream)#1 (1) { + ["stream":protected]=> + NULL +} +bool(true) +string(6) "stream" +NULL diff --git a/tests/Stream/eof_001.phpt b/tests/Stream/eof_001.phpt new file mode 100644 index 0000000..4638a3e --- /dev/null +++ b/tests/Stream/eof_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +Stream::eof() +--FILE-- +eof()); + +fread($resource, 1); +var_dump($stream->eof()); + +fwrite($resource, "abcdef"); +var_dump($stream->eof()); + +fseek($resource, 0); +var_dump($stream->eof()); + +fread($resource, 3); +var_dump($stream->eof()); + +fread($resource, 4); +var_dump($stream->eof()); +?> +--EXPECT-- +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) +bool(true) diff --git a/tests/Stream/eof_002.phpt b/tests/Stream/eof_002.phpt new file mode 100644 index 0000000..d532f04 --- /dev/null +++ b/tests/Stream/eof_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::eof() +--FILE-- +eof()); + +fclose($resource); +var_dump($stream->eof()); + +?> +--EXPECT-- +bool(false) +bool(true) diff --git a/tests/Stream/eof_003.phpt b/tests/Stream/eof_003.phpt new file mode 100644 index 0000000..a01a589 --- /dev/null +++ b/tests/Stream/eof_003.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::eof() +--FILE-- +eof()); + +$stream->detach(); +var_dump($stream->eof()); + +?> +--EXPECT-- +bool(false) +bool(true) diff --git a/tests/Stream/getSize_001.phpt b/tests/Stream/getSize_001.phpt new file mode 100644 index 0000000..9f9e7eb --- /dev/null +++ b/tests/Stream/getSize_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +Stream::getSize() +--FILE-- +getSize()); + +fwrite($resource, "abcdef"); +var_dump($stream->getSize()); + +fwrite($resource, "ghi"); +var_dump($stream->getSize()); + +fseek($resource, 0); +var_dump($stream->getSize()); + +fwrite($resource, "1234567890abcdef"); +var_dump($stream->getSize()); + +fclose($resource); +var_dump($stream->getSize()); +?> +--EXPECT-- +int(0) +int(6) +int(9) +int(9) +int(16) +NULL diff --git a/tests/Stream/getSize_002.phpt b/tests/Stream/getSize_002.phpt new file mode 100644 index 0000000..09dbf52 --- /dev/null +++ b/tests/Stream/getSize_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::getSize() with detached stream +--FILE-- +getSize()); + +$stream->detach(); +var_dump($stream->getSize()); +?> +--EXPECT-- +int(6) +NULL diff --git a/tests/Stream/isSeekable_001.phpt b/tests/Stream/isSeekable_001.phpt new file mode 100644 index 0000000..8d0628f --- /dev/null +++ b/tests/Stream/isSeekable_001.phpt @@ -0,0 +1,13 @@ +--TEST-- +Stream::isSeekable() +--FILE-- +isSeekable()); + +$unseekableStream = new HttpMessage\Stream(fopen('php://stdin', 'r')); +var_dump($unseekableStream->isSeekable()); +?> +--EXPECT-- +bool(true) +bool(false) diff --git a/tests/Stream/isSeekable_002.phpt b/tests/Stream/isSeekable_002.phpt new file mode 100644 index 0000000..20aea2c --- /dev/null +++ b/tests/Stream/isSeekable_002.phpt @@ -0,0 +1,13 @@ +--TEST-- +Stream::isSeekable() with detached stream +--FILE-- +isSeekable()); + +$stream->detach(); +var_dump($stream->isSeekable()); +?> +--EXPECT-- +bool(true) +bool(false) diff --git a/tests/Stream/isSeekable_003.phpt b/tests/Stream/isSeekable_003.phpt new file mode 100644 index 0000000..20aea2c --- /dev/null +++ b/tests/Stream/isSeekable_003.phpt @@ -0,0 +1,13 @@ +--TEST-- +Stream::isSeekable() with detached stream +--FILE-- +isSeekable()); + +$stream->detach(); +var_dump($stream->isSeekable()); +?> +--EXPECT-- +bool(true) +bool(false) diff --git a/tests/Stream/tell_001.phpt b/tests/Stream/tell_001.phpt new file mode 100644 index 0000000..c0413b6 --- /dev/null +++ b/tests/Stream/tell_001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Stream::tell() +--FILE-- +tell()); + +fwrite($resource, "abcdef"); +var_dump($stream->tell()); + +fwrite($resource, "ghi"); +var_dump($stream->tell()); + +fseek($resource, 0); +var_dump($stream->tell()); + +fwrite($resource, "1234567890abcdef"); +var_dump($stream->tell()); +?> +--EXPECT-- +int(0) +int(6) +int(9) +int(0) +int(16) diff --git a/tests/Stream/tell_err01.phpt b/tests/Stream/tell_err01.phpt new file mode 100644 index 0000000..d1e2a7b --- /dev/null +++ b/tests/Stream/tell_err01.phpt @@ -0,0 +1,17 @@ +--TEST-- +Stream::tell() error: detached stream +--FILE-- +detach(); + +try { + $stream->tell(); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +The stream has been detached diff --git a/tests/Stream/tell_err02.phpt b/tests/Stream/tell_err02.phpt new file mode 100644 index 0000000..f7e8986 --- /dev/null +++ b/tests/Stream/tell_err02.phpt @@ -0,0 +1,17 @@ +--TEST-- +Stream::tell() error: closed stream +--FILE-- +tell(); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +The stream has been closed From d722368ccd6e42935511ea80c0adce50f63252da Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 30 May 2019 14:02:09 +0200 Subject: [PATCH 07/67] Stream tests and fixes around meta data (WIP) --- stream.c | 52 ++++++++++++++----- tests/Stream/close_003.phpt | 49 +++++++++++++++++ tests/Stream/detach_002.phpt | 50 ++++++++++++++++++ tests/Stream/eof_002.phpt | 2 +- tests/Stream/getMetadata_001.phpt | 31 +++++++++++ tests/Stream/getMetadata_002.phpt | 17 ++++++ tests/Stream/getSize_002.phpt | 16 ------ tests/Stream/isReadable_001.phpt | 9 ++++ tests/Stream/isReadable_002.phpt | 11 ++++ tests/Stream/isSeekable_001.phpt | 10 ++-- tests/Stream/isSeekable_002.phpt | 8 +-- tests/Stream/isSeekable_003.phpt | 13 ----- tests/Stream/isWritable_001.phpt | 11 ++++ tests/Stream/isWritable_002.phpt | 11 ++++ tests/Stream/rewind_001.phpt | 17 ++++++ tests/Stream/seek_001.phpt | 34 ++++++++++++ .../{tell_err01.phpt => seek_err01.phpt} | 10 ++-- tests/Stream/seek_err02.phpt | 22 ++++++++ .../{tell_err02.phpt => seek_err03.phpt} | 10 ++-- 19 files changed, 316 insertions(+), 67 deletions(-) create mode 100644 tests/Stream/close_003.phpt create mode 100644 tests/Stream/detach_002.phpt create mode 100644 tests/Stream/getMetadata_001.phpt create mode 100644 tests/Stream/getMetadata_002.phpt delete mode 100644 tests/Stream/getSize_002.phpt create mode 100644 tests/Stream/isReadable_001.phpt create mode 100644 tests/Stream/isReadable_002.phpt delete mode 100644 tests/Stream/isSeekable_003.phpt create mode 100644 tests/Stream/isWritable_001.phpt create mode 100644 tests/Stream/isWritable_002.phpt create mode 100644 tests/Stream/rewind_001.phpt create mode 100644 tests/Stream/seek_001.phpt rename tests/Stream/{tell_err01.phpt => seek_err01.phpt} (53%) create mode 100644 tests/Stream/seek_err02.phpt rename tests/Stream/{tell_err02.phpt => seek_err03.phpt} (55%) diff --git a/stream.c b/stream.c index 3a2d722..2c1b884 100644 --- a/stream.c +++ b/stream.c @@ -178,7 +178,7 @@ PHP_METHOD(Stream, isSeekable) zend_bool seekable; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + if (!IS_STREAM_RESOURCE(zstream)) { RETURN_FALSE; } @@ -192,16 +192,24 @@ PHP_METHOD(Stream, seek) { zval rv, *zstream; php_stream *stream; - size_t offset, whence; + size_t offset, whence = SEEK_SET; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_LONG(offset) + Z_PARAM_OPTIONAL Z_PARAM_LONG(whence) ZEND_PARSE_PARAMETERS_END_EX(); zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { - RETURN_FALSE; + if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "The stream has been %s", + Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + return; + } + + if (whence > 3) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Invalid value for whence"); + return; } php_stream_from_zval(stream, zstream); @@ -225,7 +233,7 @@ PHP_METHOD(Stream, isWritable) zend_bool writable; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + if (!IS_STREAM_RESOURCE(zstream)) { RETURN_FALSE; } @@ -246,7 +254,7 @@ PHP_METHOD(Stream, isReadable) zend_bool writable; zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + if (!IS_STREAM_RESOURCE(zstream)) { RETURN_FALSE; } @@ -266,17 +274,37 @@ PHP_METHOD(Stream, getContents) PHP_METHOD(Stream, getMetadata) { - zval fname, zkey; - zend_string *key; + zval rv, fname, *zstream, *zvalue; + zend_string *key = NULL; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) + Z_PARAM_OPTIONAL Z_PARAM_STR(key) ZEND_PARSE_PARAMETERS_END_EX(); + if (!IS_STREAM_RESOURCE(zstream)) { + if (key == NULL) { + array_init(return_value); + } else { + RETVAL_NULL(); + } + return; + } + ZVAL_STRING(&fname, "stream_get_meta_data"); - ZVAL_STR(&zkey, key); - call_user_function(NULL, NULL, &fname, return_value, 1, &zkey); + call_user_function(NULL, NULL, &fname, return_value, 1, zstream); + + if (key != NULL) { + zvalue = zend_hash_find(Z_ARR(*return_value), key); + + if (zvalue == NULL) { + ZVAL_NULL(return_value); + } else { + ZVAL_COPY(return_value, zvalue); + } + } } diff --git a/tests/Stream/close_003.phpt b/tests/Stream/close_003.phpt new file mode 100644 index 0000000..6eab031 --- /dev/null +++ b/tests/Stream/close_003.phpt @@ -0,0 +1,49 @@ +--TEST-- +Stream::close() +--FILE-- +close(); + +try { + $stream->tell(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->seek(1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->rewind(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +var_dump($stream->getSize()); + +var_dump($stream->eof()); +var_dump($stream->isSeekable()); +var_dump($stream->isWritable()); +var_dump($stream->isReadable()); + +var_dump($stream->getMetadata()); +var_dump($stream->getMetadata('uri')); +?> +--EXPECT-- +The stream has been closed +The stream has been closed +The stream has been closed +NULL +bool(true) +bool(false) +bool(false) +bool(false) +array(0) { +} +NULL diff --git a/tests/Stream/detach_002.phpt b/tests/Stream/detach_002.phpt new file mode 100644 index 0000000..1e831ef --- /dev/null +++ b/tests/Stream/detach_002.phpt @@ -0,0 +1,50 @@ +--TEST-- +Stream::detach() call all methods +--FILE-- +detach(); + +try { + $stream->tell(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->seek(1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->rewind(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +var_dump($stream->getSize()); + +var_dump($stream->eof()); +var_dump($stream->isSeekable()); +var_dump($stream->isWritable()); +var_dump($stream->isReadable()); + +var_dump($stream->getMetadata()); +var_dump($stream->getMetadata('uri')); +?> +--EXPECT-- +The stream has been detached +The stream has been detached +The stream has been detached +NULL +bool(true) +bool(false) +bool(false) +bool(false) +array(0) { +} +NULL diff --git a/tests/Stream/eof_002.phpt b/tests/Stream/eof_002.phpt index d532f04..b3e099b 100644 --- a/tests/Stream/eof_002.phpt +++ b/tests/Stream/eof_002.phpt @@ -1,5 +1,5 @@ --TEST-- -Stream::eof() +Stream::eof() call all methods --FILE-- getMetadata()); + +?> +--EXPECT-- +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(6) "MEMORY" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(12) "php://memory" +} diff --git a/tests/Stream/getMetadata_002.phpt b/tests/Stream/getMetadata_002.phpt new file mode 100644 index 0000000..18f5e2d --- /dev/null +++ b/tests/Stream/getMetadata_002.phpt @@ -0,0 +1,17 @@ +--TEST-- +Stream::getMetadata() with key +--FILE-- +getMetadata('uri')); +var_dump($stream->getMetadata('blocked')); + +var_dump($stream->getMetadata('not_exist')); + +?> +--EXPECT-- +string(12) "php://memory" +bool(true) +NULL diff --git a/tests/Stream/getSize_002.phpt b/tests/Stream/getSize_002.phpt deleted file mode 100644 index 09dbf52..0000000 --- a/tests/Stream/getSize_002.phpt +++ /dev/null @@ -1,16 +0,0 @@ ---TEST-- -Stream::getSize() with detached stream ---FILE-- -getSize()); - -$stream->detach(); -var_dump($stream->getSize()); -?> ---EXPECT-- -int(6) -NULL diff --git a/tests/Stream/isReadable_001.phpt b/tests/Stream/isReadable_001.phpt new file mode 100644 index 0000000..8208aa9 --- /dev/null +++ b/tests/Stream/isReadable_001.phpt @@ -0,0 +1,9 @@ +--TEST-- +Stream::isReadable() with readable stream +--FILE-- +isReadable()); +?> +--EXPECT-- +bool(true) diff --git a/tests/Stream/isReadable_002.phpt b/tests/Stream/isReadable_002.phpt new file mode 100644 index 0000000..9bb1616 --- /dev/null +++ b/tests/Stream/isReadable_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +Stream::isWritable() with non-writable stream +--FILE-- +isWritable()); +?> +--EXPECT-- +bool(false) diff --git a/tests/Stream/isSeekable_001.phpt b/tests/Stream/isSeekable_001.phpt index 8d0628f..30eb9ac 100644 --- a/tests/Stream/isSeekable_001.phpt +++ b/tests/Stream/isSeekable_001.phpt @@ -1,13 +1,9 @@ --TEST-- -Stream::isSeekable() +Stream::isSeekable() with seekable stream --FILE-- isSeekable()); - -$unseekableStream = new HttpMessage\Stream(fopen('php://stdin', 'r')); -var_dump($unseekableStream->isSeekable()); +$stream = new HttpMessage\Stream(fopen('php://memory', 'r')); +var_dump($stream->isSeekable()); ?> --EXPECT-- bool(true) -bool(false) diff --git a/tests/Stream/isSeekable_002.phpt b/tests/Stream/isSeekable_002.phpt index 20aea2c..9b477fa 100644 --- a/tests/Stream/isSeekable_002.phpt +++ b/tests/Stream/isSeekable_002.phpt @@ -1,13 +1,9 @@ --TEST-- -Stream::isSeekable() with detached stream +Stream::isSeekable() with unseekable stream --FILE-- isSeekable()); - -$stream->detach(); +$stream = new HttpMessage\Stream(fopen('php://stdin', 'r')); var_dump($stream->isSeekable()); ?> --EXPECT-- -bool(true) bool(false) diff --git a/tests/Stream/isSeekable_003.phpt b/tests/Stream/isSeekable_003.phpt deleted file mode 100644 index 20aea2c..0000000 --- a/tests/Stream/isSeekable_003.phpt +++ /dev/null @@ -1,13 +0,0 @@ ---TEST-- -Stream::isSeekable() with detached stream ---FILE-- -isSeekable()); - -$stream->detach(); -var_dump($stream->isSeekable()); -?> ---EXPECT-- -bool(true) -bool(false) diff --git a/tests/Stream/isWritable_001.phpt b/tests/Stream/isWritable_001.phpt new file mode 100644 index 0000000..4fdb095 --- /dev/null +++ b/tests/Stream/isWritable_001.phpt @@ -0,0 +1,11 @@ +--TEST-- +Stream::isWritable() with writable stream +--FILE-- +isWritable()); +?> +--EXPECT-- +bool(true) diff --git a/tests/Stream/isWritable_002.phpt b/tests/Stream/isWritable_002.phpt new file mode 100644 index 0000000..162f557 --- /dev/null +++ b/tests/Stream/isWritable_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +Stream::isWritable() with non-writable stream +--FILE-- +isWritable()); +?> +--EXPECT-- +bool(true) diff --git a/tests/Stream/rewind_001.phpt b/tests/Stream/rewind_001.phpt new file mode 100644 index 0000000..66e9a87 --- /dev/null +++ b/tests/Stream/rewind_001.phpt @@ -0,0 +1,17 @@ +--TEST-- +Stream::rewind() +--FILE-- +rewind(); +var_dump(fread($resource, 4)); +?> +--EXPECT-- +string(0) "" +string(3) "abc" diff --git a/tests/Stream/seek_001.phpt b/tests/Stream/seek_001.phpt new file mode 100644 index 0000000..1785f3a --- /dev/null +++ b/tests/Stream/seek_001.phpt @@ -0,0 +1,34 @@ +--TEST-- +Stream::seek() +--FILE-- +seek(10); +var_dump(fread($resource, 64)); + +$stream->seek(3, SEEK_SET); +var_dump(fread($resource, 6)); + +$stream->seek(4, SEEK_CUR); +var_dump(fread($resource, 6)); + +$stream->seek(-3, SEEK_CUR); +var_dump(fread($resource, 6)); + +$stream->seek(-12, SEEK_END); +var_dump(fread($resource, 6)); + +$stream->seek(100); +var_dump(fread($resource, 6)); +?> +--EXPECT-- +string(16) "klmnopqrstuvwxyz" +string(6) "defghi" +string(6) "nopqrs" +string(6) "qrstuv" +string(6) "opqrst" +string(0) "" diff --git a/tests/Stream/tell_err01.phpt b/tests/Stream/seek_err01.phpt similarity index 53% rename from tests/Stream/tell_err01.phpt rename to tests/Stream/seek_err01.phpt index d1e2a7b..098e9bb 100644 --- a/tests/Stream/tell_err01.phpt +++ b/tests/Stream/seek_err01.phpt @@ -1,17 +1,15 @@ --TEST-- -Stream::tell() error: detached stream +Stream::seek() error: no arguments --FILE-- detach(); - try { - $stream->tell(); -} catch (RuntimeException $e) { + $stream->seek(); +} catch (Error $e) { echo $e->getMessage(); } ?> --EXPECT-- -The stream has been detached +HttpMessage\Stream::seek() expects at least 1 parameter, 0 given diff --git a/tests/Stream/seek_err02.phpt b/tests/Stream/seek_err02.phpt new file mode 100644 index 0000000..3c84f1a --- /dev/null +++ b/tests/Stream/seek_err02.phpt @@ -0,0 +1,22 @@ +--TEST-- +Stream::seek() error: invalid arguments +--FILE-- +seek('hello'); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->seek(1, 'hello'); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Stream::seek() expects parameter 1 to be integer, string given +HttpMessage\Stream::seek() expects parameter 2 to be integer, string given diff --git a/tests/Stream/tell_err02.phpt b/tests/Stream/seek_err03.phpt similarity index 55% rename from tests/Stream/tell_err02.phpt rename to tests/Stream/seek_err03.phpt index f7e8986..11aeb91 100644 --- a/tests/Stream/tell_err02.phpt +++ b/tests/Stream/seek_err03.phpt @@ -1,17 +1,15 @@ --TEST-- -Stream::tell() error: closed stream +Stream::seek() error: invalid whence --FILE-- tell(); + $stream->seek(1, 999); } catch (RuntimeException $e) { - echo $e->getMessage(); + echo $e->getMessage(), "\n"; } ?> --EXPECT-- -The stream has been closed +Invalid value for whence \ No newline at end of file From fb008c1b6119cb8a4aed47454596c8d657912704 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sat, 1 Jun 2019 04:01:52 +0200 Subject: [PATCH 08/67] Implemented read and write for Stream --- stream.c | 131 ++++++++++++++++++++++++++-- tests/Stream/__toString_001.phpt | 19 ++++ tests/Stream/__toString_002.phpt | 15 ++++ tests/Stream/close_003.phpt | 29 +++++- tests/Stream/detach_002.phpt | 6 +- tests/Stream/detach_003.phpt | 73 ++++++++++++++++ tests/Stream/getContents_001.phpt | 16 ++++ tests/Stream/getContents_002.phpt | 16 ++++ tests/Stream/getContents_err01.phpt | 19 ++++ tests/Stream/isReadable_002.phpt | 10 ++- tests/Stream/isWritable_002.phpt | 6 +- tests/Stream/read_001.phpt | 20 +++++ tests/Stream/read_err01.phpt | 15 ++++ tests/Stream/read_err02.phpt | 22 +++++ tests/Stream/read_err03.phpt | 19 ++++ tests/Stream/seek_err04.phpt | 14 +++ tests/Stream/write_001.phpt | 16 ++++ tests/Stream/write_err01.phpt | 15 ++++ tests/Stream/write_err02.phpt | 15 ++++ tests/Stream/write_err03.phpt | 14 +++ 20 files changed, 472 insertions(+), 18 deletions(-) create mode 100644 tests/Stream/__toString_001.phpt create mode 100644 tests/Stream/__toString_002.phpt create mode 100644 tests/Stream/detach_003.phpt create mode 100644 tests/Stream/getContents_001.phpt create mode 100644 tests/Stream/getContents_002.phpt create mode 100644 tests/Stream/getContents_err01.phpt create mode 100644 tests/Stream/read_001.phpt create mode 100644 tests/Stream/read_err01.phpt create mode 100644 tests/Stream/read_err02.phpt create mode 100644 tests/Stream/read_err03.phpt create mode 100644 tests/Stream/seek_err04.phpt create mode 100644 tests/Stream/write_001.phpt create mode 100644 tests/Stream/write_err01.phpt create mode 100644 tests/Stream/write_err02.phpt create mode 100644 tests/Stream/write_err03.phpt diff --git a/stream.c b/stream.c index 2c1b884..548df39 100644 --- a/stream.c +++ b/stream.c @@ -69,7 +69,7 @@ PHP_METHOD(Stream, __construct) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_RESOURCE(zstream) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); if (zstream == NULL) { stream = php_stream_open_wrapper("php://temp", "w+", 0, NULL); @@ -90,6 +90,36 @@ PHP_METHOD(Stream, __construct) PHP_METHOD(Stream, __toString) { + zval rv, *zstream; + php_stream *stream; + zend_string *contents; + + zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(zstream)) { + RETURN_EMPTY_STRING(); + } + + php_stream_from_zval(stream, zstream); + + if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { + RETURN_EMPTY_STRING(); + } + + if ((stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { + php_stream_seek(stream, 0, SEEK_SET); + } + + // Special case for 'php://input'. Need to reopen the resource, because seek doesn't work. + if (strcmp(stream->wrapper->wops->label, "PHP") == 0 && strcmp(stream->ops->label, "Input") == 0) { + stream = php_stream_open_wrapper(stream->orig_path, stream->mode, 0, NULL); + php_stream_to_zval(stream, &zstream); + } + + if ((contents = php_stream_copy_to_mem(stream, (ssize_t)PHP_STREAM_COPY_ALL, 0))) { + RETURN_STR(contents); + } else { + RETURN_EMPTY_STRING(); + } } PHP_METHOD(Stream, close) @@ -143,7 +173,7 @@ PHP_METHOD(Stream, tell) zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(zstream)) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "The stream has been %s", + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); return; } @@ -198,11 +228,11 @@ PHP_METHOD(Stream, seek) Z_PARAM_LONG(offset) Z_PARAM_OPTIONAL Z_PARAM_LONG(whence) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(zstream)) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "The stream has been %s", + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); return; } @@ -214,6 +244,11 @@ PHP_METHOD(Stream, seek) php_stream_from_zval(stream, zstream); + if (!stream->ops->seek || (stream->flags & PHP_STREAM_FLAG_NO_SEEK) != 0) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is not seekable"); + return; + }; + php_stream_seek(stream, offset, whence); } @@ -245,6 +280,36 @@ PHP_METHOD(Stream, isWritable) PHP_METHOD(Stream, write) { + zval rv, *zstream; + char *input; + size_t len, ret; + php_stream *stream; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_STRING(input, len) + ZEND_PARSE_PARAMETERS_END(); + + zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", + Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + return; + } + + php_stream_from_zval(stream, zstream); + + if (string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not writable"); + return; + } + + if (len == 0) { + RETURN_LONG(0); + } + + ret = php_stream_write(stream, input, len); + + RETURN_LONG(ret); } PHP_METHOD(Stream, isReadable) @@ -266,10 +331,66 @@ PHP_METHOD(Stream, isReadable) PHP_METHOD(Stream, read) { + zval rv, *zstream; + php_stream *stream; + zend_long len = 0; + zend_string *contents; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_LONG(len) + ZEND_PARSE_PARAMETERS_END(); + + if (len < 0) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Length parameter must be equal or greater than 0"); + return; + } + + zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", + Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + return; + } + + php_stream_from_zval(stream, zstream); + + if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not readable"); + return; + } + + if ((contents = php_stream_copy_to_mem(stream, (size_t)len, 0))) { + RETURN_STR(contents); + } else { + RETURN_EMPTY_STRING(); + } } PHP_METHOD(Stream, getContents) { + zval rv, *zstream; + php_stream *stream; + zend_string *contents; + + zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(zstream)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", + Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + return; + } + + php_stream_from_zval(stream, zstream); + + if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not readable"); + return; + } + + if ((contents = php_stream_copy_to_mem(stream, (size_t)PHP_STREAM_COPY_ALL, 0))) { + RETURN_STR(contents); + } else { + RETURN_EMPTY_STRING(); + } } PHP_METHOD(Stream, getMetadata) @@ -281,7 +402,7 @@ PHP_METHOD(Stream, getMetadata) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR(key) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); if (!IS_STREAM_RESOURCE(zstream)) { if (key == NULL) { diff --git a/tests/Stream/__toString_001.phpt b/tests/Stream/__toString_001.phpt new file mode 100644 index 0000000..fb036a9 --- /dev/null +++ b/tests/Stream/__toString_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +Cast Stream to string +--FILE-- + +--EXPECT-- +string(26) "abcdefghijklmnopqrstuvwxyz" +string(26) "abcdefghijklmnopqrstuvwxyz" +string(26) "abcdefghijklmnopqrstuvwxyz" diff --git a/tests/Stream/__toString_002.phpt b/tests/Stream/__toString_002.phpt new file mode 100644 index 0000000..b9b1587 --- /dev/null +++ b/tests/Stream/__toString_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +Cast unreadable Stream to string +--FILE-- + +--CLEANUP-- + +--EXPECT-- +string(0) "" diff --git a/tests/Stream/close_003.phpt b/tests/Stream/close_003.phpt index 6eab031..ad97612 100644 --- a/tests/Stream/close_003.phpt +++ b/tests/Stream/close_003.phpt @@ -25,6 +25,25 @@ try { echo $e->getMessage(), "\n"; } +try { + $stream->read(1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->getContents(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->write("abc"); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +var_dump((string)$stream); var_dump($stream->getSize()); var_dump($stream->eof()); @@ -36,9 +55,13 @@ var_dump($stream->getMetadata()); var_dump($stream->getMetadata('uri')); ?> --EXPECT-- -The stream has been closed -The stream has been closed -The stream has been closed +Stream is closed +Stream is closed +Stream is closed +Stream is closed +Stream is closed +Stream is closed +string(0) "" NULL bool(true) bool(false) diff --git a/tests/Stream/detach_002.phpt b/tests/Stream/detach_002.phpt index 1e831ef..ae25eea 100644 --- a/tests/Stream/detach_002.phpt +++ b/tests/Stream/detach_002.phpt @@ -37,9 +37,9 @@ var_dump($stream->getMetadata()); var_dump($stream->getMetadata('uri')); ?> --EXPECT-- -The stream has been detached -The stream has been detached -The stream has been detached +Stream is detached +Stream is detached +Stream is detached NULL bool(true) bool(false) diff --git a/tests/Stream/detach_003.phpt b/tests/Stream/detach_003.phpt new file mode 100644 index 0000000..81a50a2 --- /dev/null +++ b/tests/Stream/detach_003.phpt @@ -0,0 +1,73 @@ +--TEST-- +Stream::detach() call all methods +--FILE-- +detach(); + +try { + $stream->tell(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->seek(1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->rewind(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->read(1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->getContents(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->write("abc"); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +var_dump((string)$stream); +var_dump($stream->getSize()); + +var_dump($stream->eof()); +var_dump($stream->isSeekable()); +var_dump($stream->isWritable()); +var_dump($stream->isReadable()); + +var_dump($stream->getMetadata()); +var_dump($stream->getMetadata('uri')); +?> +--EXPECT-- +Stream is detached +Stream is detached +Stream is detached +Stream is detached +Stream is detached +Stream is detached +string(0) "" +NULL +bool(true) +bool(false) +bool(false) +bool(false) +array(0) { +} +NULL diff --git a/tests/Stream/getContents_001.phpt b/tests/Stream/getContents_001.phpt new file mode 100644 index 0000000..37e497d --- /dev/null +++ b/tests/Stream/getContents_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::getContents() +--FILE-- +getContents()); +var_dump($stream->getContents()); +?> +--EXPECT-- +string(26) "abcdefghijklmnopqrstuvwxyz" +string(0) "" diff --git a/tests/Stream/getContents_002.phpt b/tests/Stream/getContents_002.phpt new file mode 100644 index 0000000..c2f5a13 --- /dev/null +++ b/tests/Stream/getContents_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::getContents() +--FILE-- +getContents()); +var_dump($stream->getContents()); +?> +--EXPECT-- +string(16) "klmnopqrstuvwxyz" +string(0) "" diff --git a/tests/Stream/getContents_err01.phpt b/tests/Stream/getContents_err01.phpt new file mode 100644 index 0000000..0df2461 --- /dev/null +++ b/tests/Stream/getContents_err01.phpt @@ -0,0 +1,19 @@ +--TEST-- +Stream::getContents() with non-readable stream +--FILE-- +getContents(); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} +?> +--CLEANUP-- + +--EXPECT-- +Stream not readable diff --git a/tests/Stream/isReadable_002.phpt b/tests/Stream/isReadable_002.phpt index 9bb1616..64ece51 100644 --- a/tests/Stream/isReadable_002.phpt +++ b/tests/Stream/isReadable_002.phpt @@ -1,11 +1,15 @@ --TEST-- -Stream::isWritable() with non-writable stream +Stream::isReadable() with non-readable stream --FILE-- isWritable()); +var_dump($stream->isReadable()); +?> +--CLEANUP-- + --EXPECT-- bool(false) diff --git a/tests/Stream/isWritable_002.phpt b/tests/Stream/isWritable_002.phpt index 162f557..a6b38c0 100644 --- a/tests/Stream/isWritable_002.phpt +++ b/tests/Stream/isWritable_002.phpt @@ -2,10 +2,8 @@ Stream::isWritable() with non-writable stream --FILE-- isWritable()); ?> --EXPECT-- -bool(true) +bool(false) diff --git a/tests/Stream/read_001.phpt b/tests/Stream/read_001.phpt new file mode 100644 index 0000000..368fff4 --- /dev/null +++ b/tests/Stream/read_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +Stream::read() +--FILE-- +read(10)); +var_dump($stream->read(10)); +var_dump($stream->read(10)); +var_dump($stream->read(10)); +?> +--EXPECT-- +string(10) "abcdefghij" +string(10) "klmnopqrst" +string(6) "uvwxyz" +string(0) "" diff --git a/tests/Stream/read_err01.phpt b/tests/Stream/read_err01.phpt new file mode 100644 index 0000000..e774f51 --- /dev/null +++ b/tests/Stream/read_err01.phpt @@ -0,0 +1,15 @@ +--TEST-- +Stream::read() error: no arguments +--FILE-- +read(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Stream::read() expects exactly 1 parameter, 0 given \ No newline at end of file diff --git a/tests/Stream/read_err02.phpt b/tests/Stream/read_err02.phpt new file mode 100644 index 0000000..0ecabad --- /dev/null +++ b/tests/Stream/read_err02.phpt @@ -0,0 +1,22 @@ +--TEST-- +Stream::read() err: invalid arguments +--FILE-- +read('hello'); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + $stream->read(-1); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Stream::read() expects parameter 1 to be integer, string given +Length parameter must be equal or greater than 0 diff --git a/tests/Stream/read_err03.phpt b/tests/Stream/read_err03.phpt new file mode 100644 index 0000000..4e28e2e --- /dev/null +++ b/tests/Stream/read_err03.phpt @@ -0,0 +1,19 @@ +--TEST-- +Stream::read() with non-readable stream +--FILE-- +read(1); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} +?> +--CLEANUP-- + +--EXPECT-- +Stream not readable diff --git a/tests/Stream/seek_err04.phpt b/tests/Stream/seek_err04.phpt new file mode 100644 index 0000000..8502952 --- /dev/null +++ b/tests/Stream/seek_err04.phpt @@ -0,0 +1,14 @@ +--TEST-- +Stream::seek() error: unseekable stream +--FILE-- +seek(0); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Stream is not seekable \ No newline at end of file diff --git a/tests/Stream/write_001.phpt b/tests/Stream/write_001.phpt new file mode 100644 index 0000000..ec46aab --- /dev/null +++ b/tests/Stream/write_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +Stream::write() +--FILE-- +write('hello'); +$stream->write(' world'); + +fseek($resource, 0); +var_dump(fread($resource, 100)); +?> +--EXPECT-- +string(11) "hello world" diff --git a/tests/Stream/write_err01.phpt b/tests/Stream/write_err01.phpt new file mode 100644 index 0000000..c6f9d10 --- /dev/null +++ b/tests/Stream/write_err01.phpt @@ -0,0 +1,15 @@ +--TEST-- +Stream::write() error: no arguments +--FILE-- +write(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Stream::write() expects exactly 1 parameter, 0 given \ No newline at end of file diff --git a/tests/Stream/write_err02.phpt b/tests/Stream/write_err02.phpt new file mode 100644 index 0000000..49bca61 --- /dev/null +++ b/tests/Stream/write_err02.phpt @@ -0,0 +1,15 @@ +--TEST-- +Stream::read() err: invalid arguments +--FILE-- +write(['foo' => 'bar']); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Stream::write() expects parameter 1 to be string, array given \ No newline at end of file diff --git a/tests/Stream/write_err03.phpt b/tests/Stream/write_err03.phpt new file mode 100644 index 0000000..78f70ee --- /dev/null +++ b/tests/Stream/write_err03.phpt @@ -0,0 +1,14 @@ +--TEST-- +Stream::read() with non-readable stream +--FILE-- +write('hello'); +} catch (RuntimeException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Stream not writable From 95cc2ca6d9488ad2d62d08fe769fc93d7c580c2c Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sat, 1 Jun 2019 04:23:52 +0200 Subject: [PATCH 09/67] Fixup Stream::__toString() for php://input --- stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stream.c b/stream.c index 548df39..96bf329 100644 --- a/stream.c +++ b/stream.c @@ -112,7 +112,7 @@ PHP_METHOD(Stream, __toString) // Special case for 'php://input'. Need to reopen the resource, because seek doesn't work. if (strcmp(stream->wrapper->wops->label, "PHP") == 0 && strcmp(stream->ops->label, "Input") == 0) { stream = php_stream_open_wrapper(stream->orig_path, stream->mode, 0, NULL); - php_stream_to_zval(stream, &zstream); + php_stream_to_zval(stream, zstream); } if ((contents = php_stream_copy_to_mem(stream, (ssize_t)PHP_STREAM_COPY_ALL, 0))) { From 3c317e7c387670c6a204689e2a926c330bc72f92 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 16 Jun 2019 00:55:06 +0200 Subject: [PATCH 10/67] Tests for Message and Response classes. Some fixes --- message.c | 47 ++++++++-------- response.c | 8 ++- server_request.c | 31 +++++------ tests/Message/body_001.phpt | 19 +++++++ tests/Message/body_err01.phpt | 23 ++++++++ tests/Message/headers_001.phpt | 68 +++++++++++++++++++++++ tests/Message/headers_002.phpt | 70 ++++++++++++++++++++++++ tests/Message/headers_err01.phpt | 29 ++++++++++ tests/Message/headers_err02.phpt | 29 ++++++++++ tests/Message/headers_err03.phpt | 22 ++++++++ tests/Message/headers_err04.phpt | 22 ++++++++ tests/Message/headers_err05.phpt | 22 ++++++++ tests/Message/protocolVersion_001.phpt | 17 ++++++ tests/Message/protocolVersion_002.phpt | 11 ++++ tests/Message/protocolVersion_err01.phpt | 21 +++++++ tests/Response/__construct_001.phpt | 27 +++++++++ tests/Response/status_001.phpt | 14 +++++ tests/Response/status_002.phpt | 14 +++++ tests/Response/status_003.phpt | 69 +++++++++++++++++++++++ 19 files changed, 522 insertions(+), 41 deletions(-) create mode 100644 tests/Message/body_001.phpt create mode 100644 tests/Message/body_err01.phpt create mode 100644 tests/Message/headers_001.phpt create mode 100644 tests/Message/headers_002.phpt create mode 100644 tests/Message/headers_err01.phpt create mode 100644 tests/Message/headers_err02.phpt create mode 100644 tests/Message/headers_err03.phpt create mode 100644 tests/Message/headers_err04.phpt create mode 100644 tests/Message/headers_err05.phpt create mode 100644 tests/Message/protocolVersion_001.phpt create mode 100644 tests/Message/protocolVersion_002.phpt create mode 100644 tests/Message/protocolVersion_err01.phpt create mode 100644 tests/Response/__construct_001.phpt create mode 100644 tests/Response/status_001.phpt create mode 100644 tests/Response/status_002.phpt create mode 100644 tests/Response/status_003.phpt diff --git a/message.c b/message.c index dd40cfa..012548e 100644 --- a/message.c +++ b/message.c @@ -81,11 +81,11 @@ PHP_METHOD(Message, getProtocolVersion) PHP_METHOD(Message, withProtocolVersion) { char *value; - size_t value_len; + size_t value_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -110,12 +110,12 @@ PHP_METHOD(Message, hasHeader) { zval rv, *headers; char *name; - size_t name_len; + size_t name_len = 0; zend_bool exists; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); @@ -128,17 +128,18 @@ PHP_METHOD(Message, getHeader) { zval rv, *headers, *header_values; char *name; - size_t name_len; + size_t name_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - header_values = zend_hash_str_find(Z_ARRVAL_P(headers), name, name_len); - if (header_values != NULL) { - array_init(header_values); + + if (header_values == NULL) { + array_init(return_value); + return; } RETURN_ZVAL(header_values, 1, 0); @@ -146,37 +147,39 @@ PHP_METHOD(Message, getHeader) PHP_METHOD(Message, getHeaderLine) { - zval rv, *headers, *header_values, *header_string; + zval rv, *headers, *header_values; char *name; - size_t name_len; + size_t name_len = 0; zend_string *glue; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); header_values = zend_hash_str_find(Z_ARRVAL_P(headers), name, name_len); + if (header_values == NULL) { + RETURN_EMPTY_STRING(); + } + glue = zend_string_init(ZEND_STRL(", "), 0); - php_implode(glue, header_values, header_string); + php_implode(glue, header_values, return_value); zend_string_free(glue); - - RETURN_ZVAL(header_string, 0, 0) } PHP_METHOD(Message, withHeader) { zval rv, *headers, new_headers, header_values; char *name; - size_t name_len; + size_t name_len = 0; zend_string *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) Z_PARAM_STRING(name, name_len) Z_PARAM_STR(value) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); ZVAL_COPY(&new_headers, headers); @@ -195,13 +198,13 @@ PHP_METHOD(Message, withAddedHeader) { zval rv, *headers, *header_values; char *name; - size_t name_len; + size_t name_len = 0; zend_string *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) Z_PARAM_STRING(name, name_len) Z_PARAM_STR(value) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); @@ -222,11 +225,11 @@ PHP_METHOD(Message, withoutHeader) { zval rv, *headers; char *name; - size_t name_len; + size_t name_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); zend_hash_str_del(Z_ARRVAL_P(headers), name, name_len); @@ -254,7 +257,7 @@ PHP_METHOD(Message, withBody) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_OBJECT_OF_CLASS(value, PsrHttpMessageStreamInterface_ce_ptr) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); diff --git a/response.c b/response.c index 510ea0a..0a4a6a5 100644 --- a/response.c +++ b/response.c @@ -97,11 +97,12 @@ PHP_METHOD(Response, withStatus) { zend_long code; char *phrase; - size_t phrase_len; + size_t phrase_len = 0; const char *suggested_phrase; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_LONG(code) + Z_PARAM_OPTIONAL Z_PARAM_STRING(phrase, phrase_len) ZEND_PARSE_PARAMETERS_END_EX(); @@ -116,7 +117,8 @@ PHP_METHOD(Response, withStatus) } else { suggested_phrase = get_status_string((int)code); zend_update_property_stringl( - HttpMessage_Response_ce, return_value, ZEND_STRL("reasonPhrase"), ZEND_STRL(suggested_phrase) + HttpMessage_Response_ce, return_value, ZEND_STRL("reasonPhrase"), + suggested_phrase, strlen(suggested_phrase) ); } } diff --git a/server_request.c b/server_request.c index ca6167e..74c735c 100644 --- a/server_request.c +++ b/server_request.c @@ -45,7 +45,6 @@ zend_class_entry *HttpMessage_ServerRequest_ce; - /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageServerRequest_construct, 0, 0, 0) @@ -258,21 +257,21 @@ PHP_METHOD(ServerRequest, withoutAttribute) /* Define HttpMessage\ServerRequest class */ static const zend_function_entry request_functions[] = { - PHP_ME(ServerRequest, __construct, arginfo_HttpMessageServerRequest_construct, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(ServerRequest, getServerParams) - HTTP_MESSAGE_ME(ServerRequest, getCookieParams) - HTTP_MESSAGE_ME(ServerRequest, withCookieParams) - HTTP_MESSAGE_ME(ServerRequest, getQueryParams) - HTTP_MESSAGE_ME(ServerRequest, withQueryParams) - HTTP_MESSAGE_ME(ServerRequest, getUploadedFiles) - HTTP_MESSAGE_ME(ServerRequest, withUploadedFiles) - HTTP_MESSAGE_ME(ServerRequest, getParsedBody) - HTTP_MESSAGE_ME(ServerRequest, withParsedBody) - HTTP_MESSAGE_ME(ServerRequest, getAttributes) - HTTP_MESSAGE_ME(ServerRequest, getAttribute) - HTTP_MESSAGE_ME(ServerRequest, withAttribute) - HTTP_MESSAGE_ME(ServerRequest, withoutAttribute) - PHP_FE_END + PHP_ME(ServerRequest, __construct, arginfo_HttpMessageServerRequest_construct, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME(ServerRequest, getServerParams) + HTTP_MESSAGE_ME(ServerRequest, getCookieParams) + HTTP_MESSAGE_ME(ServerRequest, withCookieParams) + HTTP_MESSAGE_ME(ServerRequest, getQueryParams) + HTTP_MESSAGE_ME(ServerRequest, withQueryParams) + HTTP_MESSAGE_ME(ServerRequest, getUploadedFiles) + HTTP_MESSAGE_ME(ServerRequest, withUploadedFiles) + HTTP_MESSAGE_ME(ServerRequest, getParsedBody) + HTTP_MESSAGE_ME(ServerRequest, withParsedBody) + HTTP_MESSAGE_ME(ServerRequest, getAttributes) + HTTP_MESSAGE_ME(ServerRequest, getAttribute) + HTTP_MESSAGE_ME(ServerRequest, withAttribute) + HTTP_MESSAGE_ME(ServerRequest, withoutAttribute) + PHP_FE_END }; PHP_MINIT_FUNCTION(http_message_serverrequest) diff --git a/tests/Message/body_001.phpt b/tests/Message/body_001.phpt new file mode 100644 index 0000000..b92ff0f --- /dev/null +++ b/tests/Message/body_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +Message body +--FILE-- +getBody())); + +$resource = fopen('php://memory', 'w+'); +$stream = new HttpMessage\Stream($resource); + +$newResponse = $response->withBody($stream); +var_dump(get_class($newResponse->getBody())); +var_dump($newResponse->getBody() === $stream); + +?> +--EXPECT-- +string(18) "HttpMessage\Stream" +string(18) "HttpMessage\Stream" +bool(true) \ No newline at end of file diff --git a/tests/Message/body_err01.phpt b/tests/Message/body_err01.phpt new file mode 100644 index 0000000..dd0c826 --- /dev/null +++ b/tests/Message/body_err01.phpt @@ -0,0 +1,23 @@ +--TEST-- +Message::withBody() with invalid arguments +--FILE-- +withBody($resource); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withBody(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Message::withBody() must implement interface Psr\Http\Message\StreamInterface, resource given +HttpMessage\Message::withBody() expects exactly 1 parameter, 0 given diff --git a/tests/Message/headers_001.phpt b/tests/Message/headers_001.phpt new file mode 100644 index 0000000..3c2227e --- /dev/null +++ b/tests/Message/headers_001.phpt @@ -0,0 +1,68 @@ +--TEST-- +Message headers +--FILE-- +getHeaders()); +var_dump($response->hasHeader('Foo')); +var_dump($response->getHeader('Foo')); +var_dump($response->getHeaderLine('Foo')); + +echo "\n"; +$fooResponse = $response->withHeader('Foo', 'bar'); +var_dump($fooResponse->getHeaders()); +var_dump($fooResponse->hasHeader('Foo')); +var_dump($fooResponse->getHeader('Foo')); +var_dump($fooResponse->getHeaderLine('Foo')); + +echo "\n"; +$moreResponse = $fooResponse->withHeader('More', 'red'); +var_dump($moreResponse->getHeaders()); +var_dump($fooResponse->hasHeader('More')); +var_dump($fooResponse->getHeader('More')); +var_dump($fooResponse->getHeaderLine('More')); +var_dump($fooResponse->getHeaderLine('Foo')); + +?> +--EXPECT-- +array(0) { +} +bool(false) +array(0) { +} +string(0) "" + +array(1) { + ["Foo"]=> + array(1) { + [0]=> + string(3) "bar" + } +} +bool(true) +array(1) { + [0]=> + string(3) "bar" +} +string(3) "bar" + +array(2) { + ["Foo"]=> + array(1) { + [0]=> + string(3) "bar" + } + ["More"]=> + array(1) { + [0]=> + string(3) "red" + } +} +bool(true) +array(1) { + [0]=> + string(3) "red" +} +string(3) "red" +string(3) "bar" \ No newline at end of file diff --git a/tests/Message/headers_002.phpt b/tests/Message/headers_002.phpt new file mode 100644 index 0000000..ab5b847 --- /dev/null +++ b/tests/Message/headers_002.phpt @@ -0,0 +1,70 @@ +--TEST-- +Message headers; added header / without header +--FILE-- +withHeader('Foo', 'bar') + ->withAddedHeader('Foo', 'baz'); + +var_dump($foofooResponse->getHeaders()); +var_dump($foofooResponse->hasHeader('Foo')); +var_dump($foofooResponse->getHeader('Foo')); +var_dump($foofooResponse->getHeaderLine('Foo')); + +$fooResponse = $foofooResponse->withHeader('Foo', 'box'); + +echo "\n"; +var_dump($fooResponse->getHeaders()); +var_dump($fooResponse->hasHeader('Foo')); +var_dump($fooResponse->getHeader('Foo')); +var_dump($fooResponse->getHeaderLine('Foo')); + +$response = $foofooResponse->withoutHeader('Foo'); + +echo "\n"; +var_dump($response->getHeaders()); +var_dump($response->hasHeader('Foo')); +var_dump($response->getHeader('Foo')); +var_dump($response->getHeaderLine('Foo')); + +?> +--EXPECT-- +array(1) { + ["Foo"]=> + array(2) { + [0]=> + string(3) "bar" + [1]=> + string(3) "baz" + } +} +bool(true) +array(2) { + [0]=> + string(3) "bar" + [1]=> + string(3) "baz" +} +string(8) "bar, baz" + +array(1) { + ["Foo"]=> + array(1) { + [0]=> + string(3) "box" + } +} +bool(true) +array(1) { + [0]=> + string(3) "box" +} +string(3) "box" + +array(0) { +} +bool(false) +array(0) { +} +string(0) "" diff --git a/tests/Message/headers_err01.phpt b/tests/Message/headers_err01.phpt new file mode 100644 index 0000000..f1accf9 --- /dev/null +++ b/tests/Message/headers_err01.phpt @@ -0,0 +1,29 @@ +--TEST-- +Message::withHeader() with invalid arguments +--FILE-- +withHeader('Foo', ['a', 'b']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withHeader(['Foo' => 'bar']); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withHeader(['Foo' => 'bar'], null); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Message::withHeader() expects parameter 2 to be string, array given +HttpMessage\Message::withHeader() expects exactly 2 parameters, 1 given +HttpMessage\Message::withHeader() expects parameter 1 to be string, array given diff --git a/tests/Message/headers_err02.phpt b/tests/Message/headers_err02.phpt new file mode 100644 index 0000000..ed7a57a --- /dev/null +++ b/tests/Message/headers_err02.phpt @@ -0,0 +1,29 @@ +--TEST-- +Message::withAddedHeader() with invalid arguments +--FILE-- +withAddedHeader('Foo', ['a', 'b']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withAddedHeader(['Foo' => 'bar']); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withAddedHeader(['Foo' => 'bar'], null); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Message::withAddedHeader() expects parameter 2 to be string, array given +HttpMessage\Message::withAddedHeader() expects exactly 2 parameters, 1 given +HttpMessage\Message::withAddedHeader() expects parameter 1 to be string, array given diff --git a/tests/Message/headers_err03.phpt b/tests/Message/headers_err03.phpt new file mode 100644 index 0000000..604aae1 --- /dev/null +++ b/tests/Message/headers_err03.phpt @@ -0,0 +1,22 @@ +--TEST-- +Message::withoutHeader() with invalid arguments +--FILE-- +withoutHeader(['Foo' => 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withoutHeader(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Message::withoutHeader() expects parameter 1 to be string, array given +HttpMessage\Message::withoutHeader() expects exactly 1 parameter, 0 given \ No newline at end of file diff --git a/tests/Message/headers_err04.phpt b/tests/Message/headers_err04.phpt new file mode 100644 index 0000000..85b1a6d --- /dev/null +++ b/tests/Message/headers_err04.phpt @@ -0,0 +1,22 @@ +--TEST-- +Message::getHeader() with invalid arguments +--FILE-- +getHeader(['Foo' => 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->getHeader(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Message::getHeader() expects parameter 1 to be string, array given +HttpMessage\Message::getHeader() expects exactly 1 parameter, 0 given \ No newline at end of file diff --git a/tests/Message/headers_err05.phpt b/tests/Message/headers_err05.phpt new file mode 100644 index 0000000..62a28c9 --- /dev/null +++ b/tests/Message/headers_err05.phpt @@ -0,0 +1,22 @@ +--TEST-- +Message::getHeaderLine() with invalid arguments +--FILE-- +getHeaderLine(['Foo' => 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->getHeaderLine(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Message::getHeaderLine() expects parameter 1 to be string, array given +HttpMessage\Message::getHeaderLine() expects exactly 1 parameter, 0 given \ No newline at end of file diff --git a/tests/Message/protocolVersion_001.phpt b/tests/Message/protocolVersion_001.phpt new file mode 100644 index 0000000..241c1b1 --- /dev/null +++ b/tests/Message/protocolVersion_001.phpt @@ -0,0 +1,17 @@ +--TEST-- +Message::withProtocolVersion() +--FILE-- +withProtocolVersion('1.0'); +$response20 = $response10->withProtocolVersion('2.0'); + +var_dump($response10->getProtocolVersion()); +var_dump($response11->getProtocolVersion()); +var_dump($response20->getProtocolVersion()); + +?> +--EXPECT-- +string(3) "1.0" +string(3) "1.1" +string(3) "2.0" \ No newline at end of file diff --git a/tests/Message/protocolVersion_002.phpt b/tests/Message/protocolVersion_002.phpt new file mode 100644 index 0000000..f618671 --- /dev/null +++ b/tests/Message/protocolVersion_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +Message::withProtocolVersion() with float +--FILE-- +withProtocolVersion(2.0); + +var_dump($response->getProtocolVersion()); +?> +--EXPECT-- +string(1) "2" \ No newline at end of file diff --git a/tests/Message/protocolVersion_err01.phpt b/tests/Message/protocolVersion_err01.phpt new file mode 100644 index 0000000..d22a35b --- /dev/null +++ b/tests/Message/protocolVersion_err01.phpt @@ -0,0 +1,21 @@ +--TEST-- +Message::withProtocolVersion() with invalid argument +--FILE-- +withProtocolVersion(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withProtocolVersion(['foo', 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +HttpMessage\Message::withProtocolVersion() expects exactly 1 parameter, 0 given +HttpMessage\Message::withProtocolVersion() expects parameter 1 to be string, array given \ No newline at end of file diff --git a/tests/Response/__construct_001.phpt b/tests/Response/__construct_001.phpt new file mode 100644 index 0000000..92c2acb --- /dev/null +++ b/tests/Response/__construct_001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Create a Response +--FILE-- +getBody()->getMetadata('uri')); +?> +--EXPECTF-- +object(HttpMessage\Response)#1 (5) { + ["protocolVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(0) { + } + ["body":protected]=> + object(HttpMessage\Stream)#2 (1) { + ["stream":protected]=> + resource(%d) of type (stream) + } + ["statusCode":protected]=> + int(0) + ["reasonPhrase":protected]=> + string(0) "" +} +string(10) "php://temp" diff --git a/tests/Response/status_001.phpt b/tests/Response/status_001.phpt new file mode 100644 index 0000000..d9735eb --- /dev/null +++ b/tests/Response/status_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Response::withStatus() +--FILE-- +withStatus(200); +var_dump($newResponse->getStatusCode()); +var_dump($newResponse->getReasonPhrase()); + +?> +--EXPECT-- +int(200) +string(2) "OK" \ No newline at end of file diff --git a/tests/Response/status_002.phpt b/tests/Response/status_002.phpt new file mode 100644 index 0000000..f793d2f --- /dev/null +++ b/tests/Response/status_002.phpt @@ -0,0 +1,14 @@ +--TEST-- +Response::withStatus() with custom reason phrase +--FILE-- +withStatus(200, "ALL CLEAR"); +var_dump($newResponse->getStatusCode()); +var_dump($newResponse->getReasonPhrase()); + +?> +--EXPECT-- +int(200) +string(9) "ALL CLEAR" \ No newline at end of file diff --git a/tests/Response/status_003.phpt b/tests/Response/status_003.phpt new file mode 100644 index 0000000..f31dfab --- /dev/null +++ b/tests/Response/status_003.phpt @@ -0,0 +1,69 @@ +--TEST-- +Response::withStatus() with all known status codes +--FILE-- +withStatus($code); + echo $newResponse->getStatusCode(), ' ', $newResponse->getReasonPhrase(), "\n"; +} + +?> +--EXPECT-- +100 Continue +101 Switching Protocols +200 OK +201 Created +202 Accepted +203 Non-Authoritative Information +204 No Content +205 Reset Content +206 Partial Content +300 Multiple Choices +301 Moved Permanently +302 Found +303 See Other +304 Not Modified +305 Use Proxy +307 Temporary Redirect +308 Permanent Redirect +400 Bad Request +401 Unauthorized +402 Payment Required +403 Forbidden +404 Not Found +405 Method Not Allowed +406 Not Acceptable +407 Proxy Authentication Required +408 Request Timeout +409 Conflict +410 Gone +411 Length Required +412 Precondition Failed +413 Request Entity Too Large +414 Request-URI Too Long +415 Unsupported Media Type +416 Requested Range Not Satisfiable +417 Expectation Failed +426 Upgrade Required +428 Precondition Required +429 Too Many Requests +431 Request Header Fields Too Large +451 Unavailable For Legal Reasons +500 Internal Server Error +501 Not Implemented +502 Bad Gateway +503 Service Unavailable +504 Gateway Timeout +505 HTTP Version Not Supported +506 Variant Also Negotiates +511 Network Authentication Required From 3668255fabf4cbb7fcad4dd745042f804b74766d Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 17 Jun 2019 22:59:00 +0200 Subject: [PATCH 11/67] Added tests for Request Added some tests for ServerRequest (WIP) Minor fixes --- Makefile.frag | 3 ++ request.c | 34 ++++++------ server_request.c | 34 +++++++----- tests/Request/__construct_001.phpt | 49 +++++++++++++++++ tests/Request/method_001.phpt | 12 +++++ tests/Request/method_err01.phpt | 22 ++++++++ tests/Request/requestTarget_001.phpt | 12 +++++ tests/Request/requestTarget_002.phpt | 19 +++++++ tests/Request/requestTarget_err01.phpt | 22 ++++++++ tests/Request/uri_001.phpt | 14 +++++ tests/Request/uri_err01.phpt | 22 ++++++++ tests/Response/status_err01.phpt | 29 ++++++++++ tests/ServerRequest/__construct_001.phpt | 60 +++++++++++++++++++++ tests/ServerRequest/cookieParams_001.phpt | 30 +++++++++++ tests/ServerRequest/cookieParams_err01.phpt | 22 ++++++++ tests/ServerRequest/parsedBody_001.phpt | 39 ++++++++++++++ tests/ServerRequest/parsedBody_err01.phpt | 22 ++++++++ tests/ServerRequest/queryParams_001.phpt | 30 +++++++++++ tests/ServerRequest/queryParams_err01.phpt | 22 ++++++++ 19 files changed, 468 insertions(+), 29 deletions(-) create mode 100644 tests/Request/__construct_001.phpt create mode 100644 tests/Request/method_001.phpt create mode 100644 tests/Request/method_err01.phpt create mode 100644 tests/Request/requestTarget_001.phpt create mode 100644 tests/Request/requestTarget_002.phpt create mode 100644 tests/Request/requestTarget_err01.phpt create mode 100644 tests/Request/uri_001.phpt create mode 100644 tests/Request/uri_err01.phpt create mode 100644 tests/Response/status_err01.phpt create mode 100644 tests/ServerRequest/__construct_001.phpt create mode 100644 tests/ServerRequest/cookieParams_001.phpt create mode 100644 tests/ServerRequest/cookieParams_err01.phpt create mode 100644 tests/ServerRequest/parsedBody_001.phpt create mode 100644 tests/ServerRequest/parsedBody_err01.phpt create mode 100644 tests/ServerRequest/queryParams_001.phpt create mode 100644 tests/ServerRequest/queryParams_err01.phpt diff --git a/Makefile.frag b/Makefile.frag index 16dd4cb..5d94d43 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -11,6 +11,9 @@ PHP_TEST_SHARED_EXTENSIONS = ` \ done; \ fi` +clean-tests: + rm -f tests/*.diff tests/*.exp tests/*.log tests/*.out tests/*.php tests/*.sh + mrproper: clean rm -rf autom4te.cache build modules vendor rm -f acinclude.m4 aclocal.m4 config.guess config.h config.h.in config.log config.nice config.status config.sub \ diff --git a/request.c b/request.c index 328faf6..fdd5901 100644 --- a/request.c +++ b/request.c @@ -53,7 +53,7 @@ ZEND_END_ARG_INFO() PHP_METHOD(Request, __construct) { - zval rv, *uri, uri_string; + zval rv, *uri; /* parent::__construct() */ zend_call_method_with_0_params( @@ -63,12 +63,6 @@ PHP_METHOD(Request, __construct) /* $this->uri = new Uri() */ uri = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); object_init_ex(uri, HttpMessage_Uri_ce); - if (uri != NULL && Z_TYPE_P(uri) == IS_OBJECT) { /* Should always be true */ - ZVAL_EMPTY_STRING(&uri_string); - zend_call_method_with_1_params( - uri, HttpMessage_Uri_ce, &HttpMessage_Uri_ce->constructor, "__construct", NULL, &uri_string - ); - } } @@ -80,23 +74,29 @@ PHP_METHOD(Request, getRequestTarget) value = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("requestTarget"), 0, &rv); + if (ZVAL_IS_NULL(value)) { + RETURN_STRING("/"); + } + RETURN_ZVAL(value, 1, 0); } PHP_METHOD(Request, withRequestTarget) { - char *value; - size_t value_len; + zval *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(value) != IS_STRING && !ZVAL_IS_NULL(value)) { + zend_wrong_parameter_type_error(ZEND_PARSE_PARAMS_THROW, 1, Z_EXPECTED_STRING, value); + return; + } ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl( - HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value, value_len - ); + zend_update_property(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value); } @@ -118,7 +118,7 @@ PHP_METHOD(Request, withMethod) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(value, value_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -145,7 +145,7 @@ PHP_METHOD(Request, withUri) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_OBJECT_OF_CLASS(value, PsrHttpMessageUriInterface_ce_ptr) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -175,7 +175,7 @@ PHP_MINIT_FUNCTION(http_message_request) zend_class_implements(HttpMessage_Request_ce, 1, PsrHttpMessageRequestInterface_ce_ptr); /* Properties */ - zend_declare_property_string(HttpMessage_Request_ce, ZEND_STRL("requestTarget"), "/", ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("requestTarget"), ZEND_ACC_PROTECTED); zend_declare_property_string(HttpMessage_Request_ce, ZEND_STRL("method"), "", ZEND_ACC_PROTECTED); zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("uri"), ZEND_ACC_PROTECTED); diff --git a/server_request.c b/server_request.c index 74c735c..caa8684 100644 --- a/server_request.c +++ b/server_request.c @@ -101,7 +101,7 @@ PHP_METHOD(ServerRequest, withCookieParams) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_ARRAY(value); - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -126,7 +126,7 @@ PHP_METHOD(ServerRequest, withQueryParams) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_ARRAY(value); - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -151,7 +151,7 @@ PHP_METHOD(ServerRequest, withUploadedFiles) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_ARRAY(value); - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -172,15 +172,19 @@ PHP_METHOD(ServerRequest, getParsedBody) PHP_METHOD(ServerRequest, withParsedBody) { - zval *value; + zval *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_ARRAY_OR_OBJECT(value, 0, 0); - ZEND_PARSE_PARAMETERS_END_EX(); + Z_PARAM_ARRAY_OR_OBJECT_EX(value, 1, 0); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody"), value); + if (value != NULL) { + zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody"), value); + } else { + zend_update_property_null(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody")); + } } @@ -197,21 +201,27 @@ PHP_METHOD(ServerRequest, getAttributes) PHP_METHOD(ServerRequest, getAttribute) { - zval rv, *attributes, *value, *default_value; + zval rv, *attributes, *value, *default_value = NULL; char *name; size_t name_len; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) Z_PARAM_ZVAL(default_value) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); value = zend_hash_str_find(Z_ARRVAL_P(attributes), name, name_len); /* value is only NULL if the entry wasn't found. A null value is still a zval. */ - RETURN_ZVAL(value != NULL ? value : default_value, 1, 0); + if (value != NULL) { + RETURN_ZVAL(value, 1, 0); + } else if (default_value != NULL) { + RETURN_ZVAL(default_value, 1, 0); + } else { + RETURN_NULL(); + } } PHP_METHOD(ServerRequest, withAttribute) @@ -223,7 +233,7 @@ PHP_METHOD(ServerRequest, withAttribute) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) Z_PARAM_STRING(name, name_len) Z_PARAM_ZVAL(value) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); ZVAL_COPY(&new_attributes, attributes); @@ -243,7 +253,7 @@ PHP_METHOD(ServerRequest, withoutAttribute) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(name, name_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); zend_hash_str_del(Z_ARRVAL_P(attributes), name, name_len); diff --git a/tests/Request/__construct_001.phpt b/tests/Request/__construct_001.phpt new file mode 100644 index 0000000..d54fd2a --- /dev/null +++ b/tests/Request/__construct_001.phpt @@ -0,0 +1,49 @@ +--TEST-- +Create a Request +--FILE-- +getRequestTarget()); +var_dump((string)$request->getUri()); +var_dump($request->getBody()->getMetadata('uri')); + +?> +--EXPECTF-- +object(HttpMessage\Request)#1 (6) { + ["protocolVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(0) { + } + ["body":protected]=> + object(HttpMessage\Stream)#2 (1) { + ["stream":protected]=> + resource(%d) of type (stream) + } + ["requestTarget":protected]=> + NULL + ["method":protected]=> + string(0) "" + ["uri":protected]=> + object(HttpMessage\Uri)#3 (7) { + ["scheme":protected]=> + string(0) "" + ["userInfo":protected]=> + string(0) "" + ["host":protected]=> + string(0) "" + ["port":protected]=> + NULL + ["path":protected]=> + string(0) "" + ["query":protected]=> + string(0) "" + ["fragment":protected]=> + string(0) "" + } +} +string(1) "/" +string(0) "" +string(10) "php://temp" \ No newline at end of file diff --git a/tests/Request/method_001.phpt b/tests/Request/method_001.phpt new file mode 100644 index 0000000..a6a690c --- /dev/null +++ b/tests/Request/method_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Request::withMethod() +--FILE-- +withMethod('POST'); + +var_dump($request->getMethod()); + +?> +--EXPECT-- +string(4) "POST" \ No newline at end of file diff --git a/tests/Request/method_err01.phpt b/tests/Request/method_err01.phpt new file mode 100644 index 0000000..e532071 --- /dev/null +++ b/tests/Request/method_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +Request::withMethod() with invalid arguments +--FILE-- +withMethod(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withMethod(['foo', 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Request::withMethod() expects exactly 1 parameter, 0 given +HttpMessage\Request::withMethod() expects parameter 1 to be string, array given diff --git a/tests/Request/requestTarget_001.phpt b/tests/Request/requestTarget_001.phpt new file mode 100644 index 0000000..3d39df4 --- /dev/null +++ b/tests/Request/requestTarget_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Request::withRequestTarget() +--FILE-- +withRequestTarget('/foo'); + +var_dump($request->getRequestTarget()); + +?> +--EXPECT-- +string(4) "/foo" \ No newline at end of file diff --git a/tests/Request/requestTarget_002.phpt b/tests/Request/requestTarget_002.phpt new file mode 100644 index 0000000..1005448 --- /dev/null +++ b/tests/Request/requestTarget_002.phpt @@ -0,0 +1,19 @@ +--TEST-- +Request::withRequestTarget() using Uri object +--FILE-- +withUri(new HttpMessage\Uri('http://www.example.com/foo:80')); + +$fooRequest = $request->withRequestTarget('/foo'); +$defaultRequest = $fooRequest->withRequestTarget(null); + +var_dump($request->getRequestTarget()); +var_dump($fooRequest->getRequestTarget()); +var_dump($defaultRequest->getRequestTarget()); + +?> +--EXPECT-- +string(1) "/" +string(4) "/foo" +string(1) "/" diff --git a/tests/Request/requestTarget_err01.phpt b/tests/Request/requestTarget_err01.phpt new file mode 100644 index 0000000..ff11a06 --- /dev/null +++ b/tests/Request/requestTarget_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +Request::withRequestTarget() with invalid arguments +--FILE-- +withRequestTarget(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withRequestTarget(['foo', 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Request::withRequestTarget() expects exactly 1 parameter, 0 given +HttpMessage\Request::withRequestTarget() expects parameter 1 to be string, array given diff --git a/tests/Request/uri_001.phpt b/tests/Request/uri_001.phpt new file mode 100644 index 0000000..644bdc8 --- /dev/null +++ b/tests/Request/uri_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +Request::withUri() +--FILE-- +withUri($uri); + +var_dump($request->getUri() === $uri); + +?> +--EXPECT-- +bool(true) \ No newline at end of file diff --git a/tests/Request/uri_err01.phpt b/tests/Request/uri_err01.phpt new file mode 100644 index 0000000..f6ba3a7 --- /dev/null +++ b/tests/Request/uri_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +Request::withUri() with invalid arguments +--FILE-- +withUri(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withUri('http://www.example.com/'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Request::withUri() expects exactly 1 parameter, 0 given +Argument 1 passed to HttpMessage\Request::withUri() must implement interface Psr\Http\Message\UriInterface, string given diff --git a/tests/Response/status_err01.phpt b/tests/Response/status_err01.phpt new file mode 100644 index 0000000..61a8bcf --- /dev/null +++ b/tests/Response/status_err01.phpt @@ -0,0 +1,29 @@ +--TEST-- +Response::withStatus() with invalid arguments +--FILE-- +withStatus(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withStatus('ok'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $response->withStatus(200, ['foo', 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Response::withStatus() expects at least 1 parameter, 0 given +HttpMessage\Response::withStatus() expects parameter 1 to be integer, string given +HttpMessage\Response::withStatus() expects parameter 2 to be string, array given \ No newline at end of file diff --git a/tests/ServerRequest/__construct_001.phpt b/tests/ServerRequest/__construct_001.phpt new file mode 100644 index 0000000..27640f9 --- /dev/null +++ b/tests/ServerRequest/__construct_001.phpt @@ -0,0 +1,60 @@ +--TEST-- +Create a ServerRequest without any arguments +--FILE-- + +--EXPECTF-- +object(HttpMessage\ServerRequest)#1 (12) { + ["protocolVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(0) { + } + ["body":protected]=> + object(HttpMessage\Stream)#2 (1) { + ["stream":protected]=> + resource(%d) of type (stream) + } + ["requestTarget":protected]=> + NULL + ["method":protected]=> + string(0) "" + ["uri":protected]=> + object(HttpMessage\Uri)#3 (7) { + ["scheme":protected]=> + string(0) "" + ["userInfo":protected]=> + string(0) "" + ["host":protected]=> + string(0) "" + ["port":protected]=> + NULL + ["path":protected]=> + string(0) "" + ["query":protected]=> + string(0) "" + ["fragment":protected]=> + string(0) "" + } + ["serverParams":protected]=> + array(0) { + } + ["cookieParams":protected]=> + array(0) { + } + ["queryParams":protected]=> + array(0) { + } + ["uploadedFiles":protected]=> + array(0) { + } + ["parsedBody":protected]=> + NULL + ["attributes":protected]=> + array(0) { + } +} \ No newline at end of file diff --git a/tests/ServerRequest/cookieParams_001.phpt b/tests/ServerRequest/cookieParams_001.phpt new file mode 100644 index 0000000..7ccab44 --- /dev/null +++ b/tests/ServerRequest/cookieParams_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +ServerRequest::withCookieParams() +--FILE-- +withCookieParams([ + 'foo' => 'bar', + 'color' => 'green', + 'user' => 22, + ]); + +var_dump($request->getCookieParams()); + +$newRequest = $request->withCookieParams(['user' => 32]); +var_dump($newRequest->getCookieParams()); + +?> +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "bar" + ["color"]=> + string(5) "green" + ["user"]=> + int(22) +} +array(1) { + ["user"]=> + int(32) +} \ No newline at end of file diff --git a/tests/ServerRequest/cookieParams_err01.phpt b/tests/ServerRequest/cookieParams_err01.phpt new file mode 100644 index 0000000..55c1475 --- /dev/null +++ b/tests/ServerRequest/cookieParams_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +ServerRequest::withCookieParams() with invalid arguments +--FILE-- +withCookieParams(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withCookieParams('foo=bar;'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\ServerRequest::withCookieParams() expects exactly 1 parameter, 0 given +Argument 1 passed to HttpMessage\ServerRequest::withCookieParams() must be of the type array, string given \ No newline at end of file diff --git a/tests/ServerRequest/parsedBody_001.phpt b/tests/ServerRequest/parsedBody_001.phpt new file mode 100644 index 0000000..0c4cbd5 --- /dev/null +++ b/tests/ServerRequest/parsedBody_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +ServerRequest::withParsedBody() +--FILE-- +withParsedBody([ + 'foo' => 'bar', + 'color' => 'green', + 'user' => 22, +]); +var_dump($arrRequest->getParsedBody()); + +$objRequest = $request->withParsedBody((object)[ + 'color' => 'red', + 'user' => 42, +]); +var_dump($objRequest->getParsedBody()); + +$nullRequest = $objRequest->withParsedBody(null); +var_dump($nullRequest->getParsedBody()); + +?> +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "bar" + ["color"]=> + string(5) "green" + ["user"]=> + int(22) +} +object(stdClass)#5 (2) { + ["color"]=> + string(3) "red" + ["user"]=> + int(42) +} +NULL \ No newline at end of file diff --git a/tests/ServerRequest/parsedBody_err01.phpt b/tests/ServerRequest/parsedBody_err01.phpt new file mode 100644 index 0000000..b148260 --- /dev/null +++ b/tests/ServerRequest/parsedBody_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +ServerRequest::withParsedBody() with invalid arguments +--FILE-- +withQueryParams(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withParsedBody('foo=bar;'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given +HttpMessage\ServerRequest::withParsedBody() expects parameter 1 to be array, string given \ No newline at end of file diff --git a/tests/ServerRequest/queryParams_001.phpt b/tests/ServerRequest/queryParams_001.phpt new file mode 100644 index 0000000..45fa06d --- /dev/null +++ b/tests/ServerRequest/queryParams_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +ServerRequest::withQueryParams() +--FILE-- +withQueryParams([ + 'foo' => 'bar', + 'color' => 'green', + 'user' => 22, + ]); + +var_dump($request->getQueryParams()); + +$newRequest = $request->withQueryParams(['user' => 32]); +var_dump($newRequest->getQueryParams()); + +?> +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "bar" + ["color"]=> + string(5) "green" + ["user"]=> + int(22) +} +array(1) { + ["user"]=> + int(32) +} \ No newline at end of file diff --git a/tests/ServerRequest/queryParams_err01.phpt b/tests/ServerRequest/queryParams_err01.phpt new file mode 100644 index 0000000..d66f8ca --- /dev/null +++ b/tests/ServerRequest/queryParams_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +ServerRequest::withQueryParams() with invalid arguments +--FILE-- +withQueryParams(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withQueryParams('foo=bar;'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given +Argument 1 passed to HttpMessage\ServerRequest::withQueryParams() must be of the type array, string given \ No newline at end of file From dd6405e1a0c50ea2b8494f9fc34fbc5b843eef42 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 18 Jun 2019 01:03:33 +0200 Subject: [PATCH 12/67] Uploaded file (untested) --- CMakeLists.txt | 2 +- macros.h | 4 + message.c | 2 +- uploaded_file.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 uploaded_file.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a7f3ac..4df572e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ add_custom_target(extension COMMAND phpize && ./configure && make && make instal WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) set(SOURCE_FILES php_http_message - http_message.c message.c request.c uri.c server_request.c response.c stream.c) + http_message.c message.c request.c uri.c server_request.c response.c stream.c uploaded_file.c) execute_process ( COMMAND php-config --include-dir diff --git a/macros.h b/macros.h index 35d02ff..40d05f0 100644 --- a/macros.h +++ b/macros.h @@ -42,6 +42,10 @@ ZEND_END_ARG_INFO() if (val != NULL) \ zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) +#define SET_STR_PROPERTY(className, property, val) \ + if (val != NULL) \ + zend_update_property_str(className, getThis(), ZEND_STRL(property), val) + #define HTTP_MESSAGE_ME(className, method) \ PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) diff --git a/message.c b/message.c index 012548e..ab42ade 100644 --- a/message.c +++ b/message.c @@ -57,7 +57,7 @@ PHP_METHOD(Message, __construct) /* $this->body = new Stream() */ body = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("body"), 0, &rv); object_init_ex(body, HttpMessage_Stream_ce); - if (body != NULL && Z_TYPE_P(body) == IS_OBJECT) { /* Should always be true */ + if (body != NULL) { /* Should always be true */ zend_call_method_with_0_params( body, HttpMessage_Stream_ce, &HttpMessage_Stream_ce->constructor, "__construct", NULL ); diff --git a/uploaded_file.c b/uploaded_file.c new file mode 100644 index 0000000..ade50e9 --- /dev/null +++ b/uploaded_file.c @@ -0,0 +1,262 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension - UploadedFile class | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_http_message.h" +#include "macros.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "SAPI.h" +#include "ext/standard/info.h" +#include "ext/standard/file.h" +#include "ext/psr/psr_http_message.h" +#include "ext/spl/spl_exceptions.h" + +#if HAVE_HTTP_MESSAGE + +zend_class_entry *HttpMessage_UploadedFile_ce; + +void uploaded_file_chmod(char *new_path) +{ + int oldmask; int ret; + + oldmask = umask(077); + umask(oldmask); + + ret = VCWD_CHMOD(new_path, 0666 & ~oldmask); + + if (ret == -1) { + php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); + } +} + +zend_bool move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_path_len) +{ + zend_bool successful = 0; + + if (SG(rfc1867_uploaded_files) && !zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to move '%s'; not an uploaded file", path); + return 0; + } + + if (php_check_open_basedir_ex(new_path, 1)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, + "Unable to move '%s' to '%s'; open_basedir restriction in effect", path, new_path); + return 0; + } + + if (VCWD_RENAME(path, new_path) == 0) { + successful = 1; +#ifndef PHP_WIN32 + uploaded_file_chmod(new_path); +#endif + } else if (php_copy_file_ex(path, new_path, STREAM_DISABLE_OPEN_BASEDIR) == SUCCESS) { + VCWD_UNLINK(path); + successful = 1; + } + + if (!successful) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to move '%s' to '%s'", path, new_path); + return 0; + } + + zend_hash_str_del(SG(rfc1867_uploaded_files), path, path_len); + return 1; +} + +/* __construct */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 0, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(UploadedFile, __construct) +{ + zend_string *file, *clientFilename = NULL, *clientMediaType = NULL; + zend_long size = 0, error = 0; + zend_bool size_is_null; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) + Z_PARAM_STR(file) + Z_PARAM_OPTIONAL + Z_PARAM_LONG_EX(size, size_is_null, 1, 0) + Z_PARAM_LONG(error) + Z_PARAM_STR_EX(clientFilename, 1, 0) + Z_PARAM_STR(clientMediaType) + ZEND_PARSE_PARAMETERS_END(); + + zend_update_property_str(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), file); + + if (!size_is_null) { + zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("size"), size); + } + zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("error"), error); + + SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientFilename", clientFilename); + SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientMediaType", clientMediaType); +} + +PHP_METHOD(UploadedFile, getStream) +{ + zval rv, *stream, *file, *zmoved, resource; + php_stream *resource_stream; + zend_bool opened; + + stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + + file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); + zmoved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + + if (Z_TYPE_P(zmoved) == IS_TRUE) { + zend_throw_exception(spl_ce_RuntimeException, "File '%s' has already been moved", Z_STRVAL_P(file)); + return; + } + + // Stream isn't set: create new stream for file + if (ZVAL_IS_NULL(stream)) { + resource_stream = php_stream_fopen(Z_STRVAL_P(file), 'r', &opened); + if (!opened) { + zend_throw_exception(spl_ce_RuntimeException, "Failed to open stream for '%s'", Z_STRVAL_P(file)); + return; + } + + php_stream_to_zval(resource_stream, &resource); + + object_init_ex(stream, HttpMessage_Stream_ce); + if (stream != NULL) { /* Should always be true */ + zend_call_method_with_1_params( + stream, HttpMessage_Stream_ce, &HttpMessage_Stream_ce->constructor, "__construct", NULL, &resource + ); + } + } + + RETURN_ZVAL(stream, 1, 0); +} + +PHP_METHOD(UploadedFile, moveTo) +{ + zval rv, *file, *zmoved; + char *new_path; + size_t new_path_len; + zend_bool moved; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH(new_path, new_path_len) + ZEND_PARSE_PARAMETERS_END(); + + file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); + zmoved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + + if (Z_TYPE_P(zmoved) == IS_TRUE) { + zend_throw_exception(spl_ce_RuntimeException, "File '%s' has already been moved", Z_STRVAL_P(file)); + return; + } + + moved = move_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file), new_path, new_path_len); + + zend_update_property_bool(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), moved); +} + +PHP_METHOD(UploadedFile, getSize) +{ + zval rv, *value; + + value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + + RETURN_ZVAL(value, 1, 0); +} + +PHP_METHOD(UploadedFile, getError) +{ + zval rv, *value; + + value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + + RETURN_ZVAL(value, 1, 0); +} + +PHP_METHOD(UploadedFile, getClientFilename) +{ + zval rv, *value; + + value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + + RETURN_ZVAL(value, 1, 0); +} + +PHP_METHOD(UploadedFile, getClientMediaType) +{ + zval rv, *value; + + value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + + RETURN_ZVAL(value, 1, 0); +} + +/* Define HttpMessage\UploadedFile class */ + +static const zend_function_entry uri_functions[] = { + PHP_ME(UploadedFile, __construct, arginfo_HttpMessageUploadedFile_construct, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME(UploadedFile, getStream) + HTTP_MESSAGE_ME(UploadedFile, moveTo) + HTTP_MESSAGE_ME(UploadedFile, getSize) + HTTP_MESSAGE_ME(UploadedFile, getError) + HTTP_MESSAGE_ME(UploadedFile, getClientFilename) + HTTP_MESSAGE_ME(UploadedFile, getClientMediaType) + PHP_FE_END +}; + +PHP_MINIT_FUNCTION(http_message_uri) +{ + zend_class_entry ce; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "UploadedFile", uri_functions); + + HttpMessage_UploadedFile_ce = zend_register_internal_class(&ce); + zend_class_implements(HttpMessage_UploadedFile_ce, 1, PsrHttpMessageUploadedFileInterface_ce_ptr); + + /* Properties */ + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("stream"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("file"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("size"), ZEND_ACC_PROTECTED); + zend_declare_property_long(HttpMessage_UploadedFile_ce, ZEND_STRL("error"), 0, ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientFilename"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientMediaType"), ZEND_ACC_PROTECTED); + + zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("moved"), ZEND_ACC_PRIVATE, 0); + + return SUCCESS; +} + +#endif From 8bc1ec806e210f5eacc395bd4e111c137a56c743 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 19 Jun 2019 18:46:39 +0200 Subject: [PATCH 13/67] UploadedFile implementation --- config.m4 | 4 +- http_message.c | 1 + php_http_message.h | 2 + stream.c | 6 +- tests/Stream/__toString_002.phpt | 2 +- tests/Stream/__toString_003.phpt | 19 ++++ tests/UploadedFile/__construct_001.phpt | 43 ++++++++ tests/UploadedFile/__construct_002.phpt | 43 ++++++++ tests/UploadedFile/__construct_003.phpt | 43 ++++++++ tests/UploadedFile/__construct_004.phpt | 36 ++++++ tests/UploadedFile/getStream_001.phpt | 29 +++++ tests/UploadedFile/getStream_002.phpt | 37 +++++++ tests/UploadedFile/getStream_err01.phpt | 14 +++ tests/UploadedFile/getStream_err02.phpt | 27 +++++ tests/UploadedFile/moveTo_001.phpt | 26 +++++ tests/UploadedFile/moveTo_002.phpt | 29 +++++ tests/UploadedFile/moveTo_err01.phpt | 14 +++ tests/UploadedFile/moveTo_err02.phpt | 30 +++++ tests/UploadedFile/moveTo_err03.phpt | 24 ++++ tests/UploadedFile/moveTo_err04.phpt | 26 +++++ uploaded_file.c | 139 ++++++++++++++++-------- 21 files changed, 543 insertions(+), 51 deletions(-) create mode 100644 tests/Stream/__toString_003.phpt create mode 100644 tests/UploadedFile/__construct_001.phpt create mode 100644 tests/UploadedFile/__construct_002.phpt create mode 100644 tests/UploadedFile/__construct_003.phpt create mode 100644 tests/UploadedFile/__construct_004.phpt create mode 100644 tests/UploadedFile/getStream_001.phpt create mode 100644 tests/UploadedFile/getStream_002.phpt create mode 100644 tests/UploadedFile/getStream_err01.phpt create mode 100644 tests/UploadedFile/getStream_err02.phpt create mode 100644 tests/UploadedFile/moveTo_001.phpt create mode 100644 tests/UploadedFile/moveTo_002.phpt create mode 100644 tests/UploadedFile/moveTo_err01.phpt create mode 100644 tests/UploadedFile/moveTo_err02.phpt create mode 100644 tests/UploadedFile/moveTo_err03.phpt create mode 100644 tests/UploadedFile/moveTo_err04.phpt diff --git a/config.m4 b/config.m4 index effe0a6..ac295f4 100644 --- a/config.m4 +++ b/config.m4 @@ -16,8 +16,8 @@ if test "$PHP_HTTP_MESSAGE" != "no"; then ]) AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message support]) - PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c, - $ext_shared) + PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c, + $ext_shared) PHP_ADD_EXTENSION_DEP([http_message], [psr], true) diff --git a/http_message.c b/http_message.c index f4cf620..acb0be8 100644 --- a/http_message.c +++ b/http_message.c @@ -67,6 +67,7 @@ PHP_MINIT_FUNCTION(http_message) PHP_MINIT(http_message_response)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(http_message_stream)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(http_message_uri)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU); return SUCCESS; } diff --git a/php_http_message.h b/php_http_message.h index 5846a2f..2cb7cd5 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -54,6 +54,7 @@ extern PHP_MINIT_FUNCTION(http_message_serverrequest); extern PHP_MINIT_FUNCTION(http_message_response); extern PHP_MINIT_FUNCTION(http_message_stream); extern PHP_MINIT_FUNCTION(http_message_uri); +extern PHP_MINIT_FUNCTION(http_message_uploadedfile); extern zend_module_entry http_message_module_entry; @@ -63,6 +64,7 @@ extern zend_class_entry *HttpMessage_ServerRequest_ce; extern zend_class_entry *HttpMessage_Response_ce; extern zend_class_entry *HttpMessage_Stream_ce; extern zend_class_entry *HttpMessage_Uri_ce; +extern zend_class_entry *HttpMessage_UploadedFile_ce; #endif diff --git a/stream.c b/stream.c index 96bf329..f380fa7 100644 --- a/stream.c +++ b/stream.c @@ -110,7 +110,11 @@ PHP_METHOD(Stream, __toString) } // Special case for 'php://input'. Need to reopen the resource, because seek doesn't work. - if (strcmp(stream->wrapper->wops->label, "PHP") == 0 && strcmp(stream->ops->label, "Input") == 0) { + if ( + stream->wrapper != NULL && + strcmp(stream->wrapper->wops->label, "PHP") == 0 && + strcmp(stream->ops->label, "Input") == 0 + ) { stream = php_stream_open_wrapper(stream->orig_path, stream->mode, 0, NULL); php_stream_to_zval(stream, zstream); } diff --git a/tests/Stream/__toString_002.phpt b/tests/Stream/__toString_002.phpt index b9b1587..7e3a16d 100644 --- a/tests/Stream/__toString_002.phpt +++ b/tests/Stream/__toString_002.phpt @@ -1,5 +1,5 @@ --TEST-- -Cast unreadable Stream to string +Cast unreadable Stream to string from non-readable stream --FILE-- +--CLEANUP-- + +--EXPECT-- +string(3) "foo" \ No newline at end of file diff --git a/tests/UploadedFile/__construct_001.phpt b/tests/UploadedFile/__construct_001.phpt new file mode 100644 index 0000000..5f714c7 --- /dev/null +++ b/tests/UploadedFile/__construct_001.phpt @@ -0,0 +1,43 @@ +--TEST-- +Create UploadedFile +--FILE-- +getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +?> +--CLEANUP-- + +--EXPECT-- +object(HttpMessage\UploadedFile)#1 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + string(17) "/tmp/uploadedfile" + ["size":protected]=> + int(99) + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + string(10) "myfile.txt" + ["clientMediaType":protected]=> + string(10) "text/plain" + ["moved":protected]=> + bool(false) + ["checkUploaded":protected]=> + bool(false) +} +int(99) +int(0) +string(10) "myfile.txt" +string(10) "text/plain" \ No newline at end of file diff --git a/tests/UploadedFile/__construct_002.phpt b/tests/UploadedFile/__construct_002.phpt new file mode 100644 index 0000000..fc2fb6a --- /dev/null +++ b/tests/UploadedFile/__construct_002.phpt @@ -0,0 +1,43 @@ +--TEST-- +Create UploadedFile with only a path +--FILE-- +getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +?> +--CLEANUP-- + +--EXPECT-- +object(HttpMessage\UploadedFile)#1 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + string(17) "/tmp/uploadedfile" + ["size":protected]=> + NULL + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) + ["checkUploaded":protected]=> + bool(false) +} +NULL +int(0) +NULL +NULL \ No newline at end of file diff --git a/tests/UploadedFile/__construct_003.phpt b/tests/UploadedFile/__construct_003.phpt new file mode 100644 index 0000000..7cae5ce --- /dev/null +++ b/tests/UploadedFile/__construct_003.phpt @@ -0,0 +1,43 @@ +--TEST-- +Create UploadedFile with only a path +--FILE-- +getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +?> +--CLEANUP-- + +--EXPECT-- +object(HttpMessage\UploadedFile)#1 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + NULL + ["size":protected]=> + NULL + ["error":protected]=> + int(1) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) + ["checkUploaded":protected]=> + bool(false) +} +NULL +int(1) +NULL +NULL \ No newline at end of file diff --git a/tests/UploadedFile/__construct_004.phpt b/tests/UploadedFile/__construct_004.phpt new file mode 100644 index 0000000..02624b1 --- /dev/null +++ b/tests/UploadedFile/__construct_004.phpt @@ -0,0 +1,36 @@ +--TEST-- +Create UploadedFile with only a path +--FILE-- +getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +?> +--EXPECT-- +object(HttpMessage\UploadedFile)#1 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + NULL + ["size":protected]=> + NULL + ["error":protected]=> + int(4) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) + ["checkUploaded":protected]=> + bool(false) +} +NULL +int(4) +NULL +NULL \ No newline at end of file diff --git a/tests/UploadedFile/getStream_001.phpt b/tests/UploadedFile/getStream_001.phpt new file mode 100644 index 0000000..d46784a --- /dev/null +++ b/tests/UploadedFile/getStream_001.phpt @@ -0,0 +1,29 @@ +--TEST-- +UploadedFile::getStream() +--FILE-- +getStream(); + +var_dump($stream); +var_dump($stream->getMetadata('uri')); +var_dump((string)$stream); +var_dump($stream == $upload->getStream()); + +?> +--CLEANUP-- + +--EXPECTF-- +object(HttpMessage\Stream)#2 (1) { + ["stream":protected]=> + resource(%d) of type (stream) +} +string(17) "/tmp/uploadedfile" +string(3) "foo" +bool(true) \ No newline at end of file diff --git a/tests/UploadedFile/getStream_002.phpt b/tests/UploadedFile/getStream_002.phpt new file mode 100644 index 0000000..27c8b60 --- /dev/null +++ b/tests/UploadedFile/getStream_002.phpt @@ -0,0 +1,37 @@ +--TEST-- +UploadedFile::getStream() after failed move +--FILE-- +moveTo(sys_get_temp_dir() . '/nosuchdir/movedfile'); +} catch (RuntimeException $e) { + // expected +} + +$stream = $upload->getStream(); + +var_dump($stream); +var_dump($stream->getMetadata('uri')); +var_dump((string)$stream); +var_dump($stream == $upload->getStream()); + +?> +--CLEANUP-- + +--EXPECTF-- +object(HttpMessage\Stream)#3 (1) { + ["stream":protected]=> + resource(%d) of type (stream) +} +string(17) "/tmp/uploadedfile" +string(3) "foo" +bool(true) \ No newline at end of file diff --git a/tests/UploadedFile/getStream_err01.phpt b/tests/UploadedFile/getStream_err01.phpt new file mode 100644 index 0000000..5364c3e --- /dev/null +++ b/tests/UploadedFile/getStream_err01.phpt @@ -0,0 +1,14 @@ +--TEST-- +UploadedFile::getStream() without a file +--FILE-- +getStream(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +No file was uploaded or uploaded file not available \ No newline at end of file diff --git a/tests/UploadedFile/getStream_err02.phpt b/tests/UploadedFile/getStream_err02.phpt new file mode 100644 index 0000000..ffb3221 --- /dev/null +++ b/tests/UploadedFile/getStream_err02.phpt @@ -0,0 +1,27 @@ +--TEST-- +UploadedFile::getStream() after move +--FILE-- +moveTo(sys_get_temp_dir() . '/movedfile'); + +try { + $upload->getStream(); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEANUP-- + +--EXPECT-- +Uploaded file '/tmp/uploadedfile' has already been moved diff --git a/tests/UploadedFile/moveTo_001.phpt b/tests/UploadedFile/moveTo_001.phpt new file mode 100644 index 0000000..78839f9 --- /dev/null +++ b/tests/UploadedFile/moveTo_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +UploadedFile::getStream() after move +--FILE-- +moveTo($target); + +var_dump(file_get_contents($target)); + +?> +--CLEANUP-- + +--EXPECT-- +string(3) "foo" \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_002.phpt b/tests/UploadedFile/moveTo_002.phpt new file mode 100644 index 0000000..5e7fcfe --- /dev/null +++ b/tests/UploadedFile/moveTo_002.phpt @@ -0,0 +1,29 @@ +--TEST-- +UploadedFile::moveTo() after failed move +--FILE-- +moveTo(sys_get_temp_dir() . '/nosuchdir/movedfile'); +} catch (RuntimeException $e) { + // expected +} + +$target = sys_get_temp_dir() . '/movedfile'; +$upload->moveTo($target); + +var_dump(file_get_contents($target)); + +?> +--CLEANUP-- + +--EXPECT-- +string(3) "foo" \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_err01.phpt b/tests/UploadedFile/moveTo_err01.phpt new file mode 100644 index 0000000..955da15 --- /dev/null +++ b/tests/UploadedFile/moveTo_err01.phpt @@ -0,0 +1,14 @@ +--TEST-- +UploadedFile::moveTo() without a file +--FILE-- +moveTo(sys_get_temp_dir() . '/movedfile'); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +No file was uploaded or uploaded file not available \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_err02.phpt b/tests/UploadedFile/moveTo_err02.phpt new file mode 100644 index 0000000..5a8d84a --- /dev/null +++ b/tests/UploadedFile/moveTo_err02.phpt @@ -0,0 +1,30 @@ +--TEST-- +UploadedFile::moveTo() after move +--FILE-- +moveTo(sys_get_temp_dir() . '/movedfile'); + +try { + $upload->moveTo(sys_get_temp_dir() . '/other'); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEANUP-- + +--EXPECT-- +Uploaded file '/tmp/uploadedfile' has already been moved diff --git a/tests/UploadedFile/moveTo_err03.phpt b/tests/UploadedFile/moveTo_err03.phpt new file mode 100644 index 0000000..650a7c0 --- /dev/null +++ b/tests/UploadedFile/moveTo_err03.phpt @@ -0,0 +1,24 @@ +--TEST-- +UploadedFile::moveTo() invalid target +--FILE-- +moveTo(sys_get_temp_dir() . '/nosuchdir/movedfile'); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEANUP-- + +--EXPECTF-- +Warning: HttpMessage\UploadedFile::moveTo(/tmp/nosuchdir/movedfile): failed to open stream: No such file or directory in %s/moveTo_err03.php on line %d +Failed to move uploaded file '/tmp/uploadedfile' to '/tmp/nosuchdir/movedfile' \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_err04.phpt b/tests/UploadedFile/moveTo_err04.phpt new file mode 100644 index 0000000..44be03e --- /dev/null +++ b/tests/UploadedFile/moveTo_err04.phpt @@ -0,0 +1,26 @@ +--TEST-- +UploadedFile::moveTo() with is_uploaded check +--FILE-- +moveTo(sys_get_temp_dir() . '/movedfile'); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEANUP-- + +--EXPECTF-- +Won't move '/tmp/uploadedfile'; not an uploaded file \ No newline at end of file diff --git a/uploaded_file.c b/uploaded_file.c index ade50e9..9b6e8f4 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -48,6 +48,32 @@ zend_class_entry *HttpMessage_UploadedFile_ce; +int assert_file_available(zval *file, zval *moved) +{ + if (ZVAL_IS_NULL(file)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "No file was uploaded or uploaded file not available"); + return FAILURE; + } + + if (Z_TYPE_P(moved) == IS_TRUE) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Uploaded file '%s' has already been moved", + Z_STRVAL_P(file)); + return FAILURE; + } + + return SUCCESS; +} + +zend_bool assert_uploaded_file(char *path, size_t path_len) +{ + if (SG(rfc1867_uploaded_files) == NULL || !zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Won't move '%s'; not an uploaded file", path); + return FAILURE; + } + + return SUCCESS; +} + void uploaded_file_chmod(char *new_path) { int oldmask; int ret; @@ -62,19 +88,15 @@ void uploaded_file_chmod(char *new_path) } } -zend_bool move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_path_len) +int move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_path_len) { + HashTable *uploaded_files; zend_bool successful = 0; - if (SG(rfc1867_uploaded_files) && !zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to move '%s'; not an uploaded file", path); - return 0; - } - if (php_check_open_basedir_ex(new_path, 1)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, - "Unable to move '%s' to '%s'; open_basedir restriction in effect", path, new_path); - return 0; + "Unable to move uploaded file '%s' to '%s'; open_basedir restriction in effect", path, new_path); + return FAILURE; } if (VCWD_RENAME(path, new_path) == 0) { @@ -88,67 +110,87 @@ zend_bool move_uploaded_file(char *path, size_t path_len, char *new_path, size_t } if (!successful) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to move '%s' to '%s'", path, new_path); - return 0; + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to move uploaded file '%s' to '%s'", + path, new_path); + return FAILURE; + } + + uploaded_files = SG(rfc1867_uploaded_files); + if (uploaded_files != NULL) { + zend_hash_str_del(uploaded_files, path, path_len); } - zend_hash_str_del(SG(rfc1867_uploaded_files), path, path_len); - return 1; + return SUCCESS; } /* __construct */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 0, 0) - ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) +ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 1, 0) + ZEND_ARG_TYPE_INFO(0, file, IS_STRING, 1) + ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 1) + ZEND_ARG_TYPE_INFO(0, error, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, clientFilename, IS_STRING, 1) + ZEND_ARG_TYPE_INFO(0, clientMediaType, IS_STRING, 1) + ZEND_ARG_INFO(0, checkUploaded) ZEND_END_ARG_INFO() PHP_METHOD(UploadedFile, __construct) { - zend_string *file, *clientFilename = NULL, *clientMediaType = NULL; + zend_string *file = NULL, *clientFilename = NULL, *clientMediaType = NULL; zend_long size = 0, error = 0; - zend_bool size_is_null; + zend_bool size_is_null, checkUploaded, checkUploaded_is_null; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) - Z_PARAM_STR(file) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 6) + Z_PARAM_STR_EX(file, 1, 0) Z_PARAM_OPTIONAL Z_PARAM_LONG_EX(size, size_is_null, 1, 0) Z_PARAM_LONG(error) Z_PARAM_STR_EX(clientFilename, 1, 0) - Z_PARAM_STR(clientMediaType) + Z_PARAM_STR_EX(clientMediaType, 1, 0) + Z_PARAM_BOOL_EX(checkUploaded, checkUploaded_is_null, 1, 0) ZEND_PARSE_PARAMETERS_END(); - zend_update_property_str(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), file); + if (error == 0) { + SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "file", file); + } + + SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientFilename", clientFilename); + SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientMediaType", clientMediaType); if (!size_is_null) { zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("size"), size); } + + if (error < 0 || error > 8) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %d", error); + } zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("error"), error); - SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientFilename", clientFilename); - SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientMediaType", clientMediaType); + if (checkUploaded_is_null) { + checkUploaded = SG(rfc1867_uploaded_files) != NULL; + } + zend_update_property_bool(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("checkUploaded"), checkUploaded); } PHP_METHOD(UploadedFile, getStream) { - zval rv, *stream, *file, *zmoved, resource; + zval rv, *stream, *file, *moved, resource; php_stream *resource_stream; - zend_bool opened; stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); - zmoved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); - if (Z_TYPE_P(zmoved) == IS_TRUE) { - zend_throw_exception(spl_ce_RuntimeException, "File '%s' has already been moved", Z_STRVAL_P(file)); + if (assert_file_available(file, moved) == FAILURE) { return; } // Stream isn't set: create new stream for file if (ZVAL_IS_NULL(stream)) { - resource_stream = php_stream_fopen(Z_STRVAL_P(file), 'r', &opened); - if (!opened) { - zend_throw_exception(spl_ce_RuntimeException, "Failed to open stream for '%s'", Z_STRVAL_P(file)); + resource_stream = php_stream_open_wrapper(Z_STRVAL_P(file), "r", 0, NULL); + if (resource_stream == NULL) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to open stream for '%s'", Z_STRVAL_P(file)); return; } @@ -167,33 +209,35 @@ PHP_METHOD(UploadedFile, getStream) PHP_METHOD(UploadedFile, moveTo) { - zval rv, *file, *zmoved; + zval rv, *file, *moved, *checkUploaded; char *new_path; size_t new_path_len; - zend_bool moved; + int move_ret; - ZEND_PARSE_PARAMETERS_START(2, 2) + ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH(new_path, new_path_len) ZEND_PARSE_PARAMETERS_END(); file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); - zmoved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + checkUploaded = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("checkUploaded"), 0, &rv); - if (Z_TYPE_P(zmoved) == IS_TRUE) { - zend_throw_exception(spl_ce_RuntimeException, "File '%s' has already been moved", Z_STRVAL_P(file)); + if ( + assert_file_available(file, moved) == FAILURE || + (Z_TYPE_P(checkUploaded) == IS_TRUE && assert_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file)) == FAILURE) + ) { return; } - moved = move_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file), new_path, new_path_len); - - zend_update_property_bool(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), moved); + move_ret = move_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file), new_path, new_path_len); + ZVAL_BOOL(moved, move_ret == SUCCESS); } PHP_METHOD(UploadedFile, getSize) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("size"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -202,7 +246,7 @@ PHP_METHOD(UploadedFile, getError) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("error"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -211,7 +255,7 @@ PHP_METHOD(UploadedFile, getClientFilename) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("clientFilename"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -220,14 +264,14 @@ PHP_METHOD(UploadedFile, getClientMediaType) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("clientMediaType"), 0, &rv); RETURN_ZVAL(value, 1, 0); } /* Define HttpMessage\UploadedFile class */ -static const zend_function_entry uri_functions[] = { +static const zend_function_entry methods[] = { PHP_ME(UploadedFile, __construct, arginfo_HttpMessageUploadedFile_construct, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(UploadedFile, getStream) HTTP_MESSAGE_ME(UploadedFile, moveTo) @@ -238,10 +282,10 @@ static const zend_function_entry uri_functions[] = { PHP_FE_END }; -PHP_MINIT_FUNCTION(http_message_uri) +PHP_MINIT_FUNCTION(http_message_uploadedfile) { zend_class_entry ce; - INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "UploadedFile", uri_functions); + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "UploadedFile", methods); HttpMessage_UploadedFile_ce = zend_register_internal_class(&ce); zend_class_implements(HttpMessage_UploadedFile_ce, 1, PsrHttpMessageUploadedFileInterface_ce_ptr); @@ -254,7 +298,8 @@ PHP_MINIT_FUNCTION(http_message_uri) zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientFilename"), ZEND_ACC_PROTECTED); zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientMediaType"), ZEND_ACC_PROTECTED); - zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("moved"), ZEND_ACC_PRIVATE, 0); + zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("moved"), 0, ZEND_ACC_PROTECTED); + zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("checkUploaded"), 0, ZEND_ACC_PROTECTED); return SUCCESS; } From 324331f00d9ef8201a665ba3b4c4060e3177f217 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Fri, 21 Jun 2019 11:38:04 +0200 Subject: [PATCH 14/67] Server request construct from params --- macros.h | 31 +++- php_http_message.h | 4 +- request.c | 25 ++- server_request.c | 180 +++++++++++++++++++- tests/Request/requestTarget_002.phpt | 10 +- tests/ServerRequest/__construct_002.phpt | 122 ++++++++++++++ tests/ServerRequest/__construct_003.phpt | 202 +++++++++++++++++++++++ tests/ServerRequest/__construct_004.phpt | 76 +++++++++ tests/ServerRequest/__construct_005.phpt | 152 +++++++++++++++++ uploaded_file.c | 137 ++++++++++++--- uri.c | 47 ++++-- 11 files changed, 931 insertions(+), 55 deletions(-) create mode 100644 tests/ServerRequest/__construct_002.phpt create mode 100644 tests/ServerRequest/__construct_003.phpt create mode 100644 tests/ServerRequest/__construct_004.phpt create mode 100644 tests/ServerRequest/__construct_005.phpt diff --git a/macros.h b/macros.h index 40d05f0..c82d18d 100644 --- a/macros.h +++ b/macros.h @@ -38,14 +38,14 @@ ZEND_END_ARG_INFO() #define INIT_ARRAY_PROPERTY(className, property, rv) \ array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)) +#define SET_ARRAY_PROPERTY(className, property, zval, rv) \ + if (zval == NULL) array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)); \ + else zend_update_property(className, getThis(), ZEND_STRL(property), zval) + #define SET_STRING_PROPERTY(className, property, val) \ if (val != NULL) \ zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) -#define SET_STR_PROPERTY(className, property, val) \ - if (val != NULL) \ - zend_update_property_str(className, getThis(), ZEND_STRL(property), val) - #define HTTP_MESSAGE_ME(className, method) \ PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) @@ -55,4 +55,27 @@ ZEND_END_ARG_INFO() (Z_RES_P(zstream)->type == php_file_le_stream() || Z_RES_P(zstream)->type == php_file_le_pstream()) \ ) +#define ARRAY_ADD(arr, index, key) \ + key == NULL ? zend_hash_index_add_empty_element(arr, index) : zend_hash_add_empty_element(arr, key) + +#define ARRAY_GET(arr, index, key) \ + arr != NULL ? (key == NULL ? zend_hash_index_find(arr, index) : zend_hash_find(arr, key)) : NULL + +#define COPY_PROPERTY_FROM_ARRAY(arr, key, className, object, property, type, val) \ + val = zend_hash_str_find(arr, ZEND_STRL(key)); \ + if (val != NULL && EXPECTED(Z_TYPE_P(val) == type)) { \ + zend_update_property(object, className, ZEND_STRL(property), val); \ + } + +#define Z_ARR_P_NULL(zval) zval != NULL ? Z_ARR_P(zval) : NULL + +#define Z_STRCMP(zval, match, def) \ + (zval == NULL || Z_TYPE_P(zval) != IS_STRING || Z_STRLEN_P(zval) == 0 ? def : \ + strncmp(match, Z_STRVAL_P(zval), Z_STRLEN_P(zval))) + +#define Z_STRVAL_P_NULL(zval) zval != NULL ? Z_STRVAL_P(zval) : NULL +#define Z_STRLEN_P_NULL(zval) zval != NULL ? Z_STRLEN_P(zval) : 0 + +#define STRLEN_NULL(str) str != NULL ? strlen(str) : 0 + #endif //HTTP_MESSAGE_MACROS_H diff --git a/php_http_message.h b/php_http_message.h index 2cb7cd5..522dd21 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -66,5 +66,7 @@ extern zend_class_entry *HttpMessage_Stream_ce; extern zend_class_entry *HttpMessage_Uri_ce; extern zend_class_entry *HttpMessage_UploadedFile_ce; -#endif +void create_uploaded_files(zval *objects, HashTable *files); +void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass_len); +#endif diff --git a/request.c b/request.c index fdd5901..00ade32 100644 --- a/request.c +++ b/request.c @@ -38,6 +38,7 @@ #include "macros.h" #include "zend_exceptions.h" #include "zend_interfaces.h" +#include "zend_smart_str.h" #include "ext/standard/info.h" #include "ext/psr/psr_http_message.h" @@ -70,15 +71,33 @@ PHP_METHOD(Request, __construct) PHP_METHOD(Request, getRequestTarget) { - zval rv, *value; + zval rv, *value, *uri, path, query; + smart_str buf = {0}; value = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("requestTarget"), 0, &rv); - if (ZVAL_IS_NULL(value)) { + if (!ZVAL_IS_NULL(value)) { + RETURN_ZVAL(value, 1, 0); + } + + uri = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); + zend_call_method_with_0_params(uri, NULL, NULL, "getPath", &path); + zend_call_method_with_0_params(uri, NULL, NULL, "getQuery", &query); + + if (UNEXPECTED(Z_TYPE(path) != IS_STRING) || Z_STRLEN(path) == 0) { RETURN_STRING("/"); } - RETURN_ZVAL(value, 1, 0); + if (Z_TYPE(query) != IS_STRING || Z_STRLEN(query) == 0) { + RETURN_ZVAL(&path, 1, 0); + } + + smart_str_appendl(&buf, Z_STRVAL(path), Z_STRLEN(path)); + smart_str_appends(&buf, "?"); + smart_str_appendl(&buf, Z_STRVAL(query), Z_STRLEN(query)); + + RETVAL_STR_COPY(buf.s); + zend_string_release(buf.s); } PHP_METHOD(Request, withRequestTarget) diff --git a/server_request.c b/server_request.c index caa8684..c8555a2 100644 --- a/server_request.c +++ b/server_request.c @@ -32,6 +32,7 @@ # include "config.h" #endif +#include #include "php.h" #include "php_ini.h" #include "php_http_message.h" @@ -45,29 +46,190 @@ zend_class_entry *HttpMessage_ServerRequest_ce; +int assert_uploaded_files(HashTable *array) +{ + zval *entry; + + ZEND_HASH_FOREACH_VAL(array, entry) { + if ( + Z_TYPE_P(entry) == IS_OBJECT && + EXPECTED(instanceof_function(Z_OBJCE_P(entry), PsrHttpMessageUploadedFileInterface_ce_ptr)) + ) { + continue; + } + + if (UNEXPECTED(Z_TYPE_P(entry) != IS_ARRAY || assert_uploaded_files(Z_ARR_P(entry)) == FAILURE)) { // recursion + zend_throw_exception(spl_ce_InvalidArgumentException, + "Expected all elements to implement Psr\\Http\\Message\\UploadedFileInterface", 0); + return FAILURE; + } + } ZEND_HASH_FOREACH_END(); + + return SUCCESS; +} + +void add_header_from_param(HashTable *headers, char *key, size_t keylen, zval *val) +{ + zval *new_header, valcpy; + zend_long index; + char header[256]; + char i; + zend_bool lower; // Turn next char to lower case + + if (UNEXPECTED(keylen > 255)) { + php_error_docref(NULL, E_WARNING, "Ignoring header '%s'; field to long", key); + return; + } + + strncpy(header, key, keylen); + header[keylen] = '\0'; + + for (i = 0, lower = 0; i < keylen; i++) { + if (lower && header[i] >= 65 && header[i] <= 90) { // is ASCII A-Z + header[i] += 32; // to lower case + } + + if (header[i] == '_') { + header[i] = '-'; + lower = 0; + } else { + lower = 1; + } + } + + new_header = zend_hash_str_add_empty_element(headers, header, keylen); + + array_init(new_header); + ZVAL_COPY(&valcpy, val); + add_next_index_zval(new_header, &valcpy); +} + +void init_headers_from_params(zval *object, HashTable *serverParams) +{ + zval rv, *val; + HashTable *headers; + zend_long index; + zend_string *key; + + headers = Z_ARR_P(zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv)); + + ZEND_HASH_FOREACH_KEY_VAL(serverParams, index, key, val) { + if (UNEXPECTED(key == NULL)) continue; + + if (ZSTR_LEN(key) > 5 && strncmp("HTTP_", ZSTR_VAL(key), 5) == 0 && EXPECTED(Z_TYPE_P(val) == IS_STRING)) { + add_header_from_param(headers, ZSTR_VAL(key) + 5, ZSTR_LEN(key) - 5, val); + } + } ZEND_HASH_FOREACH_END(); + + val = zend_hash_str_find(serverParams, ZEND_STRL("CONTENT_TYPE")); + if (val != NULL && EXPECTED(Z_TYPE_P(val) == IS_STRING)) { + add_header_from_param(headers, ZEND_STRL("CONTENT_TYPE"), val); + } + + val = zend_hash_str_find(serverParams, ZEND_STRL("CONTENT_LENGTH")); + if (val != NULL && EXPECTED(Z_TYPE_P(val) == IS_LONG)) { + add_header_from_param(headers, ZEND_STRL("CONTENT_LENGTH"), val); + } +} + +void init_uri_from_params(zval *object, HashTable *serverParams) +{ + zval rv, *uri, *tmp, *request_target, *protocol, *https, *user, *pass; + zend_long index, port = -1, default_port = -1; + zend_bool is_http; + + uri = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("uri"), 0, &rv); + + request_target = zend_hash_str_find(serverParams, ZEND_STRL("REQUEST_URI")); + zend_call_method(uri, HttpMessage_Uri_ce, &HttpMessage_Uri_ce->constructor, ZEND_STRL("__construct"), NULL, + request_target == NULL ? 0 : 1, request_target, NULL); + + COPY_PROPERTY_FROM_ARRAY(serverParams, "HTTP_HOST", uri, HttpMessage_Uri_ce, "host", IS_STRING, tmp); + COPY_PROPERTY_FROM_ARRAY(serverParams, "QUERY_STRING", uri, HttpMessage_Uri_ce, "query", IS_STRING, tmp); + + tmp = zend_hash_str_find(serverParams, ZEND_STRL("SERVER_PORT")); + if (tmp != NULL && EXPECTED(Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) > 0)) { + port = Z_LVAL_P(tmp); + } + + protocol = zend_hash_str_find(serverParams, ZEND_STRL("SERVER_PROTOCOL")); + https = zend_hash_str_find(serverParams, ZEND_STRL("HTTPS")); + is_http = protocol != NULL && Z_TYPE_P(protocol) == IS_STRING + ? (strncmp("HTTP/", Z_STRVAL_P(protocol), 5) == 0) + : (port > 0 && port == (Z_STRCMP(https, "off", 0) == 0 ? 80 : 443)); + + if (!is_http) { + // do nothing + } else if (Z_STRCMP(https, "off", 0) == 0) { + default_port = 80; + zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("scheme"), ZEND_STRL("http")); + } else { + default_port = 443; + zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("scheme"), ZEND_STRL("https")); + } + + if (port != default_port && port > 0) { + zend_update_property_long(HttpMessage_Uri_ce, uri, ZEND_STRL("port"), port); + } + + user = zend_hash_str_find(serverParams, ZEND_STRL("PHP_AUTH_USER")); + if (user != NULL) { + pass = zend_hash_str_find(serverParams, ZEND_STRL("PHP_AUTH_PASS")); + uri_set_userinfo(uri, Z_STRVAL_P(user), Z_STRLEN_P(user), Z_STRVAL_P_NULL(pass), Z_STRLEN_P_NULL(pass)); + } +} + /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageServerRequest_construct, 0, 0, 0) ZEND_ARG_TYPE_INFO(0, serverParams, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, cookieParams, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, queryParams, IS_ARRAY, 0) - ZEND_ARG_INFO(0, parsedBody) + ZEND_ARG_TYPE_INFO(0, postParams, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, files, IS_ARRAY, 0) ZEND_END_ARG_INFO() PHP_METHOD(ServerRequest, __construct) { - zval rv; + zval rv, uploadedFiles, *val; + zval *serverParams = NULL, *cookieParams = NULL, *queryParams = NULL, *post = NULL, *files = NULL; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 5) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_EX(serverParams, 1, 0) + Z_PARAM_ARRAY_EX(cookieParams, 1, 0) + Z_PARAM_ARRAY_EX(queryParams, 1, 0) + Z_PARAM_ARRAY_EX(post, 1, 0) + Z_PARAM_ARRAY_EX(files, 1, 0) + ZEND_PARSE_PARAMETERS_END(); /* parent::__construct() */ zend_call_method_with_0_params( getThis(), HttpMessage_Request_ce, &HttpMessage_Request_ce->constructor, "__construct", NULL ); - INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "serverParams", rv); - INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "cookieParams", rv); - INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "queryParams", rv); - INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "uploadedFiles", rv); + SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "serverParams", serverParams, rv); + SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "cookieParams", cookieParams, rv); + SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "queryParams", queryParams, rv); + + if (files != NULL) { + create_uploaded_files(&uploadedFiles, Z_ARR_P(files)); + zend_update_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("uploadedFiles"), &uploadedFiles); + } else { + INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "uploadedFiles", rv); + } + + if (post != NULL) { + zend_update_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("parsedBody"), post); + } + + if (serverParams != NULL) { + COPY_PROPERTY_FROM_ARRAY(Z_ARR_P(serverParams), "REQUEST_METHOD", getThis(), HttpMessage_ServerRequest_ce, + "method", IS_STRING, val); + init_headers_from_params(getThis(), Z_ARR_P(serverParams)); + init_uri_from_params(getThis(), Z_ARR_P(serverParams)); + } + INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "attributes", rv); } @@ -134,7 +296,7 @@ PHP_METHOD(ServerRequest, withQueryParams) } -/* queryParams */ +/* uploadedFiles */ PHP_METHOD(ServerRequest, getUploadedFiles) { @@ -153,6 +315,10 @@ PHP_METHOD(ServerRequest, withUploadedFiles) Z_PARAM_ARRAY(value); ZEND_PARSE_PARAMETERS_END(); + if (UNEXPECTED(assert_uploaded_files(Z_ARR_P(value)) == FAILURE)) { + return; + } + ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("uploadedFiles"), value); diff --git a/tests/Request/requestTarget_002.phpt b/tests/Request/requestTarget_002.phpt index 1005448..42fb9aa 100644 --- a/tests/Request/requestTarget_002.phpt +++ b/tests/Request/requestTarget_002.phpt @@ -3,9 +3,9 @@ Request::withRequestTarget() using Uri object --FILE-- withUri(new HttpMessage\Uri('http://www.example.com/foo:80')); + ->withUri(new HttpMessage\Uri('http://www.example.com/foo?color=red')); -$fooRequest = $request->withRequestTarget('/foo'); +$fooRequest = $request->withRequestTarget('/bar'); $defaultRequest = $fooRequest->withRequestTarget(null); var_dump($request->getRequestTarget()); @@ -14,6 +14,6 @@ var_dump($defaultRequest->getRequestTarget()); ?> --EXPECT-- -string(1) "/" -string(4) "/foo" -string(1) "/" +string(14) "/foo?color=red" +string(4) "/bar" +string(14) "/foo?color=red" \ No newline at end of file diff --git a/tests/ServerRequest/__construct_002.phpt b/tests/ServerRequest/__construct_002.phpt new file mode 100644 index 0000000..9a5bb70 --- /dev/null +++ b/tests/ServerRequest/__construct_002.phpt @@ -0,0 +1,122 @@ +--TEST-- +Create a ServerRequest with params +--FILE-- + 'POST', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/', + ], + ['session' => 999], + ['id' => '42', 'persist' => 'yes'], + ['id' => 42, 'date' => '2019-01-01', 'categories' => [22, 44]], + [ + 'document' => [ + 'tmp_name' => sys_get_temp_dir() . '/uploadedfile', + 'size' => 2822, + 'error' => UPLOAD_ERR_OK, + 'name' => 'document.pdf', + 'type' => 'application/pdf', + ], + ] +); + +var_dump($request); + +?> +--EXPECTF-- +object(HttpMessage\ServerRequest)#1 (12) { + ["protocolVersion":protected]=> + string(3) "1.1" + ["headers":protected]=> + array(1) { + ["Host"]=> + array(1) { + [0]=> + string(11) "example.com" + } + } + ["body":protected]=> + object(HttpMessage\Stream)#2 (1) { + ["stream":protected]=> + resource(%d) of type (stream) + } + ["requestTarget":protected]=> + NULL + ["method":protected]=> + string(4) "POST" + ["uri":protected]=> + object(HttpMessage\Uri)#3 (7) { + ["scheme":protected]=> + string(0) "" + ["userInfo":protected]=> + string(0) "" + ["host":protected]=> + string(11) "example.com" + ["port":protected]=> + NULL + ["path":protected]=> + string(6) "/foos/" + ["query":protected]=> + string(0) "" + ["fragment":protected]=> + string(0) "" + } + ["serverParams":protected]=> + array(3) { + ["REQUEST_METHOD"]=> + string(4) "POST" + ["HTTP_HOST"]=> + string(11) "example.com" + ["REQUEST_URI"]=> + string(6) "/foos/" + } + ["cookieParams":protected]=> + array(1) { + ["session"]=> + int(999) + } + ["queryParams":protected]=> + array(2) { + ["id"]=> + string(2) "42" + ["persist"]=> + string(3) "yes" + } + ["uploadedFiles":protected]=> + array(1) { + ["document"]=> + object(HttpMessage\UploadedFile)#4 (6) { + ["file":protected]=> + string(17) "/tmp/uploadedfile" + ["size":protected]=> + int(2822) + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + string(12) "document.pdf" + ["clientMediaType":protected]=> + string(15) "application/pdf" + ["checkUploaded":protected]=> + bool(false) + } + } + ["parsedBody":protected]=> + array(3) { + ["id"]=> + int(42) + ["date"]=> + string(10) "2019-01-01" + ["categories"]=> + array(2) { + [0]=> + int(22) + [1]=> + int(44) + } + } + ["attributes":protected]=> + array(0) { + } +} \ No newline at end of file diff --git a/tests/ServerRequest/__construct_003.phpt b/tests/ServerRequest/__construct_003.phpt new file mode 100644 index 0000000..6ab5289 --- /dev/null +++ b/tests/ServerRequest/__construct_003.phpt @@ -0,0 +1,202 @@ +--TEST-- +Create a ServerRequest with multiple uploaded files +--FILE-- + [ + 'tmp_name' => sys_get_temp_dir() . '/uploadedfile01', + 'size' => 2822, + 'error' => UPLOAD_ERR_OK, + 'name' => 'document.pdf', + 'type' => 'application/pdf', + ], + 'attachments' => [ + 'tmp_name' => [ + sys_get_temp_dir() . '/uploadedfile02', + sys_get_temp_dir() . '/uploadedfile03', + ], + 'size' => [ + 3724, + 263, + ], + 'error' => [ + UPLOAD_ERR_OK, + UPLOAD_ERR_OK, + ], + 'name' => [ + 'copy-id.pdf', + 'proof-of-residence.pdf', + ], + 'type' => [ + 'image/jpg', + 'application/pdf', + ], + ], + 'forms' => [ + 'tmp_name' => [ + 'g201' => sys_get_temp_dir() . '/uploadedfile04', + 'g202' => [ + 'a' => sys_get_temp_dir() . '/uploadedfile05', + 'c' => sys_get_temp_dir() . '/uploadedfile06', + ], + 'g301' => [ + sys_get_temp_dir() . '/uploadedfile07', + ], + ], + 'size' => [ + 'g201' => 942, + 'g202' => [ + 'a' => 2391, + 'c' => 485, + ], + 'g301' => [ + 4732, + 124901432, + ], + ], + 'error' => [ + 'g201' => UPLOAD_ERR_OK, + 'g202' => [ + 'a' => UPLOAD_ERR_OK, + 'b' => UPLOAD_ERR_NO_FILE, + 'c' => UPLOAD_ERR_PARTIAL, + ], + 'g301' => [ + UPLOAD_ERR_OK, + UPLOAD_ERR_FORM_SIZE, + ], + ], + 'name' => [ + ], + 'type' => [ + ], + ], + ] +); + +var_dump($request->getUploadedFiles()); + +?> +--EXPECT-- +array(3) { + ["document"]=> + object(HttpMessage\UploadedFile)#4 (6) { + ["file":protected]=> + string(19) "/tmp/uploadedfile01" + ["size":protected]=> + int(2822) + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + string(12) "document.pdf" + ["clientMediaType":protected]=> + string(15) "application/pdf" + ["checkUploaded":protected]=> + bool(false) + } + ["attachments"]=> + array(2) { + [0]=> + object(HttpMessage\UploadedFile)#5 (6) { + ["file":protected]=> + string(19) "/tmp/uploadedfile02" + ["size":protected]=> + int(3724) + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + string(11) "copy-id.pdf" + ["clientMediaType":protected]=> + string(9) "image/jpg" + ["checkUploaded":protected]=> + bool(false) + } + [1]=> + object(HttpMessage\UploadedFile)#6 (6) { + ["file":protected]=> + string(19) "/tmp/uploadedfile03" + ["size":protected]=> + int(263) + ["error":protected]=> + int(0) + ["clientFilename":protected]=> + string(22) "proof-of-residence.pdf" + ["clientMediaType":protected]=> + string(15) "application/pdf" + ["checkUploaded":protected]=> + bool(false) + } + } + ["forms"]=> + array(3) { + ["g201"]=> + object(HttpMessage\UploadedFile)#7 (4) { + ["file":protected]=> + string(19) "/tmp/uploadedfile04" + ["size":protected]=> + int(942) + ["error":protected]=> + int(0) + ["checkUploaded":protected]=> + bool(false) + } + ["g202"]=> + array(3) { + ["a"]=> + object(HttpMessage\UploadedFile)#8 (4) { + ["file":protected]=> + string(19) "/tmp/uploadedfile05" + ["size":protected]=> + int(2391) + ["error":protected]=> + int(0) + ["checkUploaded":protected]=> + bool(false) + } + ["b"]=> + object(HttpMessage\UploadedFile)#9 (2) { + ["error":protected]=> + int(4) + ["checkUploaded":protected]=> + bool(false) + } + ["c"]=> + object(HttpMessage\UploadedFile)#10 (3) { + ["size":protected]=> + int(485) + ["error":protected]=> + int(3) + ["checkUploaded":protected]=> + bool(false) + } + } + ["g301"]=> + array(2) { + [0]=> + object(HttpMessage\UploadedFile)#11 (4) { + ["file":protected]=> + string(19) "/tmp/uploadedfile07" + ["size":protected]=> + int(4732) + ["error":protected]=> + int(0) + ["checkUploaded":protected]=> + bool(false) + } + [1]=> + object(HttpMessage\UploadedFile)#12 (3) { + ["size":protected]=> + int(124901432) + ["error":protected]=> + int(2) + ["checkUploaded":protected]=> + bool(false) + } + } + } +} \ No newline at end of file diff --git a/tests/ServerRequest/__construct_004.phpt b/tests/ServerRequest/__construct_004.phpt new file mode 100644 index 0000000..d8ef1b2 --- /dev/null +++ b/tests/ServerRequest/__construct_004.phpt @@ -0,0 +1,76 @@ +--TEST-- +Create a ServerRequest with server params +--FILE-- + 'HTTP/1.1', + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + 'CONTENT_LENGTH' => 1324, + 'HTTP_ACCEPT' => 'text/html', + 'HTTP_ACCEPT_CHARSET' => 'utf-8', + 'HTTP_ACCEPT_ENCODING' => 'zip, deflate', + 'PHP_AUTH_USER' => 'john', + 'PHP_AUTH_PASS' => 'secret', + 'SERVER_PORT' => 80, + ] +); + +var_dump($request->getMethod()); +var_dump($request->getUri()); +var_dump($request->getHeaders()); + +?> +--EXPECT-- +string(4) "POST" +object(HttpMessage\Uri)#3 (7) { + ["scheme":protected]=> + string(4) "http" + ["userInfo":protected]=> + string(11) "john:secret" + ["host":protected]=> + string(11) "example.com" + ["port":protected]=> + NULL + ["path":protected]=> + string(6) "/foos/" + ["query":protected]=> + string(5) "bar=1" + ["fragment":protected]=> + string(0) "" +} +array(6) { + ["Host"]=> + array(1) { + [0]=> + string(11) "example.com" + } + ["Accept"]=> + array(1) { + [0]=> + string(9) "text/html" + } + ["Accept-Charset"]=> + array(1) { + [0]=> + string(5) "utf-8" + } + ["Accept-Encoding"]=> + array(1) { + [0]=> + string(12) "zip, deflate" + } + ["Content-Type"]=> + array(1) { + [0]=> + string(33) "application/x-www-form-urlencoded" + } + ["Content-Length"]=> + array(1) { + [0]=> + int(1324) + } +} \ No newline at end of file diff --git a/tests/ServerRequest/__construct_005.phpt b/tests/ServerRequest/__construct_005.phpt new file mode 100644 index 0000000..bb1d45e --- /dev/null +++ b/tests/ServerRequest/__construct_005.phpt @@ -0,0 +1,152 @@ +--TEST-- +Create a ServerRequest with server params for uri +--FILE-- + 'HTTP/1.1', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 80, + ] +); +echo $request->getUri(), "\n"; + +// HTTP (explicit) +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTPS' => 'off', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 80, + ] +); +echo $request->getUri(), "\n"; + +// HTTPS +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTPS' => 'on', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 443, + ] +); +echo $request->getUri(), "\n"; + +// Custom HTTP port +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTPS' => 'off', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 8080, + ] +); +echo $request->getUri(), "\n"; + +// HTTPS on port 80 +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTPS' => 'on', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 80, + ] +); +echo $request->getUri(), "\n"; + +// No protocol, but default HTTP port +$request = new HttpMessage\ServerRequest( + [ + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 80, + ] +); +echo $request->getUri(), "\n"; + +// No protocol, but default HTTPS port +$request = new HttpMessage\ServerRequest( + [ + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'SERVER_PORT' => 80, + ] +); +echo $request->getUri(), "\n"; + +// No protocol, no port +$request = new HttpMessage\ServerRequest( + [ + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + ] +); +echo $request->getUri(), "\n"; + +// User +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'PHP_AUTH_USER' => 'john' + ] +); +echo $request->getUri(), "\n"; + +// User + pass +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'PHP_AUTH_USER' => 'john', + 'PHP_AUTH_PASS' => 'secret', + ] +); +echo $request->getUri(), "\n"; + +// Only pass (ignored) +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'PHP_AUTH_PASS' => 'secret', + ] +); +echo $request->getUri(), "\n"; + +// Query string overwrite +$request = new HttpMessage\ServerRequest( + [ + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'QUERY_STRING' => 'bar=99', + ] +); +echo $request->getUri(), "\n"; + + +?> +--EXPECT-- +http://example.com/foos/?bar=1 +http://example.com/foos/?bar=1 +https://example.com/foos/?bar=1 +http://example.com:8080/foos/?bar=1 +https://example.com:80/foos/?bar=1 +http://example.com/foos/?bar=1 +http://example.com/foos/?bar=1 +//example.com/foos/?bar=1 +http://john@example.com/foos/?bar=1 +http://john:secret@example.com/foos/?bar=1 +http://example.com/foos/?bar=1 +http://example.com/foos/?bar=99 \ No newline at end of file diff --git a/uploaded_file.c b/uploaded_file.c index 9b6e8f4..b89dcff 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -123,6 +123,121 @@ int move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_p return SUCCESS; } +void construct_uploaded_file( + zval* object, + zend_string *file, + zend_long size, + zend_bool size_is_null, + zend_long error, + zend_string *clientFilename, + zend_string *clientMediaType, + char checkUploaded +) { + if (error == 0 && file != NULL) { + zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("file"), file); + } + if (clientFilename != NULL) { + zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientFilename"), clientFilename); + } + if (clientMediaType != NULL) { + zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientMediaType"), clientMediaType); + } + + if (!size_is_null) { + zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("size"), size); + } + if (error < 0 || error > 8) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %d", error); + } + zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("error"), error); + + if (checkUploaded < 0) { + checkUploaded = SG(rfc1867_uploaded_files) != NULL; + } + zend_update_property_bool(HttpMessage_UploadedFile_ce, object, ZEND_STRL("checkUploaded"), checkUploaded); +} + +void create_uploaded_file(zval *uploaded_file, zval *tmp_name, zval *size, zval *error, zval *name, zval *type) +{ + ZVAL_OBJ(uploaded_file, zend_objects_new(HttpMessage_UploadedFile_ce)); + + construct_uploaded_file( + uploaded_file, + tmp_name != NULL ? Z_STR_P(tmp_name) : NULL, + size != NULL ? Z_LVAL_P(size) : 0, + size == NULL || Z_TYPE_P(size) != IS_LONG, + Z_LVAL_P(error), + name != NULL ? Z_STR_P(name) : NULL, + type != NULL ? Z_STR_P(type) : NULL, + -1 // auto-detect check is_uploaded + ); +} + +void restructure_uploaded_files( + zval *objects, + HashTable *names, + HashTable *types, + HashTable *tmp_names, + HashTable *errors, + HashTable *sizes +) { + zval *name, *type, *tmp_name, *error, *size, *element; + zend_ulong index; + zend_string *key; + + ZEND_HASH_FOREACH_KEY_VAL(errors, index, key, error) { + element = ARRAY_ADD(Z_ARR_P(objects), index, key); + + name = ARRAY_GET(names, index, key); + type = ARRAY_GET(types, index, key); + tmp_name = ARRAY_GET(tmp_names, index, key); + size = ARRAY_GET(sizes, index, key); + + if (Z_TYPE_P(error) == IS_LONG) { + create_uploaded_file(element, tmp_name, size, error, name, type); + } else if (EXPECTED(Z_TYPE_P(error) == IS_ARRAY)) { + array_init(element); + restructure_uploaded_files(element, Z_ARR_P_NULL(name), Z_ARR_P_NULL(type), Z_ARR_P_NULL(tmp_name), + Z_ARR_P_NULL(error), Z_ARR_P_NULL(size)); // recursion + } + } ZEND_HASH_FOREACH_END(); +} + +void create_uploaded_files(zval *objects, HashTable *files) +{ + zval *zentry, *name, *type, *tmp_name, *error, *size, *element; + HashTable *entry; + zend_ulong index; + zend_string *key; + + array_init(objects); + + ZEND_HASH_FOREACH_KEY_VAL(files, index, key, zentry) { + if (UNEXPECTED(Z_TYPE_P(zentry) != IS_ARRAY)) continue; + + entry = Z_ARR_P(zentry); + error = zend_hash_str_find(entry, ZEND_STRL("error")); + + if (UNEXPECTED(error == NULL)) continue; + + name = zend_hash_str_find(entry, ZEND_STRL("name")); + type = zend_hash_str_find(entry, ZEND_STRL("type")); + tmp_name = zend_hash_str_find(entry, ZEND_STRL("tmp_name")); + size = zend_hash_str_find(entry, ZEND_STRL("size")); + + element = ARRAY_ADD(Z_ARR_P(objects), index, key); + + if (Z_TYPE_P(error) == IS_LONG) { + create_uploaded_file(element, tmp_name, size, error, name, type); + } else if (EXPECTED(Z_TYPE_P(error) == IS_ARRAY)) { + array_init(element); + restructure_uploaded_files(element, Z_ARR_P(name), Z_ARR_P(type), Z_ARR_P(tmp_name), Z_ARR_P(error) + , Z_ARR_P(size)); + } + } ZEND_HASH_FOREACH_END(); +} + + /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 1, 0) @@ -150,26 +265,8 @@ PHP_METHOD(UploadedFile, __construct) Z_PARAM_BOOL_EX(checkUploaded, checkUploaded_is_null, 1, 0) ZEND_PARSE_PARAMETERS_END(); - if (error == 0) { - SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "file", file); - } - - SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientFilename", clientFilename); - SET_STR_PROPERTY(HttpMessage_UploadedFile_ce, "clientMediaType", clientMediaType); - - if (!size_is_null) { - zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("size"), size); - } - - if (error < 0 || error > 8) { - zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %d", error); - } - zend_update_property_long(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("error"), error); - - if (checkUploaded_is_null) { - checkUploaded = SG(rfc1867_uploaded_files) != NULL; - } - zend_update_property_bool(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("checkUploaded"), checkUploaded); + construct_uploaded_file(getThis(), file, size, size_is_null, error, clientFilename, clientMediaType, + checkUploaded_is_null ? -1 : (char)checkUploaded); } PHP_METHOD(UploadedFile, getStream) diff --git a/uri.c b/uri.c index 900f7a1..2aa4308 100644 --- a/uri.c +++ b/uri.c @@ -47,6 +47,30 @@ zend_class_entry *HttpMessage_Uri_ce; +void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass_len) +{ + char *userinfo; + + if (user_len == 0 && pass_len == 0) { + return; + } + + if (pass_len == 0) { + zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("userInfo"), user, user_len); + } else { + userinfo = emalloc(user_len + pass_len + 2); + if (UNEXPECTED(userinfo == NULL)) return; // Memory issue + + user[user_len] = '\0'; + pass[pass_len] = '\0'; + sprintf(userinfo, "%s:%s", user, pass); + + zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("userInfo"), userinfo, user_len + pass_len + 1); + + efree(userinfo); + } +} + /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUri_construct, 0, 0, 0) @@ -56,7 +80,7 @@ ZEND_END_ARG_INFO() PHP_METHOD(Uri, __construct) { php_url *info; - char *value, *userinfo; + char *value; size_t value_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) @@ -82,14 +106,7 @@ PHP_METHOD(Uri, __construct) zend_update_property_long(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), info->port); } - if (info->pass == NULL) { - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "userInfo", info->user); - } else { - userinfo = emalloc(strlen(info->user) + strlen(info->pass) + 2); - sprintf(userinfo, "%s:%s", info->user, info->pass); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "userInfo", userinfo); - efree(userinfo); - } + uri_set_userinfo(getThis(), info->user, STRLEN_NULL(info->user), info->pass, STRLEN_NULL(info->pass)); } } @@ -207,20 +224,20 @@ PHP_METHOD(Uri, getAuthority) host = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); port = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); - if (Z_STRLEN(*host) == 0) { + if (Z_STRLEN_P(host) == 0) { RETURN_EMPTY_STRING(); } - if (Z_STRLEN(*userinfo) > 0) { - smart_str_appendl(&buf, Z_STRVAL(*userinfo), Z_STRLEN(*userinfo)); + if (Z_STRLEN_P(userinfo) > 0) { + smart_str_appendl(&buf, Z_STRVAL_P(userinfo), Z_STRLEN_P(userinfo)); smart_str_appends(&buf, "@"); } - smart_str_appendl(&buf, Z_STRVAL(*host), Z_STRLEN(*host)); + smart_str_appendl(&buf, Z_STRVAL_P(host), Z_STRLEN_P(host)); - if (Z_TYPE(*port) == IS_LONG) { + if (Z_TYPE_P(port) == IS_LONG) { smart_str_appends(&buf, ":"); - smart_str_append_long(&buf, Z_LVAL(*port)); + smart_str_append_long(&buf, Z_LVAL_P(port)); } RETVAL_STR_COPY(buf.s); From 202dadeadbbf27d6511235d4bc729da390db05ec Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 09:13:55 +0200 Subject: [PATCH 15/67] Fixed issues with headers and attributes array. Those arrays were not copied when adding an item. --- message.c | 70 +++++++++++++---------- server_request.c | 26 +++++---- tests/Message/body_001.phpt | 11 +++- tests/Message/headers_001.phpt | 12 ++-- tests/Message/headers_002.phpt | 6 +- tests/Request/method_001.phpt | 9 ++- tests/Request/requestTarget_001.phpt | 6 +- tests/Request/uri_001.phpt | 8 ++- tests/Response/status_001.phpt | 4 +- tests/ServerRequest/attributes_001.phpt | 52 +++++++++++++++++ tests/ServerRequest/attributes_err01.phpt | 22 +++++++ tests/ServerRequest/cookieParams_001.phpt | 4 +- tests/ServerRequest/parsedBody_001.phpt | 5 +- tests/ServerRequest/queryParams_001.phpt | 4 +- 14 files changed, 169 insertions(+), 70 deletions(-) create mode 100644 tests/ServerRequest/attributes_001.phpt create mode 100644 tests/ServerRequest/attributes_err01.phpt diff --git a/message.c b/message.c index ab42ade..19f5064 100644 --- a/message.c +++ b/message.c @@ -47,6 +47,32 @@ zend_class_entry *HttpMessage_Message_ce; +void add_header(zval *object, char *name, size_t name_len, zend_string *value, zend_bool added) +{ + zval rv, *headers_prop, *header_values; + HashTable *headers; + + headers_prop = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv); + + if (UNEXPECTED(Z_TYPE_P(headers_prop) != IS_ARRAY && Z_TYPE_P(headers_prop) != IS_ARRAY_EX)) { + return; // Shouldn't happen + } + + headers = zend_array_dup(Z_ARR_P(headers_prop)); + + header_values = zend_hash_str_find(headers, name, name_len); + if (header_values == NULL) { + header_values = zend_hash_str_add_empty_element(headers, name, name_len); + array_init(header_values); + } else if (!added) { + ZVAL_DEREF(header_values); + array_init(header_values); + } + add_next_index_str(header_values, value); + + ZVAL_ARR(headers_prop, headers); + +} /* __construct */ @@ -171,7 +197,6 @@ PHP_METHOD(Message, getHeaderLine) PHP_METHOD(Message, withHeader) { - zval rv, *headers, new_headers, header_values; char *name; size_t name_len = 0; zend_string *value; @@ -181,49 +206,30 @@ PHP_METHOD(Message, withHeader) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - ZVAL_COPY(&new_headers, headers); - - array_init(&header_values); - add_next_index_str(&header_values, value); - - add_assoc_zval_ex(&new_headers, name, name_len, &header_values); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), &new_headers); + add_header(return_value, name, name_len, value, 0); } -PHP_METHOD(Message, withAddedHeader) -{ - zval rv, *headers, *header_values; +PHP_METHOD(Message, withAddedHeader) { char *name; size_t name_len = 0; zend_string *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) - Z_PARAM_STRING(name, name_len) - Z_PARAM_STR(value) + Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - - header_values = zend_hash_str_find(Z_ARRVAL_P(headers), name, name_len); - if (header_values == NULL) { - array_init(header_values); - } - add_next_index_str(header_values, value); - - add_assoc_zval_ex(headers, name, name_len, header_values); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), headers); + add_header(return_value, name, name_len, value, 1); } PHP_METHOD(Message, withoutHeader) { - zval rv, *headers; + zval rv, *headers_prop; + HashTable *headers; char *name; size_t name_len = 0; @@ -231,12 +237,14 @@ PHP_METHOD(Message, withoutHeader) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - zend_hash_str_del(Z_ARRVAL_P(headers), name, name_len); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), headers); + headers_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), 0, &rv); + + headers = zend_array_dup(Z_ARR_P(headers_prop)); + zend_hash_str_del(headers, name, name_len); + + ZVAL_ARR(headers_prop, headers); } diff --git a/server_request.c b/server_request.c index c8555a2..7d9a711 100644 --- a/server_request.c +++ b/server_request.c @@ -392,7 +392,8 @@ PHP_METHOD(ServerRequest, getAttribute) PHP_METHOD(ServerRequest, withAttribute) { - zval rv, *value, *attributes, new_attributes; + zval rv, *value, *attributes_prop; + HashTable *attributes; char *name; size_t name_len; @@ -401,19 +402,19 @@ PHP_METHOD(ServerRequest, withAttribute) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); - attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); - ZVAL_COPY(&new_attributes, attributes); - - add_assoc_zval_ex(&new_attributes, name, name_len, value); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), &new_attributes); + attributes_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes = zend_array_dup(Z_ARR_P(attributes_prop)); + + zend_symtable_str_update(attributes, name, name_len, value); + ZVAL_ARR(attributes_prop, attributes); } PHP_METHOD(ServerRequest, withoutAttribute) { - zval rv, *attributes; + zval rv, *attributes_prop; + HashTable *attributes; char *name; size_t name_len; @@ -421,12 +422,13 @@ PHP_METHOD(ServerRequest, withoutAttribute) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); - attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); - zend_hash_str_del(Z_ARRVAL_P(attributes), name, name_len); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), attributes); + attributes_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes = zend_array_dup(Z_ARR_P(attributes_prop)); + + zend_symtable_str_del(attributes, name, name_len); + ZVAL_ARR(attributes_prop, attributes); } diff --git a/tests/Message/body_001.phpt b/tests/Message/body_001.phpt index b92ff0f..8c0d394 100644 --- a/tests/Message/body_001.phpt +++ b/tests/Message/body_001.phpt @@ -3,17 +3,22 @@ Message body --FILE-- getBody())); $resource = fopen('php://memory', 'w+'); $stream = new HttpMessage\Stream($resource); - $newResponse = $response->withBody($stream); + +var_dump(get_class($response->getBody())); +var_dump($response->getBody()->getMetadata('uri')); + var_dump(get_class($newResponse->getBody())); var_dump($newResponse->getBody() === $stream); +var_dump($newResponse->getBody()->getMetadata('uri')); ?> --EXPECT-- string(18) "HttpMessage\Stream" +string(10) "php://temp" string(18) "HttpMessage\Stream" -bool(true) \ No newline at end of file +bool(true) +string(12) "php://memory" \ No newline at end of file diff --git a/tests/Message/headers_001.phpt b/tests/Message/headers_001.phpt index 3c2227e..67c6a6f 100644 --- a/tests/Message/headers_001.phpt +++ b/tests/Message/headers_001.phpt @@ -3,6 +3,8 @@ Message headers --FILE-- withHeader('Foo', 'bar'); +$moreResponse = $fooResponse->withHeader('More', 'red'); var_dump($response->getHeaders()); var_dump($response->hasHeader('Foo')); @@ -10,19 +12,17 @@ var_dump($response->getHeader('Foo')); var_dump($response->getHeaderLine('Foo')); echo "\n"; -$fooResponse = $response->withHeader('Foo', 'bar'); var_dump($fooResponse->getHeaders()); var_dump($fooResponse->hasHeader('Foo')); var_dump($fooResponse->getHeader('Foo')); var_dump($fooResponse->getHeaderLine('Foo')); echo "\n"; -$moreResponse = $fooResponse->withHeader('More', 'red'); var_dump($moreResponse->getHeaders()); -var_dump($fooResponse->hasHeader('More')); -var_dump($fooResponse->getHeader('More')); -var_dump($fooResponse->getHeaderLine('More')); -var_dump($fooResponse->getHeaderLine('Foo')); +var_dump($moreResponse->hasHeader('More')); +var_dump($moreResponse->getHeader('More')); +var_dump($moreResponse->getHeaderLine('More')); +var_dump($moreResponse->getHeaderLine('Foo')); ?> --EXPECT-- diff --git a/tests/Message/headers_002.phpt b/tests/Message/headers_002.phpt index ab5b847..f52ca9d 100644 --- a/tests/Message/headers_002.phpt +++ b/tests/Message/headers_002.phpt @@ -6,22 +6,20 @@ Message headers; added header / without header $foofooResponse = (new HttpMessage\Response()) ->withHeader('Foo', 'bar') ->withAddedHeader('Foo', 'baz'); +$fooResponse = $foofooResponse->withHeader('Foo', 'box'); +$response = $foofooResponse->withoutHeader('Foo'); var_dump($foofooResponse->getHeaders()); var_dump($foofooResponse->hasHeader('Foo')); var_dump($foofooResponse->getHeader('Foo')); var_dump($foofooResponse->getHeaderLine('Foo')); -$fooResponse = $foofooResponse->withHeader('Foo', 'box'); - echo "\n"; var_dump($fooResponse->getHeaders()); var_dump($fooResponse->hasHeader('Foo')); var_dump($fooResponse->getHeader('Foo')); var_dump($fooResponse->getHeaderLine('Foo')); -$response = $foofooResponse->withoutHeader('Foo'); - echo "\n"; var_dump($response->getHeaders()); var_dump($response->hasHeader('Foo')); diff --git a/tests/Request/method_001.phpt b/tests/Request/method_001.phpt index a6a690c..0cd8c1a 100644 --- a/tests/Request/method_001.phpt +++ b/tests/Request/method_001.phpt @@ -2,11 +2,16 @@ Request::withMethod() --FILE-- withMethod('POST'); +$request = new HttpMessage\Request(); +$getRequest = $request->withMethod('GET'); +$postRequest = $getRequest->withMethod('POST'); var_dump($request->getMethod()); +var_dump($getRequest->getMethod()); +var_dump($postRequest->getMethod()); ?> --EXPECT-- +string(0) "" +string(3) "GET" string(4) "POST" \ No newline at end of file diff --git a/tests/Request/requestTarget_001.phpt b/tests/Request/requestTarget_001.phpt index 3d39df4..3b50b89 100644 --- a/tests/Request/requestTarget_001.phpt +++ b/tests/Request/requestTarget_001.phpt @@ -2,11 +2,13 @@ Request::withRequestTarget() --FILE-- withRequestTarget('/foo'); +$request = new HttpMessage\Request(); +$newRequest = $request->withRequestTarget('/foo'); var_dump($request->getRequestTarget()); +var_dump($newRequest->getRequestTarget()); ?> --EXPECT-- +string(1) "/" string(4) "/foo" \ No newline at end of file diff --git a/tests/Request/uri_001.phpt b/tests/Request/uri_001.phpt index 644bdc8..e44328f 100644 --- a/tests/Request/uri_001.phpt +++ b/tests/Request/uri_001.phpt @@ -4,11 +4,13 @@ Request::withUri() withUri($uri); +$request = (new HttpMessage\Request()); +$newRequest = $request->withUri($uri); -var_dump($request->getUri() === $uri); +var_dump($request->getUri() !== $uri); +var_dump($newRequest->getUri() === $uri); ?> --EXPECT-- +bool(true) bool(true) \ No newline at end of file diff --git a/tests/Response/status_001.phpt b/tests/Response/status_001.phpt index d9735eb..1ab889a 100644 --- a/tests/Response/status_001.phpt +++ b/tests/Response/status_001.phpt @@ -3,12 +3,14 @@ Response::withStatus() --FILE-- withStatus(200); + +var_dump($response->getStatusCode()); var_dump($newResponse->getStatusCode()); var_dump($newResponse->getReasonPhrase()); ?> --EXPECT-- +int(0) int(200) string(2) "OK" \ No newline at end of file diff --git a/tests/ServerRequest/attributes_001.phpt b/tests/ServerRequest/attributes_001.phpt new file mode 100644 index 0000000..2ae8c05 --- /dev/null +++ b/tests/ServerRequest/attributes_001.phpt @@ -0,0 +1,52 @@ +--TEST-- +ServerRequest::withAttribute() and ServerRequest::withoutAttribute() +--FILE-- +withAttribute('foo', 'bar') + ->withAttribute('colors', ['red', 'green']) + ->withAttribute('user', ['id' => 22, 'name' => 'John']); + +$newRequest = $request + ->withoutAttribute('foo') + ->withAttribute('user', ['id' => 32, 'name' => 'Jane']); + +var_dump($request->getAttributes()); +var_dump($newRequest->getAttributes()); + +?> +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "bar" + ["colors"]=> + array(2) { + [0]=> + string(3) "red" + [1]=> + string(5) "green" + } + ["user"]=> + array(2) { + ["id"]=> + int(22) + ["name"]=> + string(4) "John" + } +} +array(2) { + ["colors"]=> + array(2) { + [0]=> + string(3) "red" + [1]=> + string(5) "green" + } + ["user"]=> + array(2) { + ["id"]=> + int(32) + ["name"]=> + string(4) "Jane" + } +} \ No newline at end of file diff --git a/tests/ServerRequest/attributes_err01.phpt b/tests/ServerRequest/attributes_err01.phpt new file mode 100644 index 0000000..5299da3 --- /dev/null +++ b/tests/ServerRequest/attributes_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +ServerRequest::withAttribute() with invalid arguments +--FILE-- +withAttribute('foo'); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request->withAttribute(['foo' => 'bar'], 22); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\ServerRequest::withAttribute() expects exactly 2 parameters, 1 given +HttpMessage\ServerRequest::withAttribute() expects parameter 1 to be string, array given \ No newline at end of file diff --git a/tests/ServerRequest/cookieParams_001.phpt b/tests/ServerRequest/cookieParams_001.phpt index 7ccab44..e559659 100644 --- a/tests/ServerRequest/cookieParams_001.phpt +++ b/tests/ServerRequest/cookieParams_001.phpt @@ -9,9 +9,9 @@ $request = (new HttpMessage\ServerRequest) 'user' => 22, ]); -var_dump($request->getCookieParams()); - $newRequest = $request->withCookieParams(['user' => 32]); + +var_dump($request->getCookieParams()); var_dump($newRequest->getCookieParams()); ?> diff --git a/tests/ServerRequest/parsedBody_001.phpt b/tests/ServerRequest/parsedBody_001.phpt index 0c4cbd5..ea82db8 100644 --- a/tests/ServerRequest/parsedBody_001.phpt +++ b/tests/ServerRequest/parsedBody_001.phpt @@ -9,15 +9,16 @@ $arrRequest = $request->withParsedBody([ 'color' => 'green', 'user' => 22, ]); -var_dump($arrRequest->getParsedBody()); $objRequest = $request->withParsedBody((object)[ 'color' => 'red', 'user' => 42, ]); -var_dump($objRequest->getParsedBody()); $nullRequest = $objRequest->withParsedBody(null); + +var_dump($arrRequest->getParsedBody()); +var_dump($objRequest->getParsedBody()); var_dump($nullRequest->getParsedBody()); ?> diff --git a/tests/ServerRequest/queryParams_001.phpt b/tests/ServerRequest/queryParams_001.phpt index 45fa06d..afe06d7 100644 --- a/tests/ServerRequest/queryParams_001.phpt +++ b/tests/ServerRequest/queryParams_001.phpt @@ -9,9 +9,9 @@ $request = (new HttpMessage\ServerRequest) 'user' => 22, ]); -var_dump($request->getQueryParams()); - $newRequest = $request->withQueryParams(['user' => 32]); + +var_dump($request->getQueryParams()); var_dump($newRequest->getQueryParams()); ?> From b5cedf438251406ea992ef454546f1929750aeab Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 12:46:33 +0200 Subject: [PATCH 16/67] Added Travis and AppVeyor configuration --- .appveyor.yml | 13 +++++++++++-- .appveyor/build.cmd | 21 ++++++++++----------- .appveyor/test.cmd | 6 +++--- .travis.yml | 9 ++++----- CMakeLists.txt | 2 ++ config.w32 | 9 +++------ php_http_message.h | 3 --- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 52639fc..e894e9c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,15 +11,24 @@ environment: PHP_SDK_BINARY_TOOLS_URL: https://windows.php.net/downloads/php-sdk PHP_SDK_BINARY_TOOLS_PACKAGE: php-sdk-binary-tools-20110915.zip PHP_DEPS_URL: https://windows.php.net/downloads/php-sdk + PECL_PSR_URL: https://pecl.php.net/get/psr-0.6.1.tgz matrix: - - PHP_REL: 7.0 + - PHP_REL: 7.2 ARCHITECTURE: x64 ARCH: amd64 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PHP_BUILD_CRT: vc14 - PHP_DEPS_PACKAGE: deps-7.0-vc14-x64.7z + PHP_DEPS_PACKAGE: deps-7.2-vc14-x64.7z + - PHP_REL: 7.3 + ARCHITECTURE: x64 + ARCH: amd64 + ZTS_STATE: disable + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + PHP_BUILD_CRT: vc14 + PHP_DEPS_PACKAGE: deps-7.3-vc14-x64.7z + # Uncomment the following two lines to use RDP to debug "stuck" builds #init: diff --git a/.appveyor/build.cmd b/.appveyor/build.cmd index 5292e5d..75357ab 100644 --- a/.appveyor/build.cmd +++ b/.appveyor/build.cmd @@ -2,8 +2,6 @@ setlocal enableextensions enabledelayedexpansion - REM TODO: build external libraries - REM set up PHP mkdir C:\projects\php-sdk >NUL 2>NUL cd C:\projects\php-sdk @@ -22,12 +20,14 @@ setlocal enableextensions enabledelayedexpansion popd popd + REM download and install the psr extension from PECL + mkdir c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\psr + wget %PECL_PSR_URL% --no-check-certificate -q -O psr.tgz + 7z x -y psr.tgz -oc:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\psr + REM copy the extension into the PHP tree - mkdir c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\skeleton - xcopy c:\projects\skeleton-php-ext\*.* c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\skeleton /s/e/v - pushd c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\skeleton - del /q CREDITS - popd + mkdir c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\http_message + xcopy c:\projects\http_message-php-ext\*.* c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\http_message /s/e/v REM The bison utility is needed for the PHP build, so add MSYS to the path. REM Note: Add to the end to ensure MSVC tools are found firts. @@ -37,13 +37,12 @@ setlocal enableextensions enabledelayedexpansion cmd /c bin\phpsdk_setvars.bat pushd phpdev\vc14\x64\php-src cmd /c buildconf --force - cmd /c configure --disable-all --enable-cli --with-skeleton=shared + cmd /c configure --disable-all --enable-cli --with-extra-includes=c:\projects\libhttp_message --with-extra-libs=c:\projects\libhttp_message --with-psr=shared --with-http_message=shared nmake popd - REM TODO: debugging - - dir php_skeleton.dll /s + REM TODO:debugging + dir php_http_message.dll /s dir php.exe /s dir php*.dll /s diff --git a/.appveyor/test.cmd b/.appveyor/test.cmd index 255d475..1ec3fef 100644 --- a/.appveyor/test.cmd +++ b/.appveyor/test.cmd @@ -4,13 +4,13 @@ setlocal enableextensions enabledelayedexpansion cd C:\projects\php-sdk\phpdev\vc14\x64\php-src - pushd ext\skeleton + pushd ext\base58 echo [PHP] > php.ini echo extension_dir = "ext" >> php.ini - echo extension=php_skeleton.dll >> php.ini + echo extension=php_http_message.dll >> php.ini popd set TEST_PHP_EXECUTABLE=C:\projects\php-sdk\phpdev\vc14\x64\php-src\x64\Release_TS\php.exe - %TEST_PHP_EXECUTABLE% run-tests.php ext\skeleton -q --show-diff + %TEST_PHP_EXECUTABLE% run-tests.php ext\http_message -q --show-diff endlocal diff --git a/.travis.yml b/.travis.yml index 05c47f1..0ce94c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,21 @@ language: php php: - - 7.0 - - 7.1 - 7.2 + - 7.3 + - 7.4snapshot - nightly matrix: allow_failures: - - php: 7.0 + - php: 7.4snapshot - php: nightly - branches: only: - master before_install: - # Install external libraries + - pecl install psr install: - phpize diff --git a/CMakeLists.txt b/CMakeLists.txt index 4df572e..bd1fc04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.8) project(http_message C) +add_compile_definitions(HAVE_HTTP_MESSAGE) + add_custom_target(extension COMMAND phpize && ./configure && make && make install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) diff --git a/config.w32 b/config.w32 index 4feb5bc..a2ffe06 100644 --- a/config.w32 +++ b/config.w32 @@ -4,10 +4,7 @@ ARG_WITH("http_message", "Include http_message support", "no"); if (PHP_HTTP_MESSAGE != "no") { - if (true /* TODO: check external libs */) { - EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c"); - AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'Have http_message support'); - PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); - } + EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); + AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'Have http_message support'); + PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } - diff --git a/php_http_message.h b/php_http_message.h index 522dd21..95d8c96 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,9 +31,6 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -/* Temp for cmake */ -#define HAVE_HTTP_MESSAGE 1 - #define PHP_HTTP_MESSAGE_VERSION "0.0.1" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" From 2b860d2a18cb65c72b666610a0deed81dfe2a5db Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 13:05:24 +0200 Subject: [PATCH 17/67] Travis show log on failure --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0ce94c8..59c26c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,3 +28,11 @@ before_script: script: make test +after_failure: + - | + for LOG in $(find tests -name '*.log'); do + echo $LOG + tail -n +2 $LOG + echo + done + From e18c37a202c8516b612cdf547eee1fe265cd4c47 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 14:33:31 +0200 Subject: [PATCH 18/67] Fixes for PHP7.3+ integer -> int in TypeError php_url_parse_ex returns zend_string* instead of char* in 7.3+ is_null vars need to be initialized to true --- macros.h | 14 ++++++++++++-- request.c | 15 +++++++-------- tests/Response/status_err01.phpt | 4 ++-- tests/Stream/__toString_002.phpt | 2 +- tests/Stream/__toString_003.phpt | 2 +- tests/Stream/getContents_err01.phpt | 2 +- tests/Stream/isReadable_002.phpt | 2 +- tests/Stream/read_err02.phpt | 6 +++--- tests/Stream/read_err03.phpt | 2 +- tests/Stream/seek_err02.phpt | 10 +++++----- tests/UploadedFile/__construct_001.phpt | 2 +- tests/UploadedFile/__construct_002.phpt | 2 +- tests/UploadedFile/__construct_003.phpt | 2 +- tests/UploadedFile/getStream_001.phpt | 2 +- tests/UploadedFile/getStream_002.phpt | 2 +- tests/UploadedFile/getStream_err02.phpt | 2 +- tests/UploadedFile/moveTo_001.phpt | 2 +- tests/UploadedFile/moveTo_002.phpt | 2 +- tests/UploadedFile/moveTo_err02.phpt | 2 +- tests/UploadedFile/moveTo_err03.phpt | 2 +- tests/UploadedFile/moveTo_err04.phpt | 2 +- tests/Uri/port_err01.phpt | 6 +++--- uploaded_file.c | 16 +++++++--------- uri.c | 14 +++++++++----- 24 files changed, 64 insertions(+), 53 deletions(-) diff --git a/macros.h b/macros.h index c82d18d..bb834cd 100644 --- a/macros.h +++ b/macros.h @@ -43,8 +43,16 @@ ZEND_END_ARG_INFO() else zend_update_property(className, getThis(), ZEND_STRL(property), zval) #define SET_STRING_PROPERTY(className, property, val) \ - if (val != NULL) \ - zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) + if (val != NULL) zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) + +#define SET_STR_PROPERTY(className, property, val) \ + if (val != NULL) zend_update_property_str(className, getThis(), ZEND_STRL(property), val) + +#if PHP_VERSION_ID < 70300 +#define SET_URI_PROPERTY(className, property, val) SET_STRING_PROPERTY(className, property, val) +#else +#define SET_URI_PROPERTY(className, property, val) SET_STR_PROPERTY(className, property, val) +#endif #define HTTP_MESSAGE_ME(className, method) \ PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) @@ -76,6 +84,8 @@ ZEND_END_ARG_INFO() #define Z_STRVAL_P_NULL(zval) zval != NULL ? Z_STRVAL_P(zval) : NULL #define Z_STRLEN_P_NULL(zval) zval != NULL ? Z_STRLEN_P(zval) : 0 +#define ZSTR_VAL_LEN(zstr) zstr != NULL ? ZSTR_VAL(zstr) : NULL, zstr != NULL ? ZSTR_LEN(zstr) : 0 + #define STRLEN_NULL(str) str != NULL ? strlen(str) : 0 #endif //HTTP_MESSAGE_MACROS_H diff --git a/request.c b/request.c index 00ade32..05a3942 100644 --- a/request.c +++ b/request.c @@ -102,20 +102,19 @@ PHP_METHOD(Request, getRequestTarget) PHP_METHOD(Request, withRequestTarget) { - zval *value; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_ZVAL(value) + Z_PARAM_STR_EX(value, 1, 0) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(value) != IS_STRING && !ZVAL_IS_NULL(value)) { - zend_wrong_parameter_type_error(ZEND_PARSE_PARAMS_THROW, 1, Z_EXPECTED_STRING, value); - return; - } - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value); + if (value != NULL) { + zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value); + } else { + zend_update_property_null(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget")); + } } diff --git a/tests/Response/status_err01.phpt b/tests/Response/status_err01.phpt index 61a8bcf..9c028ea 100644 --- a/tests/Response/status_err01.phpt +++ b/tests/Response/status_err01.phpt @@ -13,7 +13,7 @@ try { try { $response->withStatus('ok'); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } try { @@ -25,5 +25,5 @@ try { ?> --EXPECT-- HttpMessage\Response::withStatus() expects at least 1 parameter, 0 given -HttpMessage\Response::withStatus() expects parameter 1 to be integer, string given +HttpMessage\Response::withStatus() expects parameter 1 to be int, string given HttpMessage\Response::withStatus() expects parameter 2 to be string, array given \ No newline at end of file diff --git a/tests/Stream/__toString_002.phpt b/tests/Stream/__toString_002.phpt index 7e3a16d..1cbcb2e 100644 --- a/tests/Stream/__toString_002.phpt +++ b/tests/Stream/__toString_002.phpt @@ -7,7 +7,7 @@ $stream = new HttpMessage\Stream($resource); var_dump((string)$stream); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/Stream/__toString_003.phpt b/tests/Stream/__toString_003.phpt index 84ac546..e4fabb9 100644 --- a/tests/Stream/__toString_003.phpt +++ b/tests/Stream/__toString_003.phpt @@ -11,7 +11,7 @@ $stream = new HttpMessage\Stream($resource); var_dump((string)$stream); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/Stream/getContents_err01.phpt b/tests/Stream/getContents_err01.phpt index 0df2461..50df873 100644 --- a/tests/Stream/getContents_err01.phpt +++ b/tests/Stream/getContents_err01.phpt @@ -11,7 +11,7 @@ try { echo $e->getMessage(); } ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/Stream/isReadable_002.phpt b/tests/Stream/isReadable_002.phpt index 64ece51..62f21fe 100644 --- a/tests/Stream/isReadable_002.phpt +++ b/tests/Stream/isReadable_002.phpt @@ -7,7 +7,7 @@ $stream = new HttpMessage\Stream($resource); var_dump($stream->isReadable()); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/Stream/read_err02.phpt b/tests/Stream/read_err02.phpt index 0ecabad..3088a37 100644 --- a/tests/Stream/read_err02.phpt +++ b/tests/Stream/read_err02.phpt @@ -8,7 +8,7 @@ $stream = new HttpMessage\Stream($resource); try { $stream->read('hello'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } try { @@ -17,6 +17,6 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Stream::read() expects parameter 1 to be integer, string given +--EXPECTF-- +HttpMessage\Stream::read() expects parameter 1 to be int, string given Length parameter must be equal or greater than 0 diff --git a/tests/Stream/read_err03.phpt b/tests/Stream/read_err03.phpt index 4e28e2e..4d75943 100644 --- a/tests/Stream/read_err03.phpt +++ b/tests/Stream/read_err03.phpt @@ -11,7 +11,7 @@ try { echo $e->getMessage(); } ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/Stream/seek_err02.phpt b/tests/Stream/seek_err02.phpt index 3c84f1a..70f7de1 100644 --- a/tests/Stream/seek_err02.phpt +++ b/tests/Stream/seek_err02.phpt @@ -8,15 +8,15 @@ $stream = new HttpMessage\Stream($resource); try { $stream->seek('hello'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } try { $stream->seek(1, 'hello'); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } ?> ---EXPECT-- -HttpMessage\Stream::seek() expects parameter 1 to be integer, string given -HttpMessage\Stream::seek() expects parameter 2 to be integer, string given +--EXPECTF-- +HttpMessage\Stream::seek() expects parameter 1 to be int, string given +HttpMessage\Stream::seek() expects parameter 2 to be int, string given diff --git a/tests/UploadedFile/__construct_001.phpt b/tests/UploadedFile/__construct_001.phpt index 5f714c7..8a42785 100644 --- a/tests/UploadedFile/__construct_001.phpt +++ b/tests/UploadedFile/__construct_001.phpt @@ -14,7 +14,7 @@ var_dump($upload->getClientFilename()); var_dump($upload->getClientMediaType()); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/UploadedFile/__construct_002.phpt b/tests/UploadedFile/__construct_002.phpt index fc2fb6a..a12aa53 100644 --- a/tests/UploadedFile/__construct_002.phpt +++ b/tests/UploadedFile/__construct_002.phpt @@ -14,7 +14,7 @@ var_dump($upload->getClientFilename()); var_dump($upload->getClientMediaType()); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/UploadedFile/__construct_003.phpt b/tests/UploadedFile/__construct_003.phpt index 7cae5ce..83ab6fb 100644 --- a/tests/UploadedFile/__construct_003.phpt +++ b/tests/UploadedFile/__construct_003.phpt @@ -14,7 +14,7 @@ var_dump($upload->getClientFilename()); var_dump($upload->getClientMediaType()); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/UploadedFile/getStream_001.phpt b/tests/UploadedFile/getStream_001.phpt index d46784a..3e23366 100644 --- a/tests/UploadedFile/getStream_001.phpt +++ b/tests/UploadedFile/getStream_001.phpt @@ -15,7 +15,7 @@ var_dump((string)$stream); var_dump($stream == $upload->getStream()); ?> ---CLEANUP-- +--CLEAN-- diff --git a/tests/UploadedFile/getStream_002.phpt b/tests/UploadedFile/getStream_002.phpt index 27c8b60..7c03280 100644 --- a/tests/UploadedFile/getStream_002.phpt +++ b/tests/UploadedFile/getStream_002.phpt @@ -21,7 +21,7 @@ var_dump((string)$stream); var_dump($stream == $upload->getStream()); ?> ---CLEANUP-- +--CLEAN-- getMessage(), "\n"; } ?> ---CLEANUP-- +--CLEAN-- moveTo($target); var_dump(file_get_contents($target)); ?> ---CLEANUP-- +--CLEAN-- moveTo($target); var_dump(file_get_contents($target)); ?> ---CLEANUP-- +--CLEAN-- getMessage(), "\n"; } ?> ---CLEANUP-- +--CLEAN-- getMessage(), "\n"; } ?> ---CLEANUP-- +--CLEAN-- getMessage(), "\n"; } ?> ---CLEANUP-- +--CLEAN-- withPort(['port' => 80]); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withPort() expects parameter 1 to be integer, array given +--EXPECTF-- +HttpMessage\Uri::withPort() expects parameter 1 to be int, array given diff --git a/uploaded_file.c b/uploaded_file.c index b89dcff..cbb5a47 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -127,7 +127,6 @@ void construct_uploaded_file( zval* object, zend_string *file, zend_long size, - zend_bool size_is_null, zend_long error, zend_string *clientFilename, zend_string *clientMediaType, @@ -143,11 +142,11 @@ void construct_uploaded_file( zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientMediaType"), clientMediaType); } - if (!size_is_null) { + if (size > 0) { zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("size"), size); } if (error < 0 || error > 8) { - zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %d", error); + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %ld", error); } zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("error"), error); @@ -164,8 +163,7 @@ void create_uploaded_file(zval *uploaded_file, zval *tmp_name, zval *size, zval construct_uploaded_file( uploaded_file, tmp_name != NULL ? Z_STR_P(tmp_name) : NULL, - size != NULL ? Z_LVAL_P(size) : 0, - size == NULL || Z_TYPE_P(size) != IS_LONG, + size != NULL ? Z_LVAL_P(size) : -1, Z_LVAL_P(error), name != NULL ? Z_STR_P(name) : NULL, type != NULL ? Z_STR_P(type) : NULL, @@ -252,8 +250,8 @@ ZEND_END_ARG_INFO() PHP_METHOD(UploadedFile, __construct) { zend_string *file = NULL, *clientFilename = NULL, *clientMediaType = NULL; - zend_long size = 0, error = 0; - zend_bool size_is_null, checkUploaded, checkUploaded_is_null; + zend_long size = -1, error = 0; + zend_bool size_is_null = 1, checkUploaded = 0, checkUploaded_is_null = 1; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 6) Z_PARAM_STR_EX(file, 1, 0) @@ -265,8 +263,8 @@ PHP_METHOD(UploadedFile, __construct) Z_PARAM_BOOL_EX(checkUploaded, checkUploaded_is_null, 1, 0) ZEND_PARSE_PARAMETERS_END(); - construct_uploaded_file(getThis(), file, size, size_is_null, error, clientFilename, clientMediaType, - checkUploaded_is_null ? -1 : (char)checkUploaded); + construct_uploaded_file(getThis(), file, size_is_null ? -1 : size, error, clientFilename, clientMediaType, + checkUploaded_is_null ? -1 : checkUploaded); } PHP_METHOD(UploadedFile, getStream) diff --git a/uri.c b/uri.c index 2aa4308..6d185a3 100644 --- a/uri.c +++ b/uri.c @@ -96,17 +96,21 @@ PHP_METHOD(Uri, __construct) return; } - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "scheme", info->scheme); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "host", info->host); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "path", info->path); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "query", info->query); - SET_STRING_PROPERTY(HttpMessage_Uri_ce, "fragment", info->fragment); + SET_URI_PROPERTY(HttpMessage_Uri_ce, "scheme", info->scheme); + SET_URI_PROPERTY(HttpMessage_Uri_ce, "host", info->host); + SET_URI_PROPERTY(HttpMessage_Uri_ce, "path", info->path); + SET_URI_PROPERTY(HttpMessage_Uri_ce, "query", info->query); + SET_URI_PROPERTY(HttpMessage_Uri_ce, "fragment", info->fragment); if (info->port > 0) { zend_update_property_long(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), info->port); } +#if PHP_VERSION_ID < 70300 uri_set_userinfo(getThis(), info->user, STRLEN_NULL(info->user), info->pass, STRLEN_NULL(info->pass)); +#else + uri_set_userinfo(getThis(), ZSTR_VAL_LEN(info->user), ZSTR_VAL_LEN(info->pass)); +#endif } } From 02cacc95f5036c2f62095d3da714c65c04b13d6b Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 15:11:55 +0200 Subject: [PATCH 19/67] Please don't fail on PHP 7.4 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59c26c4..f5d3e4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ php: matrix: allow_failures: - - php: 7.4snapshot - php: nightly branches: @@ -15,7 +14,7 @@ branches: - master before_install: - - pecl install psr + - pecl install --nodeps psr install: - phpize From 5bae43113c12be6b0934a5fb4ae0e54e0dbf358e Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 15:53:33 +0200 Subject: [PATCH 20/67] Segfault fix in ServerRequest::__construct() --- server_request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server_request.c b/server_request.c index 7d9a711..550cbed 100644 --- a/server_request.c +++ b/server_request.c @@ -191,7 +191,7 @@ ZEND_END_ARG_INFO() PHP_METHOD(ServerRequest, __construct) { - zval rv, uploadedFiles, *val; + zval rv, *uploadedFiles, *val; zval *serverParams = NULL, *cookieParams = NULL, *queryParams = NULL, *post = NULL, *files = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 5) @@ -213,8 +213,8 @@ PHP_METHOD(ServerRequest, __construct) SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "queryParams", queryParams, rv); if (files != NULL) { - create_uploaded_files(&uploadedFiles, Z_ARR_P(files)); - zend_update_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("uploadedFiles"), &uploadedFiles); + uploadedFiles = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("uploadedFiles"), 0, &rv); + create_uploaded_files(uploadedFiles, Z_ARR_P(files)); } else { INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "uploadedFiles", rv); } From 112610b96f14ef56a6c12d3e57a5bfca5f7684ec Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 24 Jun 2019 17:41:23 +0200 Subject: [PATCH 21/67] Init UploadedFile properties when created from $_FILES Run travis branch on Travis --- .gitignore | 1 + .travis.yml | 1 + tests/ServerRequest/__construct_002.phpt | 6 +- tests/ServerRequest/__construct_003.phpt | 86 +++++++++++++++++++++--- uploaded_file.c | 7 +- 5 files changed, 90 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index d81a2f5..c01a1c1 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ configure.ac cmake-build-* vendor composer.lock +tmp-php.ini diff --git a/.travis.yml b/.travis.yml index f5d3e4d..5fdc859 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ matrix: branches: only: - master + - travis before_install: - pecl install --nodeps psr diff --git a/tests/ServerRequest/__construct_002.phpt b/tests/ServerRequest/__construct_002.phpt index 9a5bb70..f33c5d6 100644 --- a/tests/ServerRequest/__construct_002.phpt +++ b/tests/ServerRequest/__construct_002.phpt @@ -87,7 +87,9 @@ object(HttpMessage\ServerRequest)#1 (12) { ["uploadedFiles":protected]=> array(1) { ["document"]=> - object(HttpMessage\UploadedFile)#4 (6) { + object(HttpMessage\UploadedFile)#4 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(17) "/tmp/uploadedfile" ["size":protected]=> @@ -98,6 +100,8 @@ object(HttpMessage\ServerRequest)#1 (12) { string(12) "document.pdf" ["clientMediaType":protected]=> string(15) "application/pdf" + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } diff --git a/tests/ServerRequest/__construct_003.phpt b/tests/ServerRequest/__construct_003.phpt index 6ab5289..76bc937 100644 --- a/tests/ServerRequest/__construct_003.phpt +++ b/tests/ServerRequest/__construct_003.phpt @@ -85,7 +85,9 @@ var_dump($request->getUploadedFiles()); --EXPECT-- array(3) { ["document"]=> - object(HttpMessage\UploadedFile)#4 (6) { + object(HttpMessage\UploadedFile)#4 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile01" ["size":protected]=> @@ -96,13 +98,17 @@ array(3) { string(12) "document.pdf" ["clientMediaType":protected]=> string(15) "application/pdf" + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } ["attachments"]=> array(2) { [0]=> - object(HttpMessage\UploadedFile)#5 (6) { + object(HttpMessage\UploadedFile)#5 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile02" ["size":protected]=> @@ -113,11 +119,15 @@ array(3) { string(11) "copy-id.pdf" ["clientMediaType":protected]=> string(9) "image/jpg" + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } [1]=> - object(HttpMessage\UploadedFile)#6 (6) { + object(HttpMessage\UploadedFile)#6 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile03" ["size":protected]=> @@ -128,6 +138,8 @@ array(3) { string(22) "proof-of-residence.pdf" ["clientMediaType":protected]=> string(15) "application/pdf" + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } @@ -135,42 +147,80 @@ array(3) { ["forms"]=> array(3) { ["g201"]=> - object(HttpMessage\UploadedFile)#7 (4) { + object(HttpMessage\UploadedFile)#7 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile04" ["size":protected]=> int(942) ["error":protected]=> int(0) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } ["g202"]=> array(3) { ["a"]=> - object(HttpMessage\UploadedFile)#8 (4) { + object(HttpMessage\UploadedFile)#8 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile05" ["size":protected]=> int(2391) ["error":protected]=> int(0) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } ["b"]=> - object(HttpMessage\UploadedFile)#9 (2) { + object(HttpMessage\UploadedFile)#9 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + NULL + ["size":protected]=> + NULL ["error":protected]=> int(4) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } ["c"]=> - object(HttpMessage\UploadedFile)#10 (3) { + object(HttpMessage\UploadedFile)#10 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + NULL ["size":protected]=> int(485) ["error":protected]=> int(3) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } @@ -178,22 +228,40 @@ array(3) { ["g301"]=> array(2) { [0]=> - object(HttpMessage\UploadedFile)#11 (4) { + object(HttpMessage\UploadedFile)#11 (8) { + ["stream":protected]=> + NULL ["file":protected]=> string(19) "/tmp/uploadedfile07" ["size":protected]=> int(4732) ["error":protected]=> int(0) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } [1]=> - object(HttpMessage\UploadedFile)#12 (3) { + object(HttpMessage\UploadedFile)#12 (8) { + ["stream":protected]=> + NULL + ["file":protected]=> + NULL ["size":protected]=> int(124901432) ["error":protected]=> int(2) + ["clientFilename":protected]=> + NULL + ["clientMediaType":protected]=> + NULL + ["moved":protected]=> + bool(false) ["checkUploaded":protected]=> bool(false) } diff --git a/uploaded_file.c b/uploaded_file.c index cbb5a47..a896e22 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -158,7 +158,12 @@ void construct_uploaded_file( void create_uploaded_file(zval *uploaded_file, zval *tmp_name, zval *size, zval *error, zval *name, zval *type) { - ZVAL_OBJ(uploaded_file, zend_objects_new(HttpMessage_UploadedFile_ce)); + zend_object *new_object; + + new_object = zend_objects_new(HttpMessage_UploadedFile_ce); + object_properties_init(new_object, HttpMessage_UploadedFile_ce); + + ZVAL_OBJ(uploaded_file, new_object); construct_uploaded_file( uploaded_file, From daee4fad35547472db7e895bc5d6f74b8b740b5c Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 27 Jun 2019 22:09:44 +0200 Subject: [PATCH 22/67] Switch to appveyor config taken from psr ext --- .appveyor.yml | 89 ++++++++----- .appveyor/build.cmd | 50 -------- .appveyor/test.cmd | 16 --- .ci/appveyor.psm1 | 302 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 100 deletions(-) delete mode 100644 .appveyor/build.cmd delete mode 100644 .appveyor/test.cmd create mode 100644 .ci/appveyor.psm1 diff --git a/.appveyor.yml b/.appveyor.yml index e894e9c..18cb523 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,51 +2,72 @@ version: '{branch}.{build}' branches: only: - - master + - master + - appveyor + - w32 -image: - - Visual Studio 2015 +platform: + - x86 + - x64 + +cache: + - 'C:\Downloads -> appveyor.yml' environment: - PHP_SDK_BINARY_TOOLS_URL: https://windows.php.net/downloads/php-sdk - PHP_SDK_BINARY_TOOLS_PACKAGE: php-sdk-binary-tools-20110915.zip - PHP_DEPS_URL: https://windows.php.net/downloads/php-sdk - PECL_PSR_URL: https://pecl.php.net/get/psr-0.6.1.tgz + PHP_SDK_BINARY_TOOLS_VER: 2.0.7 + NO_INTERACTION: 1 + REPORT_EXIT_STATUS: 1 + TEST_PHP_EXECUTABLE: C:\projects\php\php.exe matrix: - - PHP_REL: 7.2 - ARCHITECTURE: x64 - ARCH: amd64 - ZTS_STATE: disable + - PHP_VER: 7.2 + VC_VER: vc15 + PHP_BUILD_TYPE: Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - PHP_VER: 7.2 + VC_VER: vc15 + PHP_BUILD_TYPE: nts-Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - PHP_VER: 7.3 + VC_VER: vc15 + PHP_BUILD_TYPE: Win32 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_BUILD_CRT: vc14 - PHP_DEPS_PACKAGE: deps-7.2-vc14-x64.7z - - PHP_REL: 7.3 - ARCHITECTURE: x64 - ARCH: amd64 - ZTS_STATE: disable + - PHP_VER: 7.3 + VC_VER: vc15 + PHP_BUILD_TYPE: nts-Win32 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_BUILD_CRT: vc14 - PHP_DEPS_PACKAGE: deps-7.3-vc14-x64.7z - - -# Uncomment the following two lines to use RDP to debug "stuck" builds -#init: -# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - + install: - - cmd: cinst wget - - cmd: >- - "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH% + - ps: Import-Module .\.ci\appveyor.psm1 + - ps: SetupPhpVersionString + - ps: AppendSessionPath + - ps: EnsureRequiredDirectoriesPresent + - ps: Ensure7ZipIsInstalled + - ps: InstallSdk + - ps: InstallPhp + - ps: InstallPecl psr 0.6.1 + - ps: InstallPhpDevPack build_script: - - .appveyor\build.cmd + - ps: InitializeBuildVars + - '"%VSCOMNTOOLS%\VsDevCmd" %PLATFORM%' + - '"%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %ARCH%' + - phpsdk_setvars + - phpize + - ps: InitializeReleaseVars + - cmd: configure.bat --disable-all --with-http_message=shared --with-prefix=C:\projects\php + - cmd: nmake 2> compile-errors.log 1> compile.log test_script: - - .appveyor\test.cmd + - cmd: nmake test + +after_build: + - ps: PrepareReleasePackage -# Uncomment the following two lines to use RDP on finish, blocking -# until the "lock" file on the VM desktop is deleted. -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +on_failure : + - ps: PrintLogs +artifacts: + - path: '.\$(RELEASE_ZIPBALL).zip' + name: http_message + type: zip diff --git a/.appveyor/build.cmd b/.appveyor/build.cmd deleted file mode 100644 index 75357ab..0000000 --- a/.appveyor/build.cmd +++ /dev/null @@ -1,50 +0,0 @@ -@echo off - -setlocal enableextensions enabledelayedexpansion - - REM set up PHP - mkdir C:\projects\php-sdk >NUL 2>NUL - cd C:\projects\php-sdk - wget %PHP_SDK_BINARY_TOOLS_URL%/%PHP_SDK_BINARY_TOOLS_PACKAGE% --no-check-certificate -q -O %PHP_SDK_BINARY_TOOLS_PACKAGE% - 7z x -y %PHP_SDK_BINARY_TOOLS_PACKAGE% - cmd /c bin\phpsdk_buildtree.bat phpdev - pushd phpdev - ren vc9 vc14 - pushd vc14\x64 - git clone https://git.php.net/repository/php-src.git - cd php-src - git checkout PHP-%PHP_REL% - cd .. - wget %PHP_DEPS_URL%/%PHP_DEPS_PACKAGE% --no-check-certificate -q -O %PHP_DEPS_PACKAGE% - 7z x -y %PHP_DEPS_PACKAGE% - popd - popd - - REM download and install the psr extension from PECL - mkdir c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\psr - wget %PECL_PSR_URL% --no-check-certificate -q -O psr.tgz - 7z x -y psr.tgz -oc:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\psr - - REM copy the extension into the PHP tree - mkdir c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\http_message - xcopy c:\projects\http_message-php-ext\*.* c:\projects\php-sdk\phpdev\vc14\x64\php-src\ext\http_message /s/e/v - - REM The bison utility is needed for the PHP build, so add MSYS to the path. - REM Note: Add to the end to ensure MSVC tools are found firts. - set PATH=%PATH%;c:\MinGW\msys\1.0\bin - - REM perform the build - cmd /c bin\phpsdk_setvars.bat - pushd phpdev\vc14\x64\php-src - cmd /c buildconf --force - cmd /c configure --disable-all --enable-cli --with-extra-includes=c:\projects\libhttp_message --with-extra-libs=c:\projects\libhttp_message --with-psr=shared --with-http_message=shared - nmake - popd - - REM TODO:debugging - dir php_http_message.dll /s - dir php.exe /s - dir php*.dll /s - -endlocal - diff --git a/.appveyor/test.cmd b/.appveyor/test.cmd deleted file mode 100644 index 1ec3fef..0000000 --- a/.appveyor/test.cmd +++ /dev/null @@ -1,16 +0,0 @@ -@echo off - -setlocal enableextensions enabledelayedexpansion - - cd C:\projects\php-sdk\phpdev\vc14\x64\php-src - - pushd ext\base58 - echo [PHP] > php.ini - echo extension_dir = "ext" >> php.ini - echo extension=php_http_message.dll >> php.ini - popd - - set TEST_PHP_EXECUTABLE=C:\projects\php-sdk\phpdev\vc14\x64\php-src\x64\Release_TS\php.exe - %TEST_PHP_EXECUTABLE% run-tests.php ext\http_message -q --show-diff - -endlocal diff --git a/.ci/appveyor.psm1 b/.ci/appveyor.psm1 new file mode 100644 index 0000000..177015b --- /dev/null +++ b/.ci/appveyor.psm1 @@ -0,0 +1,302 @@ +Function InitializeReleaseVars { + If ($Env:PLATFORM -eq 'x86') { + If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\Release" + } Else { + $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\Release_TS" + } + } Else { + If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:PLATFORM}\Release" + } Else { + $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:PLATFORM}\Release_TS" + } + } + + $Env:RELEASE_ZIPBALL = "http_message_${Env:PLATFORM}_${Env:VC_VER}_${Env:PHP_VER}_${Env:APPVEYOR_BUILD_VERSION}" +} + +Function InstallPhpDevPack { + Write-Host "Install PHP Dev pack: ${Env:PHP_FULL_VER}" -foregroundcolor Cyan + + $RemoteUrl = "http://windows.php.net/downloads/releases/php-devel-pack-$%7BEnv:PHP_FULL_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" + $DestinationPath = "C:\Downloads\php-devel-pack-${Env:PHP_FULL_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" + $InstallPath = 'C:\Projects\php-devpack' + + If (-not (Test-Path $InstallPath)) { + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PHP Dev pack: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + $DestinationUnzipPath = "${Env:Temp}\php-${Env:PHP_FULL_VER}-devel-${Env:VC_VER}-${Env:PLATFORM}" + + If (-not (Test-Path "$DestinationUnzipPath")) { + Expand-Item7zip $DestinationPath $Env:Temp + } + + Move-Item -Path $DestinationUnzipPath -Destination $InstallPath + } +} + +Function InstallPhp { + Write-Host "Install PHP: ${Env:PHP_FULL_VER}" -foregroundcolor Cyan + + $RemoteUrl = "http://windows.php.net/downloads/releases/php-$%7BEnv:PHP_FULL_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" + $DestinationPath = "C:\Downloads\php-${Env:PHP_FULL_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" + $InstallPath = 'C:\Projects\php' + + If (-not (Test-Path $InstallPath)) { + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PHP source code: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + Expand-Item7zip $DestinationPath $InstallPath + } + + If (-not (Test-Path "${InstallPath}\php.ini")) { + Copy-Item "${InstallPath}\php.ini-development" "${InstallPath}\php.ini" + } +} + +Function InstallPecl($Extension, $Version) { + Write-Host "Install PECL extension: ${Extension}" -foregroundcolor Cyan + + $RemoteUrl = "https://windows.php.net/downloads/pecl/releases/$%7BExtension%7D/$%7BVersion%7D/php_$%7BExtension%7D-$%7BVersion%7D-$%7BEnv:PHP_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" + $DestinationPath = "C:\Downloads\php_${Extension}-${Version}-${Env:PHP_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" + $InstallPath = "C:\Projects\php\extensions" + $DllFile = "php_${Extension}.dll" + + If (-not (Test-Path "${InstallPath}\${DllFile}")) { + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PECL extension ${Extension} source code: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + Expand-Item7zip $DestinationPath $InstallPath $DllFile + + Add-Content "${InstallPath}\php.ini" "extension=${DllFile}" + } +} + +Function InstallSdk { + Write-Host "Install PHP SDK binary tools: ${Env:PHP_SDK_BINARY_TOOLS_VER}" -foregroundcolor Cyan + + $RemoteUrl = "https://github.com/OSTC/php-sdk-binary-tools/archive/php-sdk-$%7BEnv:PHP_SDK_BINARY_TOOLS_VER%7D.zip" + $DestinationPath = "C:\Downloads\php-sdk-${Env:PHP_SDK_BINARY_TOOLS_VER}.zip" + $InstallPath = 'C:\Projects\php-sdk' + + If (-not (Test-Path $InstallPath)) { + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PHP SDK binary tools: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + $DestinationUnzipPath = "${Env:Temp}\php-sdk-binary-tools-php-sdk-${Env:PHP_SDK_BINARY_TOOLS_VER}" + + If (-not (Test-Path "$DestinationUnzipPath")) { + Expand-Item7zip $DestinationPath $Env:Temp + } + + Move-Item -Path $DestinationUnzipPath -Destination $InstallPath + } +} + +Function Ensure7ZipIsInstalled { + If (-not (Get-Command "7z" -ErrorAction SilentlyContinue)) { + $7zipInstallationDirectory = "${Env:ProgramFiles}\7-Zip" + + If (-not (Test-Path "$7zipInstallationDirectory")) { + Throw "The 7-zip file archiver is needed to use this module" + } + + $Env:Path += ";$7zipInstallationDirectory" + } +} + +Function EnsureRequiredDirectoriesPresent { + If (-not (Test-Path 'C:\Downloads')) { + New-Item -ItemType Directory -Force -Path 'C:\Downloads' | Out-Null + } + + If (-not (Test-Path 'C:\Projects')) { + New-Item -ItemType Directory -Force -Path 'C:\Projects' | Out-Null + } +} + +Function InitializeBuildVars { + switch ($Env:VC_VER) { + 'vc14' { + If (-not (Test-Path $Env:VS120COMNTOOLS)) { + Throw'The VS120COMNTOOLS environment variable is not set. Check your VS installation' + } + + $Env:VSCOMNTOOLS = $Env:VS120COMNTOOLS -replace '\\$', '' + Break + } + 'vc15' { + If (-not (Test-Path $Env:VS140COMNTOOLS)) { + Throw'The VS140COMNTOOLS environment variable is not set. Check your VS installation' + } + + $Env:VSCOMNTOOLS = $Env:VS140COMNTOOLS -replace '\\$', '' + Break + } + default { + Throw 'This script is designed to run with VS 14/15. Check your VS installation' + } + } + + If ($Env:PLATFORM -eq 'x64') { + $Env:ARCH = 'x86_amd64' + } Else { + $Env:ARCH = 'x86' + } +} + +Function AppendSessionPath { + [string[]] $PathsCollection = @( + "C:\Projects\php-sdk\bin", + "C:\Projects\php\bin", + "C:\Projects\php", + "C:\Projects\php-devpack" + ) + + $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName + + ForEach ($PathItem In $PathsCollection) { + Set-Location Env: + $AllPaths = (Get-ChildItem Path).value.split(";") | Sort-Object -Unique + + $AddToPath = $true + + ForEach ($AddedPath In $AllPaths) { + If (-not "${AddedPath}") { + Continue + } + + $AddedPath = $AddedPath -replace '\\$', '' + + If ($PathItem -eq $AddedPath) { + $AddToPath = $false + } + } + + If ($AddToPath) { + $Env:Path += ";${PathItem}" + } + } + + Set-Location "${CurrentPath}" +} + +Function SetupPhpVersionString { + $RemoteUrl = 'http://windows.php.net/downloads/releases/sha256sum.txt' + $DestinationPath = "${Env:Temp}\php-sha256sum.txt" + + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PHP SHA Sums: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + $VersionString = Get-Content $DestinationPath | Where-Object { + $_ -match "php-($Env:PHP_VER\.\d+)-src" + } | ForEach-Object { $matches[1] } + + If ($VersionString -NotMatch '\d+\.\d+\.\d+') { + Throw "Unable to obtain PHP version string using pattern 'php-($Env:PHP_MINOR\.\d+)-src'" + } + + $Env:PHP_FULL_VER = $VersionString +} + +Function Expand-Item7zip { + Param( + [Parameter(Mandatory=$true)][System.String] $Archive, + [Parameter(Mandatory=$true)][System.String] $Destination + ) + + If (-not (Test-Path -Path $Archive -PathType Leaf)) { + Throw "Specified archive File is invalid: [$Archive]" + } + + If (-not (Test-Path -Path $Destination -PathType Container)) { + New-Item $Destination -ItemType Directory | Out-Null + } + + $Result = (& 7z x "$Archive" "-o$Destination" -aoa -bd -y -r) + + $7zipExitCode = $LASTEXITCODE + If ($7zipExitCode -ne 0) { + Throw "An error occurred while unzipping [$Archive] to [$Destination]. 7Zip Exit Code was [$7zipExitCode]" + } +} + +Function PrintLogs { + If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log") { + Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log" + } + + If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log") { + Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log" + } + + If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\configure.js") { + Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\configure.js" + } +} + +Function PrepareReleasePackage { + $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName + $PackagePath = "${Env:APPVEYOR_BUILD_FOLDER}\package" + + If (-not (Test-Path $PackagePath)) { + New-Item -ItemType Directory -Force -Path $PackagePath | Out-Null + } + + Copy-Item -Path (Join-Path -Path $Env:APPVEYOR_BUILD_FOLDER -ChildPath '\*') -Filter '*.md' -Destination "${PackagePath}" -Force + Copy-Item "${Env:RELEASE_FOLDER}\php_http_message.dll" "${PackagePath}" + + Set-Location "${PackagePath}" + $Result = (& 7z a "${Env:RELEASE_ZIPBALL}.zip" *.*) + + $7zipExitCode = $LASTEXITCODE + If ($7zipExitCode -ne 0) { + Set-Location "${CurrentPath}" + Throw "An error occurred while creating release zippbal to [${Env:RELEASE_ZIPBALL}.zip]. 7Zip Exit Code was [${7zipExitCode}]" + } + + Move-Item "${Env:RELEASE_ZIPBALL}.zip" -Destination "${Env:APPVEYOR_BUILD_FOLDER}" + + Set-Location "${CurrentPath}" +} + +Function DownloadFile { + param( + [Parameter(Mandatory=$true)][System.String] $RemoteUrl, + [Parameter(Mandatory=$true)][System.String] $DestinationPath + ) + + $RetryMax = 5 + $RetryCount = 0 + $Completed = $false + + $WebClient = New-Object System.Net.WebClient + $WebClient.Headers.Add('User-Agent', 'AppVeyor PowerShell Script') + + While (-not $Completed) { + Try { + $WebClient.DownloadFile($RemoteUrl, $DestinationPath) + $Completed = $true + } Catch { + If ($RetryCount -ge $RetryMax) { + $ErrorMessage = $_.Exception.Message + Write-Host "Error downloadingig ${RemoteUrl}: $ErrorMessage" + $Completed = $true + } Else { + $RetryCount++ + } + } + } +} From 96cbf4d005344d8a15a96af4cf9f90f5a8054bdf Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 10 Jul 2019 10:44:05 +0200 Subject: [PATCH 23/67] Fix issue with deps segfault for module entry --- http_message.c | 1 + 1 file changed, 1 insertion(+) diff --git a/http_message.c b/http_message.c index acb0be8..5b5f6c1 100644 --- a/http_message.c +++ b/http_message.c @@ -42,6 +42,7 @@ static const zend_module_dep deps[] = { ZEND_MOD_REQUIRED("psr") + {NULL, NULL, NULL} }; zend_module_entry http_message_module_entry = { From a842eccbf5f3c7318a53b8b1381e18673a1ef62f Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 10 Jul 2019 10:53:28 +0200 Subject: [PATCH 24/67] Don't use zend_entry from psr ext directly. Instead get them from the class table. This prevents a (low level) lib error when psr isn't loaded. Instead PHP will give a warning. --- http_message.c | 17 +++++++++-------- macros.h | 19 +++++++++++++++++++ message.c | 16 +++++++++++++--- request.c | 17 ++++++++++++++--- response.c | 7 ++++++- server_request.c | 20 ++++++++++++++------ stream.c | 8 ++++++-- uploaded_file.c | 8 ++++++-- uri.c | 8 ++++++-- 9 files changed, 93 insertions(+), 27 deletions(-) diff --git a/http_message.c b/http_message.c index 5b5f6c1..7b1ede1 100644 --- a/http_message.c +++ b/http_message.c @@ -62,15 +62,16 @@ zend_module_entry http_message_module_entry = { PHP_MINIT_FUNCTION(http_message) { - PHP_MINIT(http_message_message)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_request)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_serverrequest)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_response)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_stream)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_uri)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU); + int success = + PHP_MINIT(http_message_message)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_request)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_serverrequest)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_response)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_stream)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_uri)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU); - return SUCCESS; + return ZEND_NORMALIZE_BOOL(success); } #ifdef COMPILE_DL_HTTP_MESSAGE diff --git a/macros.h b/macros.h index bb834cd..5ce9280 100644 --- a/macros.h +++ b/macros.h @@ -88,4 +88,23 @@ ZEND_END_ARG_INFO() #define STRLEN_NULL(str) str != NULL ? strlen(str) : 0 +static zend_always_inline zend_class_entry* get_internal_ce(const char *class_name, size_t class_name_len) +{ + zend_class_entry* temp_ce; + + if ((temp_ce = zend_hash_str_find_ptr(CG(class_table), class_name, class_name_len)) == NULL) { + return NULL; + } + + return temp_ce; +} + +#define RETURN_HTTP_MESSAGE_INTERFACE_NOT_FOUND(className) \ + { \ + zend_error(E_CORE_WARNING, \ + "Failed to initialize 'HttpMessage\\%s': 'Psr\\Http\\Message\\%sInterace' not found", \ + className, className); \ + return FAILURE; \ + } + #endif //HTTP_MESSAGE_MACROS_H diff --git a/message.c b/message.c index 19f5064..26b2ca2 100644 --- a/message.c +++ b/message.c @@ -45,7 +45,7 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_Message_ce; +zend_class_entry *HttpMessage_Message_ce = NULL; void add_header(zval *object, char *name, size_t name_len, zend_string *value, zend_bool added) { @@ -262,9 +262,15 @@ PHP_METHOD(Message, getBody) PHP_METHOD(Message, withBody) { zval *value; + zend_class_entry *stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + + if (stream_interface == NULL) { + zend_throw_error(NULL, "Psr\\Http\\Message\\StreamInterface not foud"); + return; + } ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_OBJECT_OF_CLASS(value, PsrHttpMessageStreamInterface_ce_ptr) + Z_PARAM_OBJECT_OF_CLASS(value, stream_interface) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -294,11 +300,15 @@ static const zend_function_entry message_functions[] = { PHP_MINIT_FUNCTION(http_message_message) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\messageinterface")); + + if (interface == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Message", message_functions); HttpMessage_Message_ce = zend_register_internal_class(&ce); HttpMessage_Message_ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; - zend_class_implements(HttpMessage_Message_ce, 1, PsrHttpMessageMessageInterface_ce_ptr); + zend_class_implements(HttpMessage_Message_ce, 1, interface); /* Properties */ zend_declare_property_string( diff --git a/request.c b/request.c index 05a3942..55baa9c 100644 --- a/request.c +++ b/request.c @@ -44,7 +44,7 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_Request_ce; +zend_class_entry *HttpMessage_Request_ce = NULL; /* __construct */ @@ -160,9 +160,15 @@ PHP_METHOD(Request, getUri) PHP_METHOD(Request, withUri) { zval *value; + zend_class_entry *uri_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uriinterface")); + + if (uri_interface == NULL) { + zend_throw_error(NULL, "Psr\\Http\\Message\\UriInterface not foud"); + return; + } ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_OBJECT_OF_CLASS(value, PsrHttpMessageUriInterface_ce_ptr) + Z_PARAM_OBJECT_OF_CLASS(value, uri_interface) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -187,10 +193,15 @@ static const zend_function_entry request_functions[] = { PHP_MINIT_FUNCTION(http_message_request) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestinterface")); + + if (interface == NULL) return FAILURE; + if (HttpMessage_Message_ce == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Request", request_functions); HttpMessage_Request_ce = zend_register_internal_class_ex(&ce, HttpMessage_Message_ce); - zend_class_implements(HttpMessage_Request_ce, 1, PsrHttpMessageRequestInterface_ce_ptr); + zend_class_implements(HttpMessage_Request_ce, 1, interface); /* Properties */ zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("requestTarget"), ZEND_ACC_PROTECTED); diff --git a/response.c b/response.c index 0a4a6a5..2ee0119 100644 --- a/response.c +++ b/response.c @@ -136,10 +136,15 @@ static const zend_function_entry response_functions[] = { PHP_MINIT_FUNCTION(http_message_response) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\responseinterface")); + + if (interface == NULL) return FAILURE; + if (HttpMessage_Message_ce == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Response", response_functions); HttpMessage_Response_ce = zend_register_internal_class_ex(&ce, HttpMessage_Message_ce); - zend_class_implements(HttpMessage_Response_ce, 1, PsrHttpMessageResponseInterface_ce_ptr); + zend_class_implements(HttpMessage_Response_ce, 1, interface); /* Properties */ zend_declare_property_long(HttpMessage_Response_ce, ZEND_STRL("statusCode"), 0, ZEND_ACC_PROTECTED); diff --git a/server_request.c b/server_request.c index 550cbed..2301432 100644 --- a/server_request.c +++ b/server_request.c @@ -44,17 +44,20 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_ServerRequest_ce; +zend_class_entry *HttpMessage_ServerRequest_ce = NULL; int assert_uploaded_files(HashTable *array) { zval *entry; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); + + if (interface == NULL) { + zend_throw_error(NULL, "Psr\\Http\\Message\\UploadedFileInterface not foud"); + return FAILURE; + } ZEND_HASH_FOREACH_VAL(array, entry) { - if ( - Z_TYPE_P(entry) == IS_OBJECT && - EXPECTED(instanceof_function(Z_OBJCE_P(entry), PsrHttpMessageUploadedFileInterface_ce_ptr)) - ) { + if (Z_TYPE_P(entry) == IS_OBJECT && EXPECTED(instanceof_function(Z_OBJCE_P(entry), interface))) { continue; } @@ -455,10 +458,15 @@ static const zend_function_entry request_functions[] = { PHP_MINIT_FUNCTION(http_message_serverrequest) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\serverrequestinterface")); + + if (interface == NULL) return FAILURE; + if (HttpMessage_Request_ce == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "ServerRequest", request_functions); HttpMessage_ServerRequest_ce = zend_register_internal_class_ex(&ce, HttpMessage_Request_ce); - zend_class_implements(HttpMessage_ServerRequest_ce, 1, PsrHttpMessageServerRequestInterface_ce_ptr); + zend_class_implements(HttpMessage_ServerRequest_ce, 1, interface); /* Properties */ zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("serverParams"), ZEND_ACC_PROTECTED); diff --git a/stream.c b/stream.c index f380fa7..ae21bc9 100644 --- a/stream.c +++ b/stream.c @@ -46,7 +46,7 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_Stream_ce; +zend_class_entry *HttpMessage_Stream_ce = NULL; zend_bool string_contains_char(char *haystack, char chr) { @@ -458,10 +458,14 @@ static const zend_function_entry stream_functions[] = { PHP_MINIT_FUNCTION(http_message_stream) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + + if (interface == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Stream", stream_functions); HttpMessage_Stream_ce = zend_register_internal_class(&ce); - zend_class_implements(HttpMessage_Stream_ce, 1, PsrHttpMessageStreamInterface_ce_ptr); + zend_class_implements(HttpMessage_Stream_ce, 1, interface); /* Properties */ zend_declare_property_null(HttpMessage_Stream_ce, ZEND_STRL("stream"), ZEND_ACC_PROTECTED); diff --git a/uploaded_file.c b/uploaded_file.c index a896e22..50317ac 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -46,7 +46,7 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_UploadedFile_ce; +zend_class_entry *HttpMessage_UploadedFile_ce = NULL; int assert_file_available(zval *file, zval *moved) { @@ -385,10 +385,14 @@ static const zend_function_entry methods[] = { PHP_MINIT_FUNCTION(http_message_uploadedfile) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); + + if (interface == NULL) return FAILURE; + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "UploadedFile", methods); HttpMessage_UploadedFile_ce = zend_register_internal_class(&ce); - zend_class_implements(HttpMessage_UploadedFile_ce, 1, PsrHttpMessageUploadedFileInterface_ce_ptr); + zend_class_implements(HttpMessage_UploadedFile_ce, 1, interface); /* Properties */ zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("stream"), ZEND_ACC_PROTECTED); diff --git a/uri.c b/uri.c index 6d185a3..509ba5f 100644 --- a/uri.c +++ b/uri.c @@ -45,7 +45,7 @@ #if HAVE_HTTP_MESSAGE -zend_class_entry *HttpMessage_Uri_ce; +zend_class_entry *HttpMessage_Uri_ce = NULL; void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass_len) { @@ -435,10 +435,14 @@ static const zend_function_entry uri_functions[] = { PHP_MINIT_FUNCTION(http_message_uri) { zend_class_entry ce; + zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uriinterface")); + + if (interface == NULL) RETURN_HTTP_MESSAGE_INTERFACE_NOT_FOUND("Uri"); + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Uri", uri_functions); HttpMessage_Uri_ce = zend_register_internal_class(&ce); - zend_class_implements(HttpMessage_Uri_ce, 1, PsrHttpMessageUriInterface_ce_ptr); + zend_class_implements(HttpMessage_Uri_ce, 1, interface); /* Properties */ zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("scheme"), "", ZEND_ACC_PROTECTED); From 0842cef60e0db0cb46566684ba9e9f7343a5bfc9 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Fri, 28 Jun 2019 11:26:02 +0200 Subject: [PATCH 25/67] Bugfix ZEND_PARSE_PARAMETERS_END_EX --- .appveyor.yml | 27 ++++++++++++++------------- .ci/appveyor.psm1 | 41 ++++++++++++++++++++++++++++++++--------- config.w32 | 9 ++++++--- response.c | 2 +- server_request.c | 5 ++--- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 18cb523..bd0d611 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ branches: - w32 platform: - - x86 +# - x86 - x64 cache: @@ -24,18 +24,18 @@ environment: VC_VER: vc15 PHP_BUILD_TYPE: Win32 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - PHP_VER: 7.2 - VC_VER: vc15 - PHP_BUILD_TYPE: nts-Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - PHP_VER: 7.3 - VC_VER: vc15 - PHP_BUILD_TYPE: Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - PHP_VER: 7.3 - VC_VER: vc15 - PHP_BUILD_TYPE: nts-Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - PHP_VER: 7.2 +# VC_VER: vc15 +# PHP_BUILD_TYPE: nts-Win32 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - PHP_VER: 7.3 +# VC_VER: vc15 +# PHP_BUILD_TYPE: Win32 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - PHP_VER: 7.3 +# VC_VER: vc15 +# PHP_BUILD_TYPE: nts-Win32 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 install: - ps: Import-Module .\.ci\appveyor.psm1 @@ -47,6 +47,7 @@ install: - ps: InstallPhp - ps: InstallPecl psr 0.6.1 - ps: InstallPhpDevPack + - ps: InstallPeclHeaders psr 0.6.1 build_script: - ps: InitializeBuildVars diff --git a/.ci/appveyor.psm1 b/.ci/appveyor.psm1 index 177015b..1f108f6 100644 --- a/.ci/appveyor.psm1 +++ b/.ci/appveyor.psm1 @@ -65,19 +65,42 @@ Function InstallPecl($Extension, $Version) { $RemoteUrl = "https://windows.php.net/downloads/pecl/releases/$%7BExtension%7D/$%7BVersion%7D/php_$%7BExtension%7D-$%7BVersion%7D-$%7BEnv:PHP_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" $DestinationPath = "C:\Downloads\php_${Extension}-${Version}-${Env:PHP_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" - $InstallPath = "C:\Projects\php\extensions" - $DllFile = "php_${Extension}.dll" + $InstallPath = "C:\Projects\php\ext" + $DllFile = "php_${Extension}.dll" - If (-not (Test-Path "${InstallPath}\${DllFile}")) { - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PECL extension ${Extension} source code: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PECL extension ${Extension}: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath + } + + Expand-Item7zip $DestinationPath $InstallPath $DllFile + + Add-Content "${InstallPath}\php.ini" "extension=${DllFile}" +} - Expand-Item7zip $DestinationPath $InstallPath $DllFile - Add-Content "${InstallPath}\php.ini" "extension=${DllFile}" +Function InstallPeclHeaders { + Param( + [Parameter(Mandatory=$true)][System.String] $Extension, + [Parameter(Mandatory=$true)][System.String] $Version + ) + + Write-Host "Install headers for ${Extension} PECL extension" -foregroundcolor Cyan + + $RemoteUrl = "https://pecl.php.net/get/$%7BExtension%7D-$%7BVersion%7D.tgz" + $DestinationPath = "C:\Downloads\${Extension}-${Version}.tgz" + $InstallPath = "C:\Projects\pecl" + $InstallPhpDevPath = 'C:\Projects\php-devpack' + + If (-not [System.IO.File]::Exists($DestinationPath)) { + Write-Host "Downloading PECL extension ${Extension} source code: ${RemoteUrl} ..." + DownloadFile $RemoteUrl $DestinationPath } + + Expand-Tar $DestinationPath $InstallPath "${Extension}-${Version}" + + New-Item -Path "${InstallDevPath}\include\ext" -Name "${Extension}" -ItemType "directory" + Copy-Item "${InstallPath}\${Extension}-${Version}\*.h" -Destination "${InstallPhpDevPath}\include\ext\${Extension}" -Recurse } Function InstallSdk { diff --git a/config.w32 b/config.w32 index a2ffe06..4148511 100644 --- a/config.w32 +++ b/config.w32 @@ -4,7 +4,10 @@ ARG_WITH("http_message", "Include http_message support", "no"); if (PHP_HTTP_MESSAGE != "no") { - EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); - AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'Have http_message support'); - PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); + ADD_FLAG("LIBS_CLI", "php_psr.lib"); + + EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); + AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'Have http_message support'); + PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } + diff --git a/response.c b/response.c index 2ee0119..ef27ee9 100644 --- a/response.c +++ b/response.c @@ -104,7 +104,7 @@ PHP_METHOD(Response, withStatus) Z_PARAM_LONG(code) Z_PARAM_OPTIONAL Z_PARAM_STRING(phrase, phrase_len) - ZEND_PARSE_PARAMETERS_END_EX(); + ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); diff --git a/server_request.c b/server_request.c index 2301432..905cf26 100644 --- a/server_request.c +++ b/server_request.c @@ -74,9 +74,8 @@ int assert_uploaded_files(HashTable *array) void add_header_from_param(HashTable *headers, char *key, size_t keylen, zval *val) { zval *new_header, valcpy; - zend_long index; char header[256]; - char i; + size_t i; zend_bool lower; // Turn next char to lower case if (UNEXPECTED(keylen > 255)) { @@ -138,7 +137,7 @@ void init_headers_from_params(zval *object, HashTable *serverParams) void init_uri_from_params(zval *object, HashTable *serverParams) { zval rv, *uri, *tmp, *request_target, *protocol, *https, *user, *pass; - zend_long index, port = -1, default_port = -1; + zend_long port = -1, default_port = -1; zend_bool is_http; uri = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("uri"), 0, &rv); From 5b902eb0d04e2869bceeaa43568e82d47f102836 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 10 Jul 2019 13:39:49 +0200 Subject: [PATCH 26/67] Use sergeyklay/php-appveyor for AppVeyor build. This already supports installing Pecl. So why roll it ourselves? Added installing Pecl headers. --- .appveyor.yml | 114 +++++---- .ci/appveyor.psm1 | 312 ++--------------------- .ci/php-appveyor.psm1 | 567 ++++++++++++++++++++++++++++++++++++++++++ config.m4 | 12 +- config.w32 | 7 +- 5 files changed, 661 insertions(+), 351 deletions(-) create mode 100644 .ci/php-appveyor.psm1 diff --git a/.appveyor.yml b/.appveyor.yml index bd0d611..82e8509 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,3 +1,5 @@ +# See https://github.com/sergeyklay/php-appveyor + version: '{branch}.{build}' branches: @@ -6,69 +8,89 @@ branches: - appveyor - w32 -platform: -# - x86 - - x64 +environment: + EXTNAME: http_message -cache: - - 'C:\Downloads -> appveyor.yml' + matrix: + - PHP_VERSION: 7.3 + VC_VERSION: 15 + BUILD_TYPE: nts-Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -environment: - PHP_SDK_BINARY_TOOLS_VER: 2.0.7 + PHP_SDK_VERSION: 2.1.9 + PHP_AVM: https://raw.githubusercontent.com/sergeyklay/php-appveyor/master/php-appveyor.psm1 + + TEST_PHP_EXECUTABLE: C:\php\php.exe NO_INTERACTION: 1 REPORT_EXIT_STATUS: 1 - TEST_PHP_EXECUTABLE: C:\projects\php\php.exe - matrix: - - PHP_VER: 7.2 - VC_VER: vc15 - PHP_BUILD_TYPE: Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -# - PHP_VER: 7.2 -# VC_VER: vc15 -# PHP_BUILD_TYPE: nts-Win32 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -# - PHP_VER: 7.3 -# VC_VER: vc15 -# PHP_BUILD_TYPE: Win32 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -# - PHP_VER: 7.3 -# VC_VER: vc15 -# PHP_BUILD_TYPE: nts-Win32 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +matrix: + fast_finish: true + +cache: + - 'C:\Downloads -> .appveyor.yml' + +platform: + - x86 +# - x64 + +init: + - ps: $DebugPreference = 'Continue' #'SilentlyContinue' # Continue install: - - ps: Import-Module .\.ci\appveyor.psm1 - - ps: SetupPhpVersionString - - ps: AppendSessionPath - - ps: EnsureRequiredDirectoriesPresent - - ps: Ensure7ZipIsInstalled - - ps: InstallSdk - - ps: InstallPhp - - ps: InstallPecl psr 0.6.1 - - ps: InstallPhpDevPack - - ps: InstallPeclHeaders psr 0.6.1 + - ps: Import-Module .\.ci\php-appveyor.psm1 + + - ps: InstallPhpSdk $Env:PHP_SDK_VERSION $Env:VC_VERSION $Env:PLATFORM + - ps: InstallPhp $Env:PHP_VERSION $Env:BUILD_TYPE $Env:VC_VERSION $Env:PLATFORM + - ps: InstallPhpDevPack $Env:PHP_VERSION $Env:BUILD_TYPE $Env:VC_VERSION $Env:PLATFORM + + - ps: >- + InstallPeclExtension ` + -Name psr ` + -Version 0.6.1 ` + -PhpVersion $Env:PHP_VERSION ` + -BuildType $Env:BUILD_TYPE ` + -VC $Env:VC_VERSION ` + -Platform $Env:PLATFORM ` + -Headers $true ` + -Enable $true build_script: + - ps: Import-Module .\.ci\appveyor.psm1 - ps: InitializeBuildVars - - '"%VSCOMNTOOLS%\VsDevCmd" %PLATFORM%' - - '"%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %ARCH%' - - phpsdk_setvars - - phpize - - ps: InitializeReleaseVars - - cmd: configure.bat --disable-all --with-http_message=shared --with-prefix=C:\projects\php + - cmd: '"%VSCOMNTOOLS%\VsDevCmd" -arch=%PLATFORM%' + - cmd: '"%VCVARSALL_FILE%" %ARCH%' + - cmd: C:\php-sdk\bin\phpsdk_setvars + - cmd: C:\php-devpack\phpize + - cmd: configure.bat --with-prefix=C:\php --with-php-build=C:\php-devpack --disable-all --enable-http-message - cmd: nmake 2> compile-errors.log 1> compile.log + - ps: InitializeReleaseVars test_script: - cmd: nmake test after_build: - - ps: PrepareReleasePackage - -on_failure : - - ps: PrintLogs + - ps: Set-Location "${Env:APPVEYOR_BUILD_FOLDER}" + - ps: >- + PrepareReleasePackage ` + -PhpVersion $Env:PHP_VERSION ` + -BuildType $Env:BUILD_TYPE ` + -Platform $Env:PLATFORM ` + -ConverMdToHtml $true ` + -ReleaseFiles "${Env:RELEASE_DLL_PATH}",` + "${Env:APPVEYOR_BUILD_FOLDER}\LICENSE" artifacts: - path: '.\$(RELEASE_ZIPBALL).zip' - name: http_message + name: '$(Env:EXTNAME)' type: zip + +on_failure : + - ps: >- + If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log") { + Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log" + } + + If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log") { + Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log" + } diff --git a/.ci/appveyor.psm1 b/.ci/appveyor.psm1 index 1f108f6..ef79ae3 100644 --- a/.ci/appveyor.psm1 +++ b/.ci/appveyor.psm1 @@ -1,156 +1,6 @@ -Function InitializeReleaseVars { - If ($Env:PLATFORM -eq 'x86') { - If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { - $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\Release" - } Else { - $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\Release_TS" - } - } Else { - If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { - $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:PLATFORM}\Release" - } Else { - $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:PLATFORM}\Release_TS" - } - } - - $Env:RELEASE_ZIPBALL = "http_message_${Env:PLATFORM}_${Env:VC_VER}_${Env:PHP_VER}_${Env:APPVEYOR_BUILD_VERSION}" -} - -Function InstallPhpDevPack { - Write-Host "Install PHP Dev pack: ${Env:PHP_FULL_VER}" -foregroundcolor Cyan - - $RemoteUrl = "http://windows.php.net/downloads/releases/php-devel-pack-$%7BEnv:PHP_FULL_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" - $DestinationPath = "C:\Downloads\php-devel-pack-${Env:PHP_FULL_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" - $InstallPath = 'C:\Projects\php-devpack' - - If (-not (Test-Path $InstallPath)) { - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PHP Dev pack: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - $DestinationUnzipPath = "${Env:Temp}\php-${Env:PHP_FULL_VER}-devel-${Env:VC_VER}-${Env:PLATFORM}" - - If (-not (Test-Path "$DestinationUnzipPath")) { - Expand-Item7zip $DestinationPath $Env:Temp - } - - Move-Item -Path $DestinationUnzipPath -Destination $InstallPath - } -} - -Function InstallPhp { - Write-Host "Install PHP: ${Env:PHP_FULL_VER}" -foregroundcolor Cyan - - $RemoteUrl = "http://windows.php.net/downloads/releases/php-$%7BEnv:PHP_FULL_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" - $DestinationPath = "C:\Downloads\php-${Env:PHP_FULL_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" - $InstallPath = 'C:\Projects\php' - - If (-not (Test-Path $InstallPath)) { - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PHP source code: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - Expand-Item7zip $DestinationPath $InstallPath - } - - If (-not (Test-Path "${InstallPath}\php.ini")) { - Copy-Item "${InstallPath}\php.ini-development" "${InstallPath}\php.ini" - } -} - -Function InstallPecl($Extension, $Version) { - Write-Host "Install PECL extension: ${Extension}" -foregroundcolor Cyan - - $RemoteUrl = "https://windows.php.net/downloads/pecl/releases/$%7BExtension%7D/$%7BVersion%7D/php_$%7BExtension%7D-$%7BVersion%7D-$%7BEnv:PHP_VER%7D-$%7BEnv:PHP_BUILD_TYPE%7D-$%7BEnv:VC_VER%7D-$%7BEnv:PLATFORM%7D.zip" - $DestinationPath = "C:\Downloads\php_${Extension}-${Version}-${Env:PHP_VER}-${Env:PHP_BUILD_TYPE}-${Env:VC_VER}-${Env:PLATFORM}.zip" - $InstallPath = "C:\Projects\php\ext" - $DllFile = "php_${Extension}.dll" - - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PECL extension ${Extension}: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - Expand-Item7zip $DestinationPath $InstallPath $DllFile - - Add-Content "${InstallPath}\php.ini" "extension=${DllFile}" -} - - -Function InstallPeclHeaders { - Param( - [Parameter(Mandatory=$true)][System.String] $Extension, - [Parameter(Mandatory=$true)][System.String] $Version - ) - - Write-Host "Install headers for ${Extension} PECL extension" -foregroundcolor Cyan - - $RemoteUrl = "https://pecl.php.net/get/$%7BExtension%7D-$%7BVersion%7D.tgz" - $DestinationPath = "C:\Downloads\${Extension}-${Version}.tgz" - $InstallPath = "C:\Projects\pecl" - $InstallPhpDevPath = 'C:\Projects\php-devpack' - - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PECL extension ${Extension} source code: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - Expand-Tar $DestinationPath $InstallPath "${Extension}-${Version}" - - New-Item -Path "${InstallDevPath}\include\ext" -Name "${Extension}" -ItemType "directory" - Copy-Item "${InstallPath}\${Extension}-${Version}\*.h" -Destination "${InstallPhpDevPath}\include\ext\${Extension}" -Recurse -} - -Function InstallSdk { - Write-Host "Install PHP SDK binary tools: ${Env:PHP_SDK_BINARY_TOOLS_VER}" -foregroundcolor Cyan - - $RemoteUrl = "https://github.com/OSTC/php-sdk-binary-tools/archive/php-sdk-$%7BEnv:PHP_SDK_BINARY_TOOLS_VER%7D.zip" - $DestinationPath = "C:\Downloads\php-sdk-${Env:PHP_SDK_BINARY_TOOLS_VER}.zip" - $InstallPath = 'C:\Projects\php-sdk' - - If (-not (Test-Path $InstallPath)) { - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PHP SDK binary tools: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - $DestinationUnzipPath = "${Env:Temp}\php-sdk-binary-tools-php-sdk-${Env:PHP_SDK_BINARY_TOOLS_VER}" - - If (-not (Test-Path "$DestinationUnzipPath")) { - Expand-Item7zip $DestinationPath $Env:Temp - } - - Move-Item -Path $DestinationUnzipPath -Destination $InstallPath - } -} - -Function Ensure7ZipIsInstalled { - If (-not (Get-Command "7z" -ErrorAction SilentlyContinue)) { - $7zipInstallationDirectory = "${Env:ProgramFiles}\7-Zip" - - If (-not (Test-Path "$7zipInstallationDirectory")) { - Throw "The 7-zip file archiver is needed to use this module" - } - - $Env:Path += ";$7zipInstallationDirectory" - } -} - -Function EnsureRequiredDirectoriesPresent { - If (-not (Test-Path 'C:\Downloads')) { - New-Item -ItemType Directory -Force -Path 'C:\Downloads' | Out-Null - } - - If (-not (Test-Path 'C:\Projects')) { - New-Item -ItemType Directory -Force -Path 'C:\Projects' | Out-Null - } -} - Function InitializeBuildVars { - switch ($Env:VC_VER) { - 'vc14' { + switch ($Env:VC_VERSION) { + '14' { If (-not (Test-Path $Env:VS120COMNTOOLS)) { Throw'The VS120COMNTOOLS environment variable is not set. Check your VS installation' } @@ -158,7 +8,7 @@ Function InitializeBuildVars { $Env:VSCOMNTOOLS = $Env:VS120COMNTOOLS -replace '\\$', '' Break } - 'vc15' { + '15' { If (-not (Test-Path $Env:VS140COMNTOOLS)) { Throw'The VS140COMNTOOLS environment variable is not set. Check your VS installation' } @@ -176,150 +26,28 @@ Function InitializeBuildVars { } Else { $Env:ARCH = 'x86' } -} - -Function AppendSessionPath { - [string[]] $PathsCollection = @( - "C:\Projects\php-sdk\bin", - "C:\Projects\php\bin", - "C:\Projects\php", - "C:\Projects\php-devpack" - ) - - $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName - ForEach ($PathItem In $PathsCollection) { - Set-Location Env: - $AllPaths = (Get-ChildItem Path).value.split(";") | Sort-Object -Unique + $SearchFilter = 'vcvarsall.bat' + $SearchInFolder = "${Env:VSCOMNTOOLS}\..\..\" - $AddToPath = $true - - ForEach ($AddedPath In $AllPaths) { - If (-not "${AddedPath}") { - Continue - } - - $AddedPath = $AddedPath -replace '\\$', '' + $Env:VCVARSALL_FILE = Get-ChildItem -Path $SearchInFolder -Filter $SearchFilter -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } +} - If ($PathItem -eq $AddedPath) { - $AddToPath = $false - } +Function InitializeReleaseVars { + If ($Env:PLATFORM -eq 'x86') { + If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + $Env:RELEASE_SUBFOLDER = "Release" + } Else { + $Env:RELEASE_SUBFOLDER = "Release_TS" } - - If ($AddToPath) { - $Env:Path += ";${PathItem}" + } Else { + If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + $Env:RELEASE_SUBFOLDER = "${Env:PLATFORM}\Release" + } Else { + $Env:RELEASE_SUBFOLDER = "${Env:PLATFORM}\Release_TS" } } - Set-Location "${CurrentPath}" -} - -Function SetupPhpVersionString { - $RemoteUrl = 'http://windows.php.net/downloads/releases/sha256sum.txt' - $DestinationPath = "${Env:Temp}\php-sha256sum.txt" - - If (-not [System.IO.File]::Exists($DestinationPath)) { - Write-Host "Downloading PHP SHA Sums: ${RemoteUrl} ..." - DownloadFile $RemoteUrl $DestinationPath - } - - $VersionString = Get-Content $DestinationPath | Where-Object { - $_ -match "php-($Env:PHP_VER\.\d+)-src" - } | ForEach-Object { $matches[1] } - - If ($VersionString -NotMatch '\d+\.\d+\.\d+') { - Throw "Unable to obtain PHP version string using pattern 'php-($Env:PHP_MINOR\.\d+)-src'" - } - - $Env:PHP_FULL_VER = $VersionString -} - -Function Expand-Item7zip { - Param( - [Parameter(Mandatory=$true)][System.String] $Archive, - [Parameter(Mandatory=$true)][System.String] $Destination - ) - - If (-not (Test-Path -Path $Archive -PathType Leaf)) { - Throw "Specified archive File is invalid: [$Archive]" - } - - If (-not (Test-Path -Path $Destination -PathType Container)) { - New-Item $Destination -ItemType Directory | Out-Null - } - - $Result = (& 7z x "$Archive" "-o$Destination" -aoa -bd -y -r) - - $7zipExitCode = $LASTEXITCODE - If ($7zipExitCode -ne 0) { - Throw "An error occurred while unzipping [$Archive] to [$Destination]. 7Zip Exit Code was [$7zipExitCode]" - } -} - -Function PrintLogs { - If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log") { - Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile-errors.log" - } - - If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log") { - Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log" - } - - If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\configure.js") { - Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\configure.js" - } -} - -Function PrepareReleasePackage { - $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName - $PackagePath = "${Env:APPVEYOR_BUILD_FOLDER}\package" - - If (-not (Test-Path $PackagePath)) { - New-Item -ItemType Directory -Force -Path $PackagePath | Out-Null - } - - Copy-Item -Path (Join-Path -Path $Env:APPVEYOR_BUILD_FOLDER -ChildPath '\*') -Filter '*.md' -Destination "${PackagePath}" -Force - Copy-Item "${Env:RELEASE_FOLDER}\php_http_message.dll" "${PackagePath}" - - Set-Location "${PackagePath}" - $Result = (& 7z a "${Env:RELEASE_ZIPBALL}.zip" *.*) - - $7zipExitCode = $LASTEXITCODE - If ($7zipExitCode -ne 0) { - Set-Location "${CurrentPath}" - Throw "An error occurred while creating release zippbal to [${Env:RELEASE_ZIPBALL}.zip]. 7Zip Exit Code was [${7zipExitCode}]" - } - - Move-Item "${Env:RELEASE_ZIPBALL}.zip" -Destination "${Env:APPVEYOR_BUILD_FOLDER}" - - Set-Location "${CurrentPath}" -} - -Function DownloadFile { - param( - [Parameter(Mandatory=$true)][System.String] $RemoteUrl, - [Parameter(Mandatory=$true)][System.String] $DestinationPath - ) - - $RetryMax = 5 - $RetryCount = 0 - $Completed = $false - - $WebClient = New-Object System.Net.WebClient - $WebClient.Headers.Add('User-Agent', 'AppVeyor PowerShell Script') - - While (-not $Completed) { - Try { - $WebClient.DownloadFile($RemoteUrl, $DestinationPath) - $Completed = $true - } Catch { - If ($RetryCount -ge $RetryMax) { - $ErrorMessage = $_.Exception.Message - Write-Host "Error downloadingig ${RemoteUrl}: $ErrorMessage" - $Completed = $true - } Else { - $RetryCount++ - } - } - } + $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:RELEASE_SUBFOLDER}" + $Env:RELEASE_ZIPBALL = "${Env:EXTNAME}_${Env:PLATFORM}_vc${Env:VC_VERSION}_php${Env:PHP_VERSION}_${Env:APPVEYOR_BUILD_VERSION}" } diff --git a/.ci/php-appveyor.psm1 b/.ci/php-appveyor.psm1 new file mode 100644 index 0000000..c4612a4 --- /dev/null +++ b/.ci/php-appveyor.psm1 @@ -0,0 +1,567 @@ +# This file is part of the php-appveyor.psm1 project. +# +# (c) Serghei Iakovlev +# +# For the full copyright and license information, please view +# the LICENSE file that was distributed with this source code. + +# $ErrorActionPreference = "Stop" + +function InstallPhpSdk { + param ( + [Parameter(Mandatory=$true)] [System.String] $Version, + [Parameter(Mandatory=$true)] [System.String] $VC, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $InstallPath = "C:\php-sdk" + ) + + Write-Debug "Install PHP SDK binary tools: ${Version}" + SetupPrerequisites + + $FileName = "php-sdk-${Version}" + $RemoteUrl = "https://github.com/Microsoft/php-sdk-binary-tools/archive/$%7BFileName%7D.zip" + $Archive = "C:\Downloads\${FileName}.zip" + + if (-not (Test-Path "${InstallPath}\bin\php\php.exe")) { + if (-not (Test-Path $Archive)) { + DownloadFile -RemoteUrl $RemoteUrl -Destination $Archive + } + + $UnzipPath = "${Env:Temp}\php-sdk-binary-tools-${FileName}" + if (-not (Test-Path "${UnzipPath}")) { + Expand-Item7zip -Archive $Archive -Destination $Env:Temp + } + + Move-Item -Path $UnzipPath -Destination $InstallPath + } + + EnsureRequiredDirectoriesPresent ` + -Directories bin,lib,include ` + -Prefix "${InstallPath}\phpdev\vc${VC}\${Platform}" +} + +function InstallPhp { + param ( + [Parameter(Mandatory=$true)] [System.String] $Version, + [Parameter(Mandatory=$true)] [System.String] $BuildType, + [Parameter(Mandatory=$true)] [System.String] $VC, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $InstallPath = "C:\php" + ) + + SetupPrerequisites + $FullVersion = SetupPhpVersionString -Pattern $Version + + Write-Debug "Install PHP v${FullVersion}" + + $ReleasesPart = "releases" + if ([System.Convert]::ToDecimal($Version) -lt 7.1) { + $ReleasesPart = "releases/archives" + } + + $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-%7B1%7D-%7B2%7D-vc%7B3%7D-%7B4%7D.zip" -f + $ReleasesPart, $FullVersion, $BuildType, $VC, $Platform + + $Archive = "C:\Downloads\php-${FullVersion}-${BuildType}-VC${VC}-${Platform}.zip" + + if (-not (Test-Path "${InstallPath}\php.exe")) { + if (-not (Test-Path $Archive)) { + DownloadFile $RemoteUrl $Archive + } + + Expand-Item7zip $Archive $InstallPath + } + + if (-not (Test-Path "${InstallPath}\php.ini")) { + Copy-Item "${InstallPath}\php.ini-development" "${InstallPath}\php.ini" + } +} + +function InstallPhpDevPack { + param ( + [Parameter(Mandatory=$true)] [System.String] $PhpVersion, + [Parameter(Mandatory=$true)] [System.String] $BuildType, + [Parameter(Mandatory=$true)] [System.String] $VC, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $InstallPath = "C:\php-devpack" + ) + + SetupPrerequisites + $Version = SetupPhpVersionString -Pattern $PhpVersion + + Write-Debug "Install PHP Dev for PHP v${Version}" + + $ReleasesPart = "releases" + if ([System.Convert]::ToDecimal($PhpVersion) -lt 7.1) { + $ReleasesPart = "releases/archives" + } + + $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-devel-pack-%7B1%7D-%7B2%7D-vc%7B3%7D-%7B4%7D.zip" -f + $ReleasesPart, $Version, $BuildType, $VC, $Platform + + $Archive = "C:\Downloads\php-devel-pack-${Version}-${BuildType}-VC${VC}-${Platform}.zip" + + if (-not (Test-Path "${InstallPath}\phpize.bat")) { + if (-not (Test-Path $Archive)) { + DownloadFile $RemoteUrl $Archive + } + + $UnzipPath = "${Env:Temp}\php-${Version}-devel-VC${VC}-${Platform}" + if (-not (Test-Path "${UnzipPath}\phpize.bat")) { + Expand-Item7zip $Archive $Env:Temp + } + + if (Test-Path "${InstallPath}") { + Move-Item -Path "${UnzipPath}\*" -Destination $InstallPath + } else { + Move-Item -Path $UnzipPath -Destination $InstallPath + } + } +} + +function InstallPeclExtension { + param ( + [Parameter(Mandatory=$true)] [System.String] $Name, + [Parameter(Mandatory=$true)] [System.String] $Version, + [Parameter(Mandatory=$true)] [System.String] $PhpVersion, + [Parameter(Mandatory=$true)] [System.String] $BuildType, + [Parameter(Mandatory=$true)] [System.String] $VC, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $InstallPath = "C:\php\ext", + [Parameter(Mandatory=$false)] [System.Boolean] $Headers = $false, + [Parameter(Mandatory=$false)] [System.Boolean] $Enable = $false + ) + + SetupPrerequisites + + $BaseUri = "https://windows.php.net/downloads/pecl/releases/$%7BName%7D/$%7BVersion%7D" + $LocalPart = "php_${Name}-${Version}-${PhpVersion}" + + if ($BuildType -Match "nts-Win32") { + $TS = "nts" + } else { + $TS = "ts" + } + + $RemoteUrl = "${BaseUri}/${LocalPart}-${TS}-vc${VC}-${Platform}.zip" + $DestinationPath = "C:\Downloads\${LocalPart}-${TS}-vc${VC}-${Platform}.zip" + + if (-not (Test-Path "${InstallPath}\php_${Name}.dll")) { + if (-not (Test-Path $DestinationPath)) { + DownloadFile $RemoteUrl $DestinationPath + } + + Expand-Item7zip $DestinationPath $InstallPath + } + + if ($Headers) { + InstallPeclHeaders -Name $Name -Version $Version + } + + if ($Enable) { + EnablePhpExtension -Name $Name + } +} + +Function InstallPeclHeaders { + Param( + [Parameter(Mandatory=$true)] [System.String] $Name, + [Parameter(Mandatory=$true)] [System.String] $Version, + [Parameter(Mandatory=$false)] [System.String] $InstallPath = 'C:\php-devpack\include\ext\' + ) + + $RemoteUrl = "https://pecl.php.net/get/$%7BName%7D-$%7BVersion%7D.tgz" + $DownloadFile = "C:\Downloads\${Name}-${Version}.tgz" + + If (-not [System.IO.File]::Exists($DownloadFile)) { + DownloadFile $RemoteUrl $DownloadFile + } + + Ensure7ZipIsInstalled + + Expand-Item7zip $DownloadFile "${Env:Temp}" + + New-Item -Path "${InstallPath}" -Name "${Name}" -ItemType "directory" | Out-Null + Copy-Item "${Env:Temp}\${Name}-${Version}\*.h" -Destination "${InstallPath}\${Name}" -Recurse + + Get-ChildItem -Path "${InstallPath}\${Name}" +} + +function InstallComposer { + param ( + [Parameter(Mandatory=$false)] [System.String] $PhpInstallPath = 'C:\php', + [Parameter(Mandatory=$false)] [System.String] $InstallPath = '.' + ) + + $InstallPath = Resolve-Path $InstallPath + + $ComposerBatch = "${InstallPath}\composer.bat" + $ComposerPhar = "${InstallPath}\composer.phar" + + if (-not (Test-Path -Path $ComposerPhar)) { + DownloadFile "https://getcomposer.org/composer.phar" "${ComposerPhar}" + + Write-Output '@echo off' | Out-File -Encoding "ASCII" $ComposerBatch + Write-Output "${PhpInstallPath}\php.exe `"${ComposerPhar}`" %*" | Out-File -Encoding "ASCII" -Append $ComposerBatch + } +} + +function EnablePhpExtension { + param ( + [Parameter(Mandatory=$true)] [System.String] $Name, + [Parameter(Mandatory=$false)] [System.String] $PhpInstallPath = 'C:\php', + [Parameter(Mandatory=$false)] [System.String] $ExtPath = 'C:\php\ext', + [Parameter(Mandatory=$false)] [System.String] $PrintableName = '' + ) + + $FullyQualifiedExtensionPath = "${ExtPath}\php_${Name}.dll" + + $IniFile = "${PhpInstallPath}\php.ini" + $PhpExe = "${PhpInstallPath}\php.exe" + + if (-not (Test-Path $IniFile)) { + throw "Unable to locate ${IniFile}" + } + + if (-not (Test-Path "${ExtPath}")) { + throw "Unable to locate ${ExtPath} direcory" + } + + Write-Debug "Add `"extension = ${FullyQualifiedExtensionPath}`" to the ${IniFile}" + Write-Output "extension = ${FullyQualifiedExtensionPath}" | Out-File -Encoding "ASCII" -Append $IniFile + + if (Test-Path -Path "${PhpExe}") { + if ($PrintableName) { + Write-Debug "Minimal load test using command: ${PhpExe} --ri `"${PrintableName}`"" + $Result = (& "${PhpExe}" --ri "${PrintableName}") + } else { + Write-Debug "Minimal load test using command: ${PhpExe} --ri ${Name}" + $Result = (& "${PhpExe}" --ri $Name) + } + + $ExitCode = $LASTEXITCODE + if ($ExitCode -ne 0) { + throw "An error occurred while enabling ${Name} at ${IniFile}. ${Result}" + } + } +} + +function TuneUpPhp { + param ( + [Parameter(Mandatory=$false)] [System.String] $MemoryLimit = '256M', + [Parameter(Mandatory=$false)] [System.String[]] $DefaultExtensions = @(), + [Parameter(Mandatory=$false)] [System.String] $IniFile = 'C:\php\php.ini', + [Parameter(Mandatory=$false)] [System.String] $ExtPath = 'C:\php\ext' + ) + + Write-Debug "Tune up PHP using file `"${IniFile}`"" + + if (-not (Test-Path $IniFile)) { + throw "Unable to locate ${IniFile} file" + } + + if (-not (Test-Path $ExtPath)) { + throw "Unable to locate ${ExtPath} direcory" + } + + Write-Output "" | Out-File -Encoding "ASCII" -Append $IniFile + + Write-Output "extension_dir = ${ExtPath}" | Out-File -Encoding "ASCII" -Append $IniFile + Write-Output "memory_limit = ${MemoryLimit}" | Out-File -Encoding "ASCII" -Append $IniFile + + if ($DefaultExtensions.count -gt 0) { + Write-Output "" | Out-File -Encoding "ASCII" -Append $IniFile + + foreach ($Ext in $DefaultExtensions) { + Write-Output "extension = php_${Ext}.dll" | Out-File -Encoding "ASCII" -Append $IniFile + } + } +} + +function PrepareReleaseNote { + param ( + [Parameter(Mandatory=$true)] [System.String] $PhpVersion, + [Parameter(Mandatory=$true)] [System.String] $BuildType, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $ReleaseFile, + [Parameter(Mandatory=$false)] [System.String] $ReleaseDirectory, + [Parameter(Mandatory=$false)] [System.String] $BasePath + ) + + $Destination = "${BasePath}\${ReleaseDirectory}" + + if (-not (Test-Path $Destination)) { + New-Item -ItemType Directory -Force -Path "${Destination}" | Out-Null + } + + $ReleaseFile = "${Destination}\${ReleaseFile}" + $ReleaseDate = Get-Date -Format o + + $Image = $Env:APPVEYOR_BUILD_WORKER_IMAGE + $Version = $Env:APPVEYOR_BUILD_VERSION + $Commit = $Env:APPVEYOR_REPO_COMMIT + $CommitDate = $Env:APPVEYOR_REPO_COMMIT_TIMESTAMP + + Write-Output "Release date: ${ReleaseDate}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Release version: ${Version}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Git commit: ${Commit}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Commit date: ${CommitDate}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Build type: ${BuildType}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Platform: ${Platform}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Target PHP version: ${PhpVersion}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" + Write-Output "Build worker image: ${Image}" | Out-File -Encoding "ASCII" -Append "${ReleaseFile}" +} + +function PrepareReleasePackage { + param ( + [Parameter(Mandatory=$true)] [System.String] $PhpVersion, + [Parameter(Mandatory=$true)] [System.String] $BuildType, + [Parameter(Mandatory=$true)] [System.String] $Platform, + [Parameter(Mandatory=$false)] [System.String] $ZipballName = '', + [Parameter(Mandatory=$false)] [System.String[]] $ReleaseFiles = @(), + [Parameter(Mandatory=$false)] [System.String] $ReleaseFile = 'RELEASE.txt', + [Parameter(Mandatory=$false)] [System.Boolean] $ConverMdToHtml = $false, + [Parameter(Mandatory=$false)] [System.String] $BasePath = '.' + ) + + $BasePath = Resolve-Path $BasePath + $ReleaseDirectory = "${Env:APPVEYOR_PROJECT_NAME}-${Env:APPVEYOR_BUILD_ID}-${Env:APPVEYOR_JOB_ID}-${Env:APPVEYOR_JOB_NUMBER}" + + PrepareReleaseNote ` + -PhpVersion $PhpVersion ` + -BuildType $BuildType ` + -Platform $Platform ` + -ReleaseFile $ReleaseFile ` + -ReleaseDirectory $ReleaseDirectory ` + -BasePath $BasePath + + $ReleaseDestination = "${BasePath}\${ReleaseDirectory}" + + $CurrentPath = Resolve-Path '.' + + if ($ConverMdToHtml) { + InstallReleaseDependencies + FormatReleaseFiles -ReleaseDirectory $ReleaseDirectory + } + + if ($ReleaseFiles.count -gt 0) { + foreach ($File in $ReleaseFiles) { + Copy-Item "${File}" "${ReleaseDestination}" + Write-Debug "Copy ${File} to ${ReleaseDestination}" + } + } + + if (!$ZipballName) { + if (!$Env:RELEASE_ZIPBALL) { + throw "Required parameter `"ZipballName`" is missing" + } else { + $ZipballName = $Env:RELEASE_ZIPBALL; + } + } + + Ensure7ZipIsInstalled + + Set-Location "${ReleaseDestination}" + $Output = (& 7z a "${ZipballName}.zip" *) + $ExitCode = $LASTEXITCODE + + $DirectoryContents = Get-ChildItem -Path "${ReleaseDestination}" + Write-Debug ($DirectoryContents | Out-String) + + if ($ExitCode -ne 0) { + Set-Location "${CurrentPath}" + throw "An error occurred while creating release zippbal: `"${ZipballName}`". ${Output}" + } + + Move-Item "${ZipballName}.zip" -Destination "${BasePath}" + Set-Location "${CurrentPath}" +} + +function FormatReleaseFiles { + param ( + [Parameter(Mandatory=$true)] [System.String] $ReleaseDirectory, + [Parameter(Mandatory=$false)] [System.String] $BasePath = '.' + ) + + EnsurePandocIsInstalled + + $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName + + $BasePath = Resolve-Path $BasePath + Set-Location "${BasePath}" + + Get-ChildItem (Get-Item -Path ".\" -Verbose).FullName *.md | + ForEach-Object{ + $BaseName = $_.BaseName + pandoc -f markdown -t html5 "${BaseName}.md" > "${BasePath}\${ReleaseDirectory}\${BaseName}.html" + } + + Set-Location "${CurrentPath}" +} + +function SetupPhpVersionString { + param ( + [Parameter(Mandatory=$true)] [String] $Pattern + ) + + $RemoteUrl = 'http://windows.php.net/downloads/releases/sha256sum.txt' + $Destination = "${Env:Temp}\php-sha256sum.txt" + + if (-not (Test-Path $Destination)) { + DownloadFile $RemoteUrl $Destination + } + + $VersionString = Get-Content $Destination | Where-Object { + $_ -match "php-($Pattern\.\d+)-src" + } | ForEach-Object { $matches[1] } + + if ($VersionString -NotMatch '\d+\.\d+\.\d+' -or $null -eq $VersionString) { + throw "Unable to obtain PHP version string using pattern 'php-($Pattern\.\d+)-src'" + } + + Write-Output $VersionString.Split(' ')[-1] +} + +function SetupPrerequisites { + Ensure7ZipIsInstalled + EnsureRequiredDirectoriesPresent -Directories C:\Downloads +} + +function Ensure7ZipIsInstalled { + if (-not (Get-Command "7z" -ErrorAction SilentlyContinue)) { + $7zipInstallationDirectory = "${Env:ProgramFiles}\7-Zip" + + if (-not (Test-Path "${7zipInstallationDirectory}")) { + throw "The 7-zip file archiver is needed to use this module" + } + + $Env:Path += ";$7zipInstallationDirectory" + } +} + +function InstallReleaseDependencies { + EnsureChocolateyIsInstalled + $Output = (choco install -y --no-progress pandoc) + $ExitCode = $LASTEXITCODE + + if ($ExitCode -ne 0) { + throw "An error occurred while installing pandoc. ${Output}" + } +} + +function EnsureChocolateyIsInstalled { + if (-not (Get-Command "choco" -ErrorAction SilentlyContinue)) { + $ChocolateyInstallationDirectory = "${Env:ChocolateyInstall}\bin" + + if (-not (Test-Path "$ChocolateyInstallationDirectory")) { + throw "The choco is needed to use this module" + } + + $Env:Path += ";$ChocolateyInstallationDirectory" + } +} + +function EnsurePandocIsInstalled { + if (-not (Get-Command "pandoc" -ErrorAction SilentlyContinue)) { + $PandocInstallationDirectory = "${Env:ChocolateyInstall}\bin" + + if (-not (Test-Path "$PandocInstallationDirectory")) { + throw "The pandoc is needed to use this module" + } + + $Env:Path += ";$PandocInstallationDirectory" + } + + $Output = (& "pandoc" -v) + $ExitCode = $LASTEXITCODE + + if ($ExitCode -ne 0) { + throw "An error occurred while self testing pandoc. ${Output}" + } +} + +function EnsureRequiredDirectoriesPresent { + param ( + [Parameter(Mandatory=$true)] [String[]] $Directories, + [Parameter(Mandatory=$false)] [String] $Prefix = "" + ) + + foreach ($Dir in $Directories) { + if (-not (Test-Path $Dir)) { + if ($Prefix) { + New-Item -ItemType Directory -Force -Path "${Prefix}\${Dir}" | Out-Null + } else { + New-Item -ItemType Directory -Force -Path "${Dir}" | Out-Null + } + + } + } +} + +function DownloadFile { + param ( + [Parameter(Mandatory=$true)] [System.String] $RemoteUrl, + [Parameter(Mandatory=$true)] [System.String] $Destination + ) + + $RetryMax = 5 + $RetryCount = 0 + $Completed = $false + + $WebClient = New-Object System.Net.WebClient + $WebClient.Headers.Add('User-Agent', 'AppVeyor PowerShell Script') + + Write-Debug "Downloading: '${RemoteUrl}' => '${Destination}' ..." + + while (-not $Completed) { + try { + $WebClient.DownloadFile($RemoteUrl, $Destination) + $Completed = $true + } catch { + if ($RetryCount -ge $RetryMax) { + $ErrorMessage = $_.Exception.Message + Write-Error -Message "${ErrorMessage}" + $Completed = $true + } else { + $RetryCount++ + } + } + } +} + +function Expand-Item7zip { + param( + [Parameter(Mandatory=$true)] [System.String] $Archive, + [Parameter(Mandatory=$true)] [System.String] $Destination + ) + + if (-not (Test-Path -Path $Archive -PathType Leaf)) { + throw "Specified archive file does not exist: ${Archive}" + } + + Write-Debug "Unzipping ${Archive} to ${Destination} ..." + + if (-not (Test-Path -Path $Destination -PathType Container)) { + New-Item $Destination -ItemType Directory | Out-Null + } + + $ExitCode = 0 + + if ("${Archive}" -like "*.tgz") { + $Output = (& 7z x -tgzip "$Archive" -bd -y "-o${Env:Temp}") + $ExitCode = $LASTEXITCODE + + if ($ExitCode -eq 0) { + $Archive = "${Env:Temp}/{0}.tar" -f [System.IO.Path]::GetFileNameWithoutExtension($Archive) + } + } + + if ($ExitCode -eq 0) { + $Output = (& 7z x "$Archive" "-o$Destination" -aoa -bd -y -r) + $ExitCode = $LASTEXITCODE + } + + if ($ExitCode -ne 0) { + throw "An error occurred while unzipping '${Archive}' to '${Destination}'. ${Output}" + } +} diff --git a/config.m4 b/config.m4 index ac295f4..2089df1 100644 --- a/config.m4 +++ b/config.m4 @@ -5,21 +5,17 @@ sinclude(./autoconf/pecl.m4) PECL_INIT([http_message]) -PHP_ARG_WITH(http-message, for http_message support, -[ --with-http-message Include http_message support]) +PHP_ARG_ENABLE(http-message, whether to enable http-message, [ --enable-http-message Enable http_message]) if test "$PHP_HTTP_MESSAGE" != "no"; then - PECL_HAVE_PHP_EXT([psr], [ - PECL_HAVE_PHP_EXT_HEADER([psr]) - ], [ - AC_MSG_ERROR([please install and enable pecl/psr]) - ]) + PECL_HAVE_PHP_EXT([psr], [PECL_HAVE_PHP_EXT_HEADER([psr])], [AC_MSG_ERROR([please install and enable the psr extension])]) - AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message support]) + AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message]) PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c, $ext_shared) PHP_ADD_EXTENSION_DEP([http_message], [psr], true) PHP_ADD_MAKEFILE_FRAGMENT + PHP_INSTALL_HEADERS([ext/http_message], [php_http_message.h]) fi diff --git a/config.w32 b/config.w32 index 4148511..c4b6989 100644 --- a/config.w32 +++ b/config.w32 @@ -1,13 +1,10 @@ // $Id$ // vim:ft=javascript -ARG_WITH("http_message", "Include http_message support", "no"); +ARG_ENABLE("http-message", "enable http_message", "no"); if (PHP_HTTP_MESSAGE != "no") { - ADD_FLAG("LIBS_CLI", "php_psr.lib"); - EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); - AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'Have http_message support'); + AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'enable http_message support'); PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } - From 00831adb51b0bc823fe58504332fded9be53eec3 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 10 Jul 2019 21:57:35 +0200 Subject: [PATCH 27/67] Appveyor output test log on error --- .appveyor.yml | 11 ++++++++--- .ci/appveyor.psm1 | 4 ++-- .ci/php-appveyor.psm1 | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 82e8509..decaad3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -35,7 +35,7 @@ platform: # - x64 init: - - ps: $DebugPreference = 'Continue' #'SilentlyContinue' # Continue + - ps: $DebugPreference = 'SilentlyContinue' # Continue install: - ps: Import-Module .\.ci\php-appveyor.psm1 @@ -77,9 +77,8 @@ after_build: -BuildType $Env:BUILD_TYPE ` -Platform $Env:PLATFORM ` -ConverMdToHtml $true ` - -ReleaseFiles "${Env:RELEASE_DLL_PATH}",` + -ReleaseFiles "${Env:RELEASE_FOLDER}\php_${Env:EXTNAME}.dll",` "${Env:APPVEYOR_BUILD_FOLDER}\LICENSE" - artifacts: - path: '.\$(RELEASE_ZIPBALL).zip' name: '$(Env:EXTNAME)' @@ -94,3 +93,9 @@ on_failure : If (Test-Path -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log") { Get-Content -Path "${Env:APPVEYOR_BUILD_FOLDER}\compile.log" } + + Get-ChildItem "${Env:APPVEYOR_BUILD_FOLDER}\tests" -Recurse -Filter *.diff | Foreach-Object { + [Environment]::NewLine + Write-Output $_.FullName + Get-Content -Path $_.FullName + } diff --git a/.ci/appveyor.psm1 b/.ci/appveyor.psm1 index ef79ae3..9ba4a39 100644 --- a/.ci/appveyor.psm1 +++ b/.ci/appveyor.psm1 @@ -35,13 +35,13 @@ Function InitializeBuildVars { Function InitializeReleaseVars { If ($Env:PLATFORM -eq 'x86') { - If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + If ($Env:BUILD_TYPE -Match "nts-Win32") { $Env:RELEASE_SUBFOLDER = "Release" } Else { $Env:RELEASE_SUBFOLDER = "Release_TS" } } Else { - If ($Env:PHP_BUILD_TYPE -Match "nts-Win32") { + If ($Env:BUILD_TYPE -Match "nts-Win32") { $Env:RELEASE_SUBFOLDER = "${Env:PLATFORM}\Release" } Else { $Env:RELEASE_SUBFOLDER = "${Env:PLATFORM}\Release_TS" diff --git a/.ci/php-appveyor.psm1 b/.ci/php-appveyor.psm1 index c4612a4..2ac57ca 100644 --- a/.ci/php-appveyor.psm1 +++ b/.ci/php-appveyor.psm1 @@ -181,10 +181,10 @@ Function InstallPeclHeaders { Expand-Item7zip $DownloadFile "${Env:Temp}" + Write-Debug "Copy header files to ${InstallPath}\${Name}" + New-Item -Path "${InstallPath}" -Name "${Name}" -ItemType "directory" | Out-Null Copy-Item "${Env:Temp}\${Name}-${Version}\*.h" -Destination "${InstallPath}\${Name}" -Recurse - - Get-ChildItem -Path "${InstallPath}\${Name}" } function InstallComposer { From ed047c349a4da54dfb81b24ea76d7688afd7d1bf Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 10 Jul 2019 22:23:43 +0200 Subject: [PATCH 28/67] Don't use hardcoded linux paths in tests --- .appveyor.yml | 2 +- tests/ServerRequest/__construct_002.phpt | 2 +- tests/ServerRequest/__construct_003.phpt | 14 +++++++------- tests/UploadedFile/__construct_001.phpt | 4 ++-- tests/UploadedFile/__construct_002.phpt | 4 ++-- tests/UploadedFile/getStream_001.phpt | 2 +- tests/UploadedFile/getStream_002.phpt | 2 +- tests/UploadedFile/getStream_err02.phpt | 4 ++-- tests/UploadedFile/moveTo_err02.phpt | 4 ++-- tests/UploadedFile/moveTo_err03.phpt | 4 ++-- tests/UploadedFile/moveTo_err04.phpt | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index decaad3..210fac5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -81,7 +81,7 @@ after_build: "${Env:APPVEYOR_BUILD_FOLDER}\LICENSE" artifacts: - path: '.\$(RELEASE_ZIPBALL).zip' - name: '$(Env:EXTNAME)' + name: '$(EXTNAME)' type: zip on_failure : diff --git a/tests/ServerRequest/__construct_002.phpt b/tests/ServerRequest/__construct_002.phpt index f33c5d6..3b5e8fc 100644 --- a/tests/ServerRequest/__construct_002.phpt +++ b/tests/ServerRequest/__construct_002.phpt @@ -91,7 +91,7 @@ object(HttpMessage\ServerRequest)#1 (12) { ["stream":protected]=> NULL ["file":protected]=> - string(17) "/tmp/uploadedfile" + string(%d) "%s/uploadedfile" ["size":protected]=> int(2822) ["error":protected]=> diff --git a/tests/ServerRequest/__construct_003.phpt b/tests/ServerRequest/__construct_003.phpt index 76bc937..9d0a74a 100644 --- a/tests/ServerRequest/__construct_003.phpt +++ b/tests/ServerRequest/__construct_003.phpt @@ -82,14 +82,14 @@ $request = new HttpMessage\ServerRequest( var_dump($request->getUploadedFiles()); ?> ---EXPECT-- +--EXPECTF-- array(3) { ["document"]=> object(HttpMessage\UploadedFile)#4 (8) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile01" + string(%d) "%s/uploadedfile01" ["size":protected]=> int(2822) ["error":protected]=> @@ -110,7 +110,7 @@ array(3) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile02" + string(%d) "%s/uploadedfile02" ["size":protected]=> int(3724) ["error":protected]=> @@ -129,7 +129,7 @@ array(3) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile03" + string(%d) "%s/uploadedfile03" ["size":protected]=> int(263) ["error":protected]=> @@ -151,7 +151,7 @@ array(3) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile04" + string(%d) "%s/uploadedfile04" ["size":protected]=> int(942) ["error":protected]=> @@ -172,7 +172,7 @@ array(3) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile05" + string(%d) "%s/uploadedfile05" ["size":protected]=> int(2391) ["error":protected]=> @@ -232,7 +232,7 @@ array(3) { ["stream":protected]=> NULL ["file":protected]=> - string(19) "/tmp/uploadedfile07" + string(%d) "%s/uploadedfile07" ["size":protected]=> int(4732) ["error":protected]=> diff --git a/tests/UploadedFile/__construct_001.phpt b/tests/UploadedFile/__construct_001.phpt index 8a42785..202f67b 100644 --- a/tests/UploadedFile/__construct_001.phpt +++ b/tests/UploadedFile/__construct_001.phpt @@ -18,12 +18,12 @@ var_dump($upload->getClientMediaType()); ---EXPECT-- +--EXPECTF-- object(HttpMessage\UploadedFile)#1 (8) { ["stream":protected]=> NULL ["file":protected]=> - string(17) "/tmp/uploadedfile" + string(%d) "%s/uploadedfile" ["size":protected]=> int(99) ["error":protected]=> diff --git a/tests/UploadedFile/__construct_002.phpt b/tests/UploadedFile/__construct_002.phpt index a12aa53..0bc5ecb 100644 --- a/tests/UploadedFile/__construct_002.phpt +++ b/tests/UploadedFile/__construct_002.phpt @@ -18,12 +18,12 @@ var_dump($upload->getClientMediaType()); ---EXPECT-- +--EXPECTF-- object(HttpMessage\UploadedFile)#1 (8) { ["stream":protected]=> NULL ["file":protected]=> - string(17) "/tmp/uploadedfile" + string(%d) "%s/uploadedfile" ["size":protected]=> NULL ["error":protected]=> diff --git a/tests/UploadedFile/getStream_001.phpt b/tests/UploadedFile/getStream_001.phpt index 3e23366..df63490 100644 --- a/tests/UploadedFile/getStream_001.phpt +++ b/tests/UploadedFile/getStream_001.phpt @@ -24,6 +24,6 @@ object(HttpMessage\Stream)#2 (1) { ["stream":protected]=> resource(%d) of type (stream) } -string(17) "/tmp/uploadedfile" +string(%d) "%s/uploadedfile" string(3) "foo" bool(true) \ No newline at end of file diff --git a/tests/UploadedFile/getStream_002.phpt b/tests/UploadedFile/getStream_002.phpt index 7c03280..29d95eb 100644 --- a/tests/UploadedFile/getStream_002.phpt +++ b/tests/UploadedFile/getStream_002.phpt @@ -32,6 +32,6 @@ object(HttpMessage\Stream)#3 (1) { ["stream":protected]=> resource(%d) of type (stream) } -string(17) "/tmp/uploadedfile" +string(%d) "%s/uploadedfile" string(3) "foo" bool(true) \ No newline at end of file diff --git a/tests/UploadedFile/getStream_err02.phpt b/tests/UploadedFile/getStream_err02.phpt index d97a9bc..963655c 100644 --- a/tests/UploadedFile/getStream_err02.phpt +++ b/tests/UploadedFile/getStream_err02.phpt @@ -23,5 +23,5 @@ if (file_exists(sys_get_temp_dir() . '/movedfile') { unlink(sys_get_temp_dir() . '/movedfile'); } ?> ---EXPECT-- -Uploaded file '/tmp/uploadedfile' has already been moved +--EXPECTF-- +Uploaded file '%s/uploadedfile' has already been moved diff --git a/tests/UploadedFile/moveTo_err02.phpt b/tests/UploadedFile/moveTo_err02.phpt index 1d6481c..a88bc92 100644 --- a/tests/UploadedFile/moveTo_err02.phpt +++ b/tests/UploadedFile/moveTo_err02.phpt @@ -26,5 +26,5 @@ if (file_exists(sys_get_temp_dir() . '/other') { unlink(sys_get_temp_dir() . '/other'); } ?> ---EXPECT-- -Uploaded file '/tmp/uploadedfile' has already been moved +--EXPECTF-- +Uploaded file '%s/uploadedfile' has already been moved diff --git a/tests/UploadedFile/moveTo_err03.phpt b/tests/UploadedFile/moveTo_err03.phpt index ff0d0a1..fb12acf 100644 --- a/tests/UploadedFile/moveTo_err03.phpt +++ b/tests/UploadedFile/moveTo_err03.phpt @@ -20,5 +20,5 @@ if (file_exists(sys_get_temp_dir() . '/uploadedfile') { } ?> --EXPECTF-- -Warning: HttpMessage\UploadedFile::moveTo(/tmp/nosuchdir/movedfile): failed to open stream: No such file or directory in %s/moveTo_err03.php on line %d -Failed to move uploaded file '/tmp/uploadedfile' to '/tmp/nosuchdir/movedfile' \ No newline at end of file +Warning: HttpMessage\UploadedFile::moveTo(%s/nosuchdir/movedfile): failed to open stream: No such file or directory in %smoveTo_err03.php on line %d +Failed to move uploaded file '%s/uploadedfile' to '%s/nosuchdir/movedfile' \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_err04.phpt b/tests/UploadedFile/moveTo_err04.phpt index 7ff0be9..e625dc0 100644 --- a/tests/UploadedFile/moveTo_err04.phpt +++ b/tests/UploadedFile/moveTo_err04.phpt @@ -23,4 +23,4 @@ if (file_exists(sys_get_temp_dir() . '/movedfile') { } ?> --EXPECTF-- -Won't move '/tmp/uploadedfile'; not an uploaded file \ No newline at end of file +Won't move '%s/uploadedfile'; not an uploaded file \ No newline at end of file From ed8189ffae6aba16c2d17e3d25327987b0efec38 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 01:02:08 +0200 Subject: [PATCH 29/67] Build and release to GitHub by Travis and AppVeyor Travis builds (and signs) pecl package. Build on all envs for AppVeyor Version v0.1.0 --- .appveyor.yml | 41 +++++++-- .gitignore | 2 + .travis.yml | 24 +++++- package.xml | 204 +++++++++++++++++++++++++++++++++++++++++++++ php_http_message.h | 2 +- sign.gpg.enc | Bin 0 -> 1200 bytes 6 files changed, 264 insertions(+), 9 deletions(-) create mode 100644 package.xml create mode 100644 sign.gpg.enc diff --git a/.appveyor.yml b/.appveyor.yml index 210fac5..a4fac26 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,21 @@ environment: EXTNAME: http_message matrix: + - PHP_VERSION: 7.2 + VC_VERSION: 15 + BUILD_TYPE: Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - PHP_VERSION: 7.2 + VC_VERSION: 15 + BUILD_TYPE: nts-Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - PHP_VERSION: 7.3 + VC_VERSION: 15 + BUILD_TYPE: Win32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - PHP_VERSION: 7.3 VC_VERSION: 15 BUILD_TYPE: nts-Win32 @@ -32,7 +47,7 @@ cache: platform: - x86 -# - x64 + - x64 init: - ps: $DebugPreference = 'SilentlyContinue' # Continue @@ -78,11 +93,8 @@ after_build: -Platform $Env:PLATFORM ` -ConverMdToHtml $true ` -ReleaseFiles "${Env:RELEASE_FOLDER}\php_${Env:EXTNAME}.dll",` + "${Env:APPVEYOR_BUILD_FOLDER}\CREDITS",\ "${Env:APPVEYOR_BUILD_FOLDER}\LICENSE" -artifacts: - - path: '.\$(RELEASE_ZIPBALL).zip' - name: '$(EXTNAME)' - type: zip on_failure : - ps: >- @@ -99,3 +111,22 @@ on_failure : Write-Output $_.FullName Get-Content -Path $_.FullName } + +artifacts: + - path: '.\$(RELEASE_ZIPBALL).zip' + name: '$(EXTNAME)' + type: zip + +deploy: + release: v$(appveyor_build_version) + description: 'v$(appveyor_build_version)' + provider: GitHub + auth_token: + secure: 9kSFTreufYy0WOpd+eYAFa+2IjSxe1idbVAzehcTS/womadyGxVG6qTKpJnXDmTh + artifact: '.\$(RELEASE_ZIPBALL).zip' + draft: false + prerelease: true + force_update: true + on: + branch: master + APPVEYOR_REPO_TAG: true diff --git a/.gitignore b/.gitignore index c01a1c1..eb960ca 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ cmake-build-* vendor composer.lock tmp-php.ini +*.gpg +/*.tgz diff --git a/.travis.yml b/.travis.yml index 5fdc859..c9a38ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,27 @@ script: after_failure: - | - for LOG in $(find tests -name '*.log'); do - echo $LOG - tail -n +2 $LOG + for FILE in $(find tests -name '*.diff'); do + echo $FILE + cat FILE echo done +before_deploy: + - openssl aes-256-cbc -K $encrypted_36ea4391f664_key -iv $encrypted_36ea4391f664_iv -in sign.gpg.enc -out sign.gpg -d + - gpg --import sign.gpg + - rm sign.gpg + - pecl package + - export RELEASE_PACKAGE=$(ls "http_message-*.tgz") + - pecl sign "$RELEASE_PACKAGE" + +deploy: + provider: releases + api_key: + secure: "HuYxK89LGMINNzDyrA9xXVzQB7YKo563Q1EVkAOrrv7cDKbfVLTPHfI9huB8XnzDJgp1EhrXA3hMKeJdpbtzoEhiaVDc/eeFcCubhf+VEsMbke9TOYIEx7mSNDpV0igyWDR1bt+8GrCFkP04NMzzlqU+KoW0ceK/xCaMRhNWiskf3Z+e2Xne3yEVd64A61xtyPMbaOIqqmjkmqCyrN9DT+5g+zZVMz1UssdfRqMCKTyHcaYYFayQwSZgmAxZO3WKoHnd5ydoii2XIBHto7RESqAoyemw/Ksw7YdplxsZMfbCsmiSuwrlmd1t/BX7QIULeJsVwPiv7MWJWjh8VRIiFCw5FdZ+n2kLfL32MY8r4hl7Uo9nEkNaIYRBX0ryV5XXRU/2q1nuz8Knaz++Q+tPodmMp8vzmDGl2cguq9KuKbVEbiFjR+PO96YFlKdtDosUQFjbSbQOFDQdstPFSZr5s/PKPVj5Va33PyyrLI9TMZwgWLPzMEqerGXy8meigeZ0r0m3DG4slzxhxE9y30fFEx9fWPNR3AN/1NGi7WTsqonPQitu1M7YyKCdMqjWJkr++geapJwKVX/poxExQ4i0TEkgqGWmV9nJehGJ5nS8s2tH4PR8+3bA2gvNoqBO+jmd8CLjkPGbCPu8OlvdwXmeKJYsX382iGG8CxrDDPhGlr4=" + file: "$RELEASE_PACKAGE" + skip_cleanup: true + name: "v$TRAVIS_TAG" + prerelease: true + on: + tags: true diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..99b3ff3 --- /dev/null +++ b/package.xml @@ -0,0 +1,204 @@ + + + http_message + pecl.php.net + PSR-7 HTTP Message implementation + PSR-7 compatible HTTP Message implementation as PHP extension + + Arnold Daniels + jasny + jasny@php.net + yes + + 2019-07-10 + + 0.1.0 + 0.1.0 + + + beta + beta + + MIT License + + Initial release. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 7.2.0 + + + 1.4.3 + + + + http_message + + + diff --git a/php_http_message.h b/php_http_message.h index 95d8c96..decb2ab 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.0.1" +#define PHP_HTTP_MESSAGE_VERSION "0.1.0" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 diff --git a/sign.gpg.enc b/sign.gpg.enc new file mode 100644 index 0000000000000000000000000000000000000000..54b7188dd6c406c981a2212d0e90724c21aeab7e GIT binary patch literal 1200 zcmV;h1W)^#jIDI_@kM2W4vKjz5e}T>*yd@!*U@1bb-DrgANxX8>ilAXEy_3oE?X5> z5(OVVFiV6aM&;1g61U(mMjb;PANml1ER3YTxqq`4i<|f~Ah8W$L%+UXZ9pMtr)Dn* z*ASQoFbqg($!lQCzcht!DPQ|v(`(+v)^KYzMLK61_h!84y))(v-XU{^ZQhoX5_n9Y zV|j=ytBK`P*3JE&@-)?Y{!z>IWjj&XHKayz8NniPQ4Iv-y%O?_0B)w$fp`C$q_X*Pv#H>*`^ zJ>ILy%>1~5SuknC2ICq%y@Tpi@4>LH%a35UljLV3JAU|1>;#VjY+wwN!G0kaI%5Om zW%j7eb5DN{jky&gxXi3{@;le&*@xTYIkwwB+#d=F{b^*h75i1FUDy6Fz{=Z+50=FfFfIEfg z*jL%OVvKR?y>YL$4PLptmY)yqv}e7jtNp~`0ZqKTzG^8W_m;(L1;ET3k3{7$c|?-2 zQ*nJ$nzX!HCVqe5m-PJ+wDIKQ;>T;jQ;djVdq5`3Z)CID+&nh@vvF|ZnY!9M{tzA7 zf39DWz^hcrLsgR)I>GL*kCYtG?D|bl@kFd>9;tK z$VMzW9oT}%>ni~R3S7$qr@SEzN-LSt@8v(!cl4!`v-A5}w_ls0Ws(&*@4?4$o z!xSIM?;G5Mv?sIQ3#$^5-GxjAtS5;*K%XLt`|gWCh5daSlv31n6c zX_TAV!~9nJ(ffm`$ccb*RGR&A7wmPMLd7nCMWRfIR>|?P5CD;8jZnAgcijE3ZlGLTK Date: Thu, 11 Jul 2019 01:17:54 +0200 Subject: [PATCH 30/67] Update README Fixup appveyor config --- .appveyor.yml | 2 +- README.md | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a4fac26..024a675 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -93,7 +93,7 @@ after_build: -Platform $Env:PLATFORM ` -ConverMdToHtml $true ` -ReleaseFiles "${Env:RELEASE_FOLDER}\php_${Env:EXTNAME}.dll",` - "${Env:APPVEYOR_BUILD_FOLDER}\CREDITS",\ + "${Env:APPVEYOR_BUILD_FOLDER}\CREDITS",` "${Env:APPVEYOR_BUILD_FOLDER}\LICENSE" on_failure : diff --git a/README.md b/README.md index ff61dc8..d548649 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# PSR-7 HTTP Message as Pecl extension +![improved PHP library](https://user-images.githubusercontent.com/100821/46372249-e5eb7500-c68a-11e8-801a-2ee57da3e5e3.png) -[![Build Status](https://travis-ci.org/jasny/http_message-php-ext.svg?branch=master)](https://travis-ci.org/jasny/http_message-php-ext) -[![Build status](https://ci.appveyor.com/api/projects/status/7rof1vr8mv4kam17/branch/master?svg=true)](https://ci.appveyor.com/project/jasny/http_message-php-ext/branch/master) +# PSR-7 HTTP Message as PHP extension + +[![Build Status](https://travis-ci.org/improved-php-library/http-message.svg?branch=master)](https://travis-ci.org/improved-php-library/http-message) +[![Build status](https://ci.appveyor.com/api/projects/status/7rof1vr8mv4kam17/branch/master?svg=true)](https://ci.appveyor.com/project/jasny/http_message/branch/master) [PSR-7 HTTP Message](https://www.php-fig.org/psr/psr-7/) implementation as PHP extension written in C. @@ -9,10 +11,16 @@ ## Requirements -* PHP 7.x +* PHP 7.2+ ## Installation +pecl install http_message-beta + +### Manual build + +Instead of installing this extension from pecl, you can build it manually + phpize ./configure make From 9b4cdac05aede46be8c603d62d6ddfc1dd62ed83 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 01:28:29 +0200 Subject: [PATCH 31/67] Set appveyor version dynamically --- .appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 024a675..57db776 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,5 @@ # See https://github.com/sergeyklay/php-appveyor -version: '{branch}.{build}' - branches: only: - master @@ -51,6 +49,12 @@ platform: init: - ps: $DebugPreference = 'SilentlyContinue' # Continue + - ps: >- + if ($env:APPVEYOR_REPO_TAG -eq "true") { + Update-AppveyorBuild -Version "$($Env:APPVEYOR_REPO_TAG_NAME.TrimStart("v"))" + } else { + Update-AppveyorBuild -Version "${Env:APPVEYOR_REPO_BRANCH}-$($Env:APPVEYOR_REPO_COMMIT.Substring(0, 7))" + } install: - ps: Import-Module .\.ci\php-appveyor.psm1 From 160ee60b4ec47cf6be77710e02df5cc2fd9870fe Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 01:58:10 +0200 Subject: [PATCH 32/67] Fix travis build on tag --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9a38ab..7d69880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ branches: only: - master - travis + - /^v\d+\.\d+\.\d+$/ before_install: - pecl install --nodeps psr @@ -41,7 +42,7 @@ before_deploy: - gpg --import sign.gpg - rm sign.gpg - pecl package - - export RELEASE_PACKAGE=$(ls "http_message-*.tgz") + - export RELEASE_PACKAGE=$(ls http_message-*.tgz) - pecl sign "$RELEASE_PACKAGE" deploy: From c8912bf06da6a403b2fd20bed53d7b4dc7a5afde Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 02:21:11 +0200 Subject: [PATCH 33/67] Travis no interaction --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7d69880..2f9f3c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ before_deploy: - rm sign.gpg - pecl package - export RELEASE_PACKAGE=$(ls http_message-*.tgz) - - pecl sign "$RELEASE_PACKAGE" + - echo | pecl sign "$RELEASE_PACKAGE" deploy: provider: releases From e4cc85a3ac503dcd58846e2261e7c82e5ec0a2ec Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 02:39:34 +0200 Subject: [PATCH 34/67] Travis don't sign for now; not working --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f9f3c7..759f674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,7 @@ before_deploy: - rm sign.gpg - pecl package - export RELEASE_PACKAGE=$(ls http_message-*.tgz) - - echo | pecl sign "$RELEASE_PACKAGE" +# - echo | pecl sign "$RELEASE_PACKAGE" deploy: provider: releases From 1a7bb3019d30216e8178bfdc9ac4d96dd6497132 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 02:43:20 +0200 Subject: [PATCH 35/67] Fix deploy AppVeyor --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 57db776..f35c73f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -127,7 +127,7 @@ deploy: provider: GitHub auth_token: secure: 9kSFTreufYy0WOpd+eYAFa+2IjSxe1idbVAzehcTS/womadyGxVG6qTKpJnXDmTh - artifact: '.\$(RELEASE_ZIPBALL).zip' + artifact: '$(RELEASE_ZIPBALL).zip' draft: false prerelease: true force_update: true From 2519b5d9b2128ae64b418195d9535bacffc9d0ce Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 03:07:05 +0200 Subject: [PATCH 36/67] Fixup travis release --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 759f674..7083d6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ deploy: secure: "HuYxK89LGMINNzDyrA9xXVzQB7YKo563Q1EVkAOrrv7cDKbfVLTPHfI9huB8XnzDJgp1EhrXA3hMKeJdpbtzoEhiaVDc/eeFcCubhf+VEsMbke9TOYIEx7mSNDpV0igyWDR1bt+8GrCFkP04NMzzlqU+KoW0ceK/xCaMRhNWiskf3Z+e2Xne3yEVd64A61xtyPMbaOIqqmjkmqCyrN9DT+5g+zZVMz1UssdfRqMCKTyHcaYYFayQwSZgmAxZO3WKoHnd5ydoii2XIBHto7RESqAoyemw/Ksw7YdplxsZMfbCsmiSuwrlmd1t/BX7QIULeJsVwPiv7MWJWjh8VRIiFCw5FdZ+n2kLfL32MY8r4hl7Uo9nEkNaIYRBX0ryV5XXRU/2q1nuz8Knaz++Q+tPodmMp8vzmDGl2cguq9KuKbVEbiFjR+PO96YFlKdtDosUQFjbSbQOFDQdstPFSZr5s/PKPVj5Va33PyyrLI9TMZwgWLPzMEqerGXy8meigeZ0r0m3DG4slzxhxE9y30fFEx9fWPNR3AN/1NGi7WTsqonPQitu1M7YyKCdMqjWJkr++geapJwKVX/poxExQ4i0TEkgqGWmV9nJehGJ5nS8s2tH4PR8+3bA2gvNoqBO+jmd8CLjkPGbCPu8OlvdwXmeKJYsX382iGG8CxrDDPhGlr4=" file: "$RELEASE_PACKAGE" skip_cleanup: true - name: "v$TRAVIS_TAG" + name: "$TRAVIS_TAG" prerelease: true on: tags: true From afed6bcfedb1e66ee0486b654070f27ee764f344 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 13:36:00 +0200 Subject: [PATCH 37/67] Added psr dependency for config.w32 and in packacke.xml --- config.w32 | 1 + package.xml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/config.w32 b/config.w32 index c4b6989..59177d8 100644 --- a/config.w32 +++ b/config.w32 @@ -6,5 +6,6 @@ ARG_ENABLE("http-message", "enable http_message", "no"); if (PHP_HTTP_MESSAGE != "no") { EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'enable http_message support'); + ADD_EXTENSION_DEP('http_message', 'psr'); PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } diff --git a/package.xml b/package.xml index 99b3ff3..db67d30 100644 --- a/package.xml +++ b/package.xml @@ -196,6 +196,10 @@ 1.4.3 + + psr + 0.6.0 + http_message From 4e6ba69d218ef48ce45b47d1a8fcc4ae6917976b Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 11 Jul 2019 13:49:00 +0200 Subject: [PATCH 38/67] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d548649..c585b41 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,14 @@ ## Requirements * PHP 7.2+ +* [psr extension 0.6+](https://github.com/jbboehr/php-psr) ## Installation -pecl install http_message-beta +The extension is [available from pecl](https://pecl.php.net/package/http_message). + + pecl install psr-beta + pecl install http_message-beta ### Manual build @@ -34,4 +38,3 @@ Add the following line to your `php.ini` To try out the extension, you can run the following command php -a -d extension=modules/http_message.so - From 4949b47adc535d7f0686a4c0bee8e0f9ea7bfb30 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Fri, 12 Jul 2019 16:35:10 +0200 Subject: [PATCH 39/67] Remove ADD_EXTENSION_DEP from config.m4 and config.w32. These are not required for pecl packages and will actually break the build for w32. --- config.m4 | 2 -- config.w32 | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/config.m4 b/config.m4 index 2089df1..4da5251 100644 --- a/config.m4 +++ b/config.m4 @@ -14,8 +14,6 @@ if test "$PHP_HTTP_MESSAGE" != "no"; then PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c, $ext_shared) - PHP_ADD_EXTENSION_DEP([http_message], [psr], true) - PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/http_message], [php_http_message.h]) fi diff --git a/config.w32 b/config.w32 index 59177d8..ba5eed5 100644 --- a/config.w32 +++ b/config.w32 @@ -6,6 +6,6 @@ ARG_ENABLE("http-message", "enable http_message", "no"); if (PHP_HTTP_MESSAGE != "no") { EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'enable http_message support'); - ADD_EXTENSION_DEP('http_message', 'psr'); PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } + From 263b28747cf0f1ba1f81a8f75373125d608ab273 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 28 Jul 2019 14:20:34 +0200 Subject: [PATCH 40/67] Fix issue with `ServerRequest::getAttribute()`. Did not take a default value, because it only accepted on arg. --- server_request.c | 3 +- tests/ServerRequest/attributes_002.phpt | 40 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/ServerRequest/attributes_002.phpt diff --git a/server_request.c b/server_request.c index 905cf26..698505d 100644 --- a/server_request.c +++ b/server_request.c @@ -373,8 +373,9 @@ PHP_METHOD(ServerRequest, getAttribute) char *name; size_t name_len; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_STRING(name, name_len) + Z_PARAM_OPTIONAL Z_PARAM_ZVAL(default_value) ZEND_PARSE_PARAMETERS_END(); diff --git a/tests/ServerRequest/attributes_002.phpt b/tests/ServerRequest/attributes_002.phpt new file mode 100644 index 0000000..a453a0d --- /dev/null +++ b/tests/ServerRequest/attributes_002.phpt @@ -0,0 +1,40 @@ +--TEST-- +ServerRequest::getAttribute() +--FILE-- +withAttribute('foo', 'bar') + ->withAttribute('colors', ['red', 'green']) + ->withAttribute('user', ['id' => 22, 'name' => 'John']); + +var_dump($request->getAttributes()); +var_dump($request->getAttribute('colors', [])); +var_dump($request->getAttribute('qux', 42)); + +?> +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "bar" + ["colors"]=> + array(2) { + [0]=> + string(3) "red" + [1]=> + string(5) "green" + } + ["user"]=> + array(2) { + ["id"]=> + int(22) + ["name"]=> + string(4) "John" + } +} +array(2) { + [0]=> + string(3) "red" + [1]=> + string(5) "green" +} +int(42) \ No newline at end of file From d37bbf3fbd22ae6cfb921831ec15ede9285e2c29 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 28 Jul 2019 14:50:31 +0200 Subject: [PATCH 41/67] Prepared v0.1.1 release --- package.xml | 44 +++++++++++++++++++++++++++++++++++++++++--- php_http_message.h | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/package.xml b/package.xml index db67d30..1a0234e 100644 --- a/package.xml +++ b/package.xml @@ -10,9 +10,9 @@ jasny@php.net yes - 2019-07-10 + 2019-07-28 - 0.1.0 + 0.1.1 0.1.0 @@ -21,7 +21,7 @@ MIT License - Initial release. +Fixed default value issue with ServerRequest::getAttribute(). The method only accepted one argument. @@ -204,5 +204,43 @@ http_message + + + + 2019-07-28 + + + 0.1.1 + 0.1.0 + + + beta + beta + + MIT License + +Fixed default value issue with ServerRequest::getAttribute(). The method only accepted one argument. + + + + + 2019-07-10 + + + 0.1.0 + 0.1.0 + + + beta + beta + + MIT License + +Initial release. + + + + + diff --git a/php_http_message.h b/php_http_message.h index decb2ab..596474f 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.1.0" +#define PHP_HTTP_MESSAGE_VERSION "0.1.1" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 From 5cbafa3bdb17384103bc89e6ba24d05c03948032 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 13 Aug 2019 03:07:30 +0200 Subject: [PATCH 42/67] Factory WIP. Added macro to check param but use zval. Fixed places where object properties where not initialized. --- CMakeLists.txt | 2 +- factory.c | 228 +++++++++++++++++++++++++++++++++++++++++++++ macros.h | 71 +++++++++++++- message.c | 14 +-- php_http_message.h | 4 +- request.c | 4 +- response.c | 2 +- server_request.c | 7 +- stream.c | 37 ++++---- uploaded_file.c | 59 ++++++++---- uploaded_file.h | 47 ++++++++++ uri.c | 2 +- 12 files changed, 414 insertions(+), 63 deletions(-) create mode 100644 factory.c create mode 100644 uploaded_file.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bd1fc04..8ac1c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ add_custom_target(extension COMMAND phpize && ./configure && make && make instal WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) set(SOURCE_FILES php_http_message - http_message.c message.c request.c uri.c server_request.c response.c stream.c uploaded_file.c) + http_message.c message.c request.c uri.c server_request.c response.c stream.c uploaded_file.c factory.c) execute_process ( COMMAND php-config --include-dir diff --git a/factory.c b/factory.c new file mode 100644 index 0000000..c2cc385 --- /dev/null +++ b/factory.c @@ -0,0 +1,228 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension - Factory methods | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_http_message.h" +#include "macros.h" +#include "uploaded_file.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "zend_string.h" +#include "ext/standard/php_string.h" +#include "ext/psr/psr_http_message.h" +#include "ext/psr/psr_http_factory.h" + +#if HAVE_HTTP_MESSAGE + +zend_class_entry *HttpMessage_Factory_ce = NULL; + +PHP_METHOD(Factory, createRequest) +{ + zval *method, *uri; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) + Z_PARAM_ZVAL_STRING(method) + Z_PARAM_ZVAL(uri) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Request_ce); + zend_call_method_with_1_params(return_value, HttpMessage_Request_ce, NULL, "withMethod", return_value, method); + zend_call_method_with_1_params(return_value, HttpMessage_Request_ce, NULL, "withUri", return_value, uri); +} + +PHP_METHOD(Factory, createResponse) +{ + zval *code = NULL, *reasonPhrase = NULL; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL_LONG(code) + Z_PARAM_ZVAL_STRING(reasonPhrase) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Response_ce); + + if (code != NULL) { + zend_call_method_with_2_params(return_value, HttpMessage_Response_ce, NULL, "withStatus", return_value, code, + reasonPhrase); + } +} + +PHP_METHOD(Factory, createServerRequest) +{ + zval *method, *uri, *serverParams = NULL; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 3) + Z_PARAM_ZVAL_STRING(method) + Z_PARAM_ZVAL(uri) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL_ARRAY_EX(serverParams, 1, 0) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_ServerRequest_ce, serverParams); + zend_call_method_with_1_params(return_value, HttpMessage_ServerRequest_ce, NULL, "withMethod", return_value, + method); + zend_call_method_with_1_params(return_value, HttpMessage_ServerRequest_ce, NULL, "withUri", return_value, uri); +} + +PHP_METHOD(Factory, createStream) +{ + zval *content; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_ZVAL_STRING(content) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Stream_ce); + zend_call_method_with_1_params(return_value, HttpMessage_Stream_ce, NULL, "write", NULL, content); +} + +PHP_METHOD(Factory, createStreamFromFile) +{ + char *file; + size_t file_len; + php_stream *stream; + zval resource; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_STRING(file, file_len) + ZEND_PARSE_PARAMETERS_END(); + + file[file_len] = '\0'; + stream = php_stream_open_wrapper(file, "r+", 0, NULL); + + if (stream == NULL) { + zend_throw_error(NULL, "Failed to open 'php://temp' stream"); + return; + } + + php_stream_to_zval(stream, &resource); + NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Stream_ce, &resource); +} + +PHP_METHOD(Factory, createStreamFromResource) +{ + zval *resource; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_ZVAL(resource) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Stream_ce, resource); +} + +PHP_METHOD(Factory, createUploadedFile) +{ + zval *stream = NULL; + zend_long size = -1, error = 0; + zend_string *clientFilename = NULL, *clientMediaType = NULL; + zend_bool size_is_null = 1; + zend_class_entry *stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 5) + Z_PARAM_OBJECT_OF_CLASS(stream, stream_interface) + Z_PARAM_OPTIONAL + Z_PARAM_LONG_EX(size, size_is_null, 1, 0) + Z_PARAM_LONG(error) + Z_PARAM_STR_EX(clientFilename, 1, 0) + Z_PARAM_STR_EX(clientMediaType, 1, 0) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT(return_value, HttpMessage_UploadedFile_ce); + construct_uploaded_file(return_value, stream, NULL, size_is_null ? -1 : size, error, clientFilename, + clientMediaType, -1); +} + +PHP_METHOD(Factory, createUri) +{ + zval *uri = NULL; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 0) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL_STRING_EX(uri, 1, 0) + ZEND_PARSE_PARAMETERS_END(); + + NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Request_ce, uri); +} + +/* Define HttpMessage\Factory class */ + +static const zend_function_entry request_functions[] = { + HTTP_MESSAGE_ME_EX(Factory, RequestFactory, createRequest) + HTTP_MESSAGE_ME_EX(Factory, ResponseFactory, createResponse) + HTTP_MESSAGE_ME_EX(Factory, ServerRequestFactory, createServerRequest) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStream) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromFile) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromResource) + HTTP_MESSAGE_ME_EX(Factory, UploadedFileFactory, createUploadedFile) + HTTP_MESSAGE_ME_EX(Factory, UriFactory, createUri) + PHP_FE_END +}; + +PHP_MINIT_FUNCTION(http_message_serverrequest) +{ + zend_class_entry ce; + zend_class_entry *request_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestfactoryinterface")); + zend_class_entry *response_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\responsefactoryinterface")); + zend_class_entry *serverrequest_factory + = get_internal_ce(ZEND_STRL("psr\\http\\message\\serverrequestfactoryinterface")); + zend_class_entry *stream_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\streamfactoryinterface")); + zend_class_entry *uploadedfile_factory + = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfilefactoryinterface")); + zend_class_entry *uri_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\urifactoryinterface")); + + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(request_factory, "Factory", "RequestFactory"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(response_factory, "Factory", "ResponseFactory"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(serverrequest_factory, "Factory", "ServerRequestFactory"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(stream_factory, "Factory", "StreamFactory"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(uploadedfile_factory, "Factory", "UploadedFileFactory"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(uri_factory, "Factory", "UriFactory"); + + if (UNEXPECTED( + HttpMessage_Request_ce == NULL || HttpMessage_Response_ce == NULL || HttpMessage_ServerRequest_ce == NULL || + HttpMessage_Stream_ce == NULL || HttpMessage_UploadedFile_ce == NULL || HttpMessage_Uri_ce == NULL + )) { + return FAILURE; + } + + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Factory", request_functions); + + HttpMessage_Factory_ce = zend_register_internal_class(&ce); + zend_class_implements(HttpMessage_Factory_ce, 6, request_factory, response_factory, serverrequest_factory, + stream_factory, uploadedfile_factory, uri_factory); + + return SUCCESS; +} + +#endif diff --git a/macros.h b/macros.h index 5ce9280..ddee3b3 100644 --- a/macros.h +++ b/macros.h @@ -54,8 +54,23 @@ ZEND_END_ARG_INFO() #define SET_URI_PROPERTY(className, property, val) SET_STR_PROPERTY(className, property, val) #endif +#define HTTP_MESSAGE_ME_EX(className, interfaceName, method) \ + PHP_ME(className, method, arginfo_PsrHttpMessage ## interfaceName ## Interface_ ## method, ZEND_ACC_PUBLIC) + #define HTTP_MESSAGE_ME(className, method) \ - PHP_ME(className, method, arginfo_PsrHttpMessage ## className ## Interface_ ## method, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME_EX(className, className, method) + +#define NEW_OBJECT(zval, ce) \ + object_init_ex(zval, ce); \ + if (EXPECTED(zval != NULL)) object_properties_init(Z_OBJ_P(zval), ce) + +#define NEW_OBJECT_CONSTRUCT_0(zval, ce) \ + NEW_OBJECT(zval, ce); \ + if (EXPECTED(zval != NULL)) zend_call_method_with_0_params(zval, ce, &ce->constructor, "__construct", NULL) + +#define NEW_OBJECT_CONSTRUCT_1(zval, ce, arg) \ + NEW_OBJECT(zval, ce); \ + if (EXPECTED(zval != NULL)) zend_call_method_with_1_params(zval, ce, &ce->constructor, "__construct", NULL, arg) #define IS_STREAM_RESOURCE(zstream) \ ( \ @@ -99,12 +114,60 @@ static zend_always_inline zend_class_entry* get_internal_ce(const char *class_na return temp_ce; } -#define RETURN_HTTP_MESSAGE_INTERFACE_NOT_FOUND(className) \ - { \ +#define ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(ce, className, psrClassName) \ + if (UNEXPECTED(ce == NULL)) { \ zend_error(E_CORE_WARNING, \ "Failed to initialize 'HttpMessage\\%s': 'Psr\\Http\\Message\\%sInterace' not found", \ - className, className); \ + className, psrClassName); \ return FAILURE; \ } +#define ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(ce, className) \ + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(ce, className, className) + +// Parameter as zval, but with type checking + +#define Z_PARAM_ZVAL_STRING_EX(dest, check_null, separate) \ + Z_PARAM_PROLOGUE(separate, separate); \ + if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_STRING, &dest, check_null))) { \ + _expected_type = Z_EXPECTED_STRING; \ + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_ZVAL_STRING(dest) \ + Z_PARAM_ZVAL_STRING_EX(dest, 0, 0) + +#define Z_PARAM_ZVAL_LONG_EX(dest, check_null, separate) \ + Z_PARAM_PROLOGUE(separate, separate); \ + if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_LONG, &dest, check_null))) { \ + _expected_type = Z_EXPECTED_LONG; \ + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_ZVAL_LONG(dest) \ + Z_PARAM_ZVAL_LONG_EX(dest, 0, 0) + +#define Z_PARAM_ZVAL_ARRAY_EX(dest, check_null, separate) \ + Z_PARAM_PROLOGUE(separate, separate); \ + if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_ARRAY, &dest, check_null))) { \ + _expected_type = Z_EXPECTED_ARRAY; \ + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_ZVAL_ARRAY(dest) \ + Z_PARAM_ZVAL_ARRAY_EX(dest, 0, 0) + +static zend_always_inline int zend_parse_arg_zval_ceck(zval *arg, u_char type, zval **dest, int check_null) +{ + if (EXPECTED(Z_TYPE_P(arg) == type)) { + *dest = arg; + } else if (check_null && Z_TYPE_P(arg) == IS_NULL) { + *dest = NULL; + } + return 1; +} + #endif //HTTP_MESSAGE_MACROS_H diff --git a/message.c b/message.c index 26b2ca2..0b059ba 100644 --- a/message.c +++ b/message.c @@ -33,13 +33,11 @@ #endif #include "php.h" -#include "php_ini.h" #include "php_http_message.h" #include "macros.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_string.h" -#include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "ext/psr/psr_http_message.h" @@ -54,7 +52,7 @@ void add_header(zval *object, char *name, size_t name_len, zend_string *value, z headers_prop = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv); - if (UNEXPECTED(Z_TYPE_P(headers_prop) != IS_ARRAY && Z_TYPE_P(headers_prop) != IS_ARRAY_EX)) { + if (UNEXPECTED(Z_TYPE_P(headers_prop) != IS_ARRAY)) { return; // Shouldn't happen } @@ -71,7 +69,6 @@ void add_header(zval *object, char *name, size_t name_len, zend_string *value, z add_next_index_str(header_values, value); ZVAL_ARR(headers_prop, headers); - } /* __construct */ @@ -82,12 +79,7 @@ PHP_METHOD(Message, __construct) /* $this->body = new Stream() */ body = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("body"), 0, &rv); - object_init_ex(body, HttpMessage_Stream_ce); - if (body != NULL) { /* Should always be true */ - zend_call_method_with_0_params( - body, HttpMessage_Stream_ce, &HttpMessage_Stream_ce->constructor, "__construct", NULL - ); - } + NEW_OBJECT_CONSTRUCT_0(body, HttpMessage_Stream_ce); INIT_ARRAY_PROPERTY(HttpMessage_Message_ce, "headers", rv); } @@ -302,7 +294,7 @@ PHP_MINIT_FUNCTION(http_message_message) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\messageinterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Message"); INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Message", message_functions); diff --git a/php_http_message.h b/php_http_message.h index 596474f..59dc985 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -62,8 +62,6 @@ extern zend_class_entry *HttpMessage_Response_ce; extern zend_class_entry *HttpMessage_Stream_ce; extern zend_class_entry *HttpMessage_Uri_ce; extern zend_class_entry *HttpMessage_UploadedFile_ce; - -void create_uploaded_files(zval *objects, HashTable *files); -void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass_len); +extern zend_class_entry *HttpMessage_Factory_ce; #endif diff --git a/request.c b/request.c index 55baa9c..fef646c 100644 --- a/request.c +++ b/request.c @@ -63,7 +63,7 @@ PHP_METHOD(Request, __construct) /* $this->uri = new Uri() */ uri = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); - object_init_ex(uri, HttpMessage_Uri_ce); + NEW_OBJECT(uri, HttpMessage_Uri_ce); } @@ -195,7 +195,7 @@ PHP_MINIT_FUNCTION(http_message_request) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestinterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Request"); if (HttpMessage_Message_ce == NULL) return FAILURE; INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Request", request_functions); diff --git a/response.c b/response.c index ef27ee9..e69b88c 100644 --- a/response.c +++ b/response.c @@ -138,7 +138,7 @@ PHP_MINIT_FUNCTION(http_message_response) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\responseinterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Response"); if (HttpMessage_Message_ce == NULL) return FAILURE; INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Response", response_functions); diff --git a/server_request.c b/server_request.c index 698505d..7c4728f 100644 --- a/server_request.c +++ b/server_request.c @@ -34,12 +34,11 @@ #include #include "php.h" -#include "php_ini.h" #include "php_http_message.h" #include "macros.h" +#include "uploaded_file.h" #include "zend_exceptions.h" #include "zend_interfaces.h" -#include "ext/standard/info.h" #include "ext/psr/psr_http_message.h" #if HAVE_HTTP_MESSAGE @@ -52,7 +51,7 @@ int assert_uploaded_files(HashTable *array) zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); if (interface == NULL) { - zend_throw_error(NULL, "Psr\\Http\\Message\\UploadedFileInterface not foud"); + zend_throw_error(NULL, "Psr\\Http\\Message\\UploadedFileInterface not found"); return FAILURE; } @@ -460,7 +459,7 @@ PHP_MINIT_FUNCTION(http_message_serverrequest) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\serverrequestinterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "ServerRequest"); if (HttpMessage_Request_ce == NULL) return FAILURE; INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "ServerRequest", request_functions); diff --git a/stream.c b/stream.c index ae21bc9..ef1d3d7 100644 --- a/stream.c +++ b/stream.c @@ -418,7 +418,6 @@ PHP_METHOD(Stream, getMetadata) } ZVAL_STRING(&fname, "stream_get_meta_data"); - call_user_function(NULL, NULL, &fname, return_value, 1, zstream); if (key != NULL) { @@ -436,23 +435,23 @@ PHP_METHOD(Stream, getMetadata) /* Define HttpMessage\Stream class */ static const zend_function_entry stream_functions[] = { - PHP_ME(Stream, __construct, arginfo_HttpMessageStream_construct, ZEND_ACC_PUBLIC) - HTTP_MESSAGE_ME(Stream, __toString) - HTTP_MESSAGE_ME(Stream, close) - HTTP_MESSAGE_ME(Stream, detach) - HTTP_MESSAGE_ME(Stream, getSize) - HTTP_MESSAGE_ME(Stream, tell) - HTTP_MESSAGE_ME(Stream, eof) - HTTP_MESSAGE_ME(Stream, isSeekable) - HTTP_MESSAGE_ME(Stream, seek) - HTTP_MESSAGE_ME(Stream, rewind) - HTTP_MESSAGE_ME(Stream, isWritable) - HTTP_MESSAGE_ME(Stream, write) - HTTP_MESSAGE_ME(Stream, isReadable) - HTTP_MESSAGE_ME(Stream, read) - HTTP_MESSAGE_ME(Stream, getContents) - HTTP_MESSAGE_ME(Stream, getMetadata) - PHP_FE_END + PHP_ME(Stream, __construct, arginfo_HttpMessageStream_construct, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME(Stream, __toString) + HTTP_MESSAGE_ME(Stream, close) + HTTP_MESSAGE_ME(Stream, detach) + HTTP_MESSAGE_ME(Stream, getSize) + HTTP_MESSAGE_ME(Stream, tell) + HTTP_MESSAGE_ME(Stream, eof) + HTTP_MESSAGE_ME(Stream, isSeekable) + HTTP_MESSAGE_ME(Stream, seek) + HTTP_MESSAGE_ME(Stream, rewind) + HTTP_MESSAGE_ME(Stream, isWritable) + HTTP_MESSAGE_ME(Stream, write) + HTTP_MESSAGE_ME(Stream, isReadable) + HTTP_MESSAGE_ME(Stream, read) + HTTP_MESSAGE_ME(Stream, getContents) + HTTP_MESSAGE_ME(Stream, getMetadata) + PHP_FE_END }; PHP_MINIT_FUNCTION(http_message_stream) @@ -460,7 +459,7 @@ PHP_MINIT_FUNCTION(http_message_stream) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Stream"); INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Stream", stream_functions); diff --git a/uploaded_file.c b/uploaded_file.c index 50317ac..74471f3 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -33,13 +33,11 @@ #endif #include "php.h" -#include "php_ini.h" #include "php_http_message.h" #include "macros.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "SAPI.h" -#include "ext/standard/info.h" #include "ext/standard/file.h" #include "ext/psr/psr_http_message.h" #include "ext/spl/spl_exceptions.h" @@ -125,6 +123,7 @@ int move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_p void construct_uploaded_file( zval* object, + zval *stream, zend_string *file, zend_long size, zend_long error, @@ -132,9 +131,22 @@ void construct_uploaded_file( zend_string *clientMediaType, char checkUploaded ) { + zval zfile, zarg1; + + if (error == 0 && stream != NULL) { + // Must be verified it's a StreamInterface object before passing it to this function. + zend_update_property(HttpMessage_UploadedFile_ce, object, ZEND_STRL("stream"), stream); + + if (file == NULL) { + ZVAL_STRINGL(&zarg1, "uri", 3); + zend_call_method_with_1_params(stream, NULL, NULL, "getMetadata", &zfile, &zarg1); + file = Z_STR_P(&zfile); + } + } if (error == 0 && file != NULL) { zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("file"), file); } + if (clientFilename != NULL) { zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientFilename"), clientFilename); } @@ -166,6 +178,7 @@ void create_uploaded_file(zval *uploaded_file, zval *tmp_name, zval *size, zval ZVAL_OBJ(uploaded_file, new_object); construct_uploaded_file( + NULL, uploaded_file, tmp_name != NULL ? Z_STR_P(tmp_name) : NULL, size != NULL ? Z_LVAL_P(size) : -1, @@ -201,7 +214,7 @@ void restructure_uploaded_files( } else if (EXPECTED(Z_TYPE_P(error) == IS_ARRAY)) { array_init(element); restructure_uploaded_files(element, Z_ARR_P_NULL(name), Z_ARR_P_NULL(type), Z_ARR_P_NULL(tmp_name), - Z_ARR_P_NULL(error), Z_ARR_P_NULL(size)); // recursion + Z_ARR_P_NULL(error), Z_ARR_P_NULL(size)); // recursion } } ZEND_HASH_FOREACH_END(); } @@ -234,8 +247,8 @@ void create_uploaded_files(zval *objects, HashTable *files) create_uploaded_file(element, tmp_name, size, error, name, type); } else if (EXPECTED(Z_TYPE_P(error) == IS_ARRAY)) { array_init(element); - restructure_uploaded_files(element, Z_ARR_P(name), Z_ARR_P(type), Z_ARR_P(tmp_name), Z_ARR_P(error) - , Z_ARR_P(size)); + restructure_uploaded_files(element, Z_ARR_P(name), Z_ARR_P(type), Z_ARR_P(tmp_name), Z_ARR_P(error), + Z_ARR_P(size)); } } ZEND_HASH_FOREACH_END(); } @@ -243,8 +256,8 @@ void create_uploaded_files(zval *objects, HashTable *files) /* __construct */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 1, 0) - ZEND_ARG_TYPE_INFO(0, file, IS_STRING, 1) +ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageUploadedFile_construct, 0, 0, 1) + ZEND_ARG_INFO(0, fileOrStream) ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 1) ZEND_ARG_TYPE_INFO(0, error, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, clientFilename, IS_STRING, 1) @@ -254,12 +267,14 @@ ZEND_END_ARG_INFO() PHP_METHOD(UploadedFile, __construct) { + zval *fileOrStream = NULL, *stream = NULL; zend_string *file = NULL, *clientFilename = NULL, *clientMediaType = NULL; zend_long size = -1, error = 0; zend_bool size_is_null = 1, checkUploaded = 0, checkUploaded_is_null = 1; + zend_class_entry *stream_interface; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 6) - Z_PARAM_STR_EX(file, 1, 0) + Z_PARAM_ZVAL(fileOrStream) Z_PARAM_OPTIONAL Z_PARAM_LONG_EX(size, size_is_null, 1, 0) Z_PARAM_LONG(error) @@ -268,7 +283,23 @@ PHP_METHOD(UploadedFile, __construct) Z_PARAM_BOOL_EX(checkUploaded, checkUploaded_is_null, 1, 0) ZEND_PARSE_PARAMETERS_END(); - construct_uploaded_file(getThis(), file, size_is_null ? -1 : size, error, clientFilename, clientMediaType, + if (Z_TYPE_P(fileOrStream) == IS_STRING) { + file = Z_STR_P(fileOrStream); + } else { + stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + + if (UNEXPECTED( + Z_TYPE_P(fileOrStream) == IS_OBJECT && instanceof_function(Z_OBJ_P(fileOrStream), stream_interface) + )) { + zend_type_error("Expected parameter 1 to be a string or object that implements " + "Psr\\Http\\Message\\StreamInterface, %s given", zend_zval_type_name(fileOrStream)); + return; + } + + stream = fileOrStream; + } + + construct_uploaded_file(getThis(), stream, file, size_is_null ? -1 : size, error, clientFilename, clientMediaType, checkUploaded_is_null ? -1 : checkUploaded); } @@ -295,13 +326,7 @@ PHP_METHOD(UploadedFile, getStream) } php_stream_to_zval(resource_stream, &resource); - - object_init_ex(stream, HttpMessage_Stream_ce); - if (stream != NULL) { /* Should always be true */ - zend_call_method_with_1_params( - stream, HttpMessage_Stream_ce, &HttpMessage_Stream_ce->constructor, "__construct", NULL, &resource - ); - } + NEW_OBJECT_CONSTRUCT_1(stream, HttpMessage_Stream_ce, &resource); } RETURN_ZVAL(stream, 1, 0); @@ -387,7 +412,7 @@ PHP_MINIT_FUNCTION(http_message_uploadedfile) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); - if (interface == NULL) return FAILURE; + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "UploadedFile"); INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "UploadedFile", methods); diff --git a/uploaded_file.h b/uploaded_file.h new file mode 100644 index 0000000..5d76f38 --- /dev/null +++ b/uploaded_file.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifndef HTTP_MESSAGE_UPLOADED_FILE_H +#define HTTP_MESSAGE_UPLOADED_FILE_H + +void construct_uploaded_file( + zval* object, + zval *stream, + zend_string *file, + zend_long size, + zend_long error, + zend_string *clientFilename, + zend_string *clientMediaType, + char checkUploaded +); +void create_uploaded_files(zval *objects, HashTable *files); +void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass_len); + +#endif //HTTP_MESSAGE_UPLOADED_FILE_H diff --git a/uri.c b/uri.c index 509ba5f..b3be010 100644 --- a/uri.c +++ b/uri.c @@ -437,7 +437,7 @@ PHP_MINIT_FUNCTION(http_message_uri) zend_class_entry ce; zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uriinterface")); - if (interface == NULL) RETURN_HTTP_MESSAGE_INTERFACE_NOT_FOUND("Uri"); + ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Uri"); INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Uri", uri_functions); From 2683f48ae4869811be49f8cf6557846ce8f11a06 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 14 Aug 2019 02:20:12 +0200 Subject: [PATCH 43/67] Added smoke test. Made sure code passes smoke test. Copied make scripts from skeleton (works better on clion). Removed unused includes --- .gitignore | 1 + CMakeLists.txt | 10 ++++++---- autoconf/php-executable.m4 | 7 +++++++ config.m4 | 4 ++-- config.w32 | 3 +-- factory.c | 2 +- http_message.c | 1 + php_http_message.h | 1 + request.c | 2 -- response.c | 2 -- stream.c | 4 ---- tests/smoke.php | 15 +++++++++++++++ uploaded_file.c | 4 ++-- uri.c | 3 --- 14 files changed, 37 insertions(+), 22 deletions(-) create mode 100644 autoconf/php-executable.m4 create mode 100644 tests/smoke.php diff --git a/.gitignore b/.gitignore index eb960ca..8448412 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ modules/ *.lo tests/**/*.* !tests/**/*.phpt +!tests/smoke.php php_test_results_*.txt http_message.loT *.loT diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ac1c04..a5b8b47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,6 @@ project(http_message C) add_compile_definitions(HAVE_HTTP_MESSAGE) -add_custom_target(extension COMMAND phpize && ./configure && make && make install - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - set(SOURCE_FILES php_http_message http_message.c message.c request.c uri.c server_request.c response.c stream.c uploaded_file.c factory.c) @@ -23,4 +20,9 @@ include_directories(${PHP_SOURCE}/Zend) include_directories(${PHP_SOURCE}/TSRM) include_directories(${PROJECT_SOURCE_DIR}) -add_executable(http_message ${SOURCE_FILES}) +add_custom_target(configure + COMMAND phpize && ./configure + DEPENDS ${SOURCE_FILES} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + +add_library(___ EXCLUDE_FROM_ALL ${SOURCE_FILES}) diff --git a/autoconf/php-executable.m4 b/autoconf/php-executable.m4 new file mode 100644 index 0000000..2e6e16e --- /dev/null +++ b/autoconf/php-executable.m4 @@ -0,0 +1,7 @@ +dnl +dnl Generate run-php bash script +dnl +AC_CONFIG_COMMANDS_POST([ + rm -f build/php + ln -s "$PHP_EXECUTABLE" build/php +]) diff --git a/config.m4 b/config.m4 index 4da5251..35a20df 100644 --- a/config.m4 +++ b/config.m4 @@ -2,6 +2,7 @@ dnl $Id$ dnl config.m4 for extension http_message sinclude(./autoconf/pecl.m4) +sinclude(./autoconf/php-executable.m4) PECL_INIT([http_message]) @@ -11,8 +12,7 @@ if test "$PHP_HTTP_MESSAGE" != "no"; then PECL_HAVE_PHP_EXT([psr], [PECL_HAVE_PHP_EXT_HEADER([psr])], [AC_MSG_ERROR([please install and enable the psr extension])]) AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message]) - PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c, - $ext_shared) + PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c, $ext_shared) PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/http_message], [php_http_message.h]) diff --git a/config.w32 b/config.w32 index ba5eed5..b941d1d 100644 --- a/config.w32 +++ b/config.w32 @@ -4,8 +4,7 @@ ARG_ENABLE("http-message", "enable http_message", "no"); if (PHP_HTTP_MESSAGE != "no") { - EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c"); + EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c"); AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'enable http_message support'); PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } - diff --git a/factory.c b/factory.c index c2cc385..08b5555 100644 --- a/factory.c +++ b/factory.c @@ -190,7 +190,7 @@ static const zend_function_entry request_functions[] = { PHP_FE_END }; -PHP_MINIT_FUNCTION(http_message_serverrequest) +PHP_MINIT_FUNCTION(http_message_factory) { zend_class_entry ce; zend_class_entry *request_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestfactoryinterface")); diff --git a/http_message.c b/http_message.c index 7b1ede1..403c13b 100644 --- a/http_message.c +++ b/http_message.c @@ -70,6 +70,7 @@ PHP_MINIT_FUNCTION(http_message) PHP_MINIT(http_message_stream)(INIT_FUNC_ARGS_PASSTHRU) + PHP_MINIT(http_message_uri)(INIT_FUNC_ARGS_PASSTHRU) + PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(http_message_factory)(INIT_FUNC_ARGS_PASSTHRU); return ZEND_NORMALIZE_BOOL(success); } diff --git a/php_http_message.h b/php_http_message.h index 59dc985..ce10a6b 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -52,6 +52,7 @@ extern PHP_MINIT_FUNCTION(http_message_response); extern PHP_MINIT_FUNCTION(http_message_stream); extern PHP_MINIT_FUNCTION(http_message_uri); extern PHP_MINIT_FUNCTION(http_message_uploadedfile); +extern PHP_MINIT_FUNCTION(http_message_factory); extern zend_module_entry http_message_module_entry; diff --git a/request.c b/request.c index fef646c..4163b35 100644 --- a/request.c +++ b/request.c @@ -33,13 +33,11 @@ #endif #include "php.h" -#include "php_ini.h" #include "php_http_message.h" #include "macros.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_smart_str.h" -#include "ext/standard/info.h" #include "ext/psr/psr_http_message.h" #if HAVE_HTTP_MESSAGE diff --git a/response.c b/response.c index e69b88c..a152b67 100644 --- a/response.c +++ b/response.c @@ -33,13 +33,11 @@ #endif #include "php.h" -#include "php_ini.h" #include "php_http_message.h" #include "macros.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "http_status_codes.h" -#include "ext/standard/info.h" #include "ext/psr/psr_http_message.h" #if HAVE_HTTP_MESSAGE diff --git a/stream.c b/stream.c index ef1d3d7..832253d 100644 --- a/stream.c +++ b/stream.c @@ -33,14 +33,10 @@ #endif #include "php.h" -#include "php_ini.h" -#include "php_http_message.h" #include "macros.h" #include "php_streams.h" #include "zend_exceptions.h" #include "zend_interfaces.h" -#include "http_status_codes.h" -#include "ext/standard/info.h" #include "ext/psr/psr_http_message.h" #include "ext/spl/spl_exceptions.h" diff --git a/tests/smoke.php b/tests/smoke.php new file mode 100644 index 0000000..14947c0 --- /dev/null +++ b/tests/smoke.php @@ -0,0 +1,15 @@ + Date: Mon, 2 Sep 2019 22:23:17 +0200 Subject: [PATCH 44/67] Basic tests for Factory. Fixes for Factory. All properties private. Allow filename and mode for Stream constructor. Allow StreamInterface object for UploadedFile constructor. Move uploaded file copies a stream if stream is supplied. Lot's of minor fixes and clean ups. --- Makefile.frag | 2 +- factory.c | 160 +++++++----- macros.h | 62 +---- message.c | 82 +++--- request.c | 27 +- response.c | 82 +++--- response.h | 62 +++++ server_request.c | 55 ++--- stream.c | 233 +++++++++--------- stream.h | 68 +++++ tests/Factory/createRequest_001.phpt | 44 ++++ tests/Factory/createRequest_002.phpt | 48 ++++ tests/Factory/createResponse_001.phpt | 27 ++ tests/Factory/createResponse_002.phpt | 36 +++ tests/Factory/createResponse_003.phpt | 27 ++ tests/Factory/createServerRequest_001.phpt | 80 ++++++ tests/Factory/createServerRequest_002.phpt | 84 +++++++ tests/Factory/createServerRequest_003.phpt | 150 +++++++++++ tests/Factory/createStreamFromFile_001.phpt | 43 ++++ tests/Factory/createStreamFromFile_002.phpt | 43 ++++ tests/Factory/createStreamFromFile_003.phpt | 38 +++ .../Factory/createStreamFromResource_001.phpt | 18 ++ tests/Factory/createStream_001.phpt | 36 +++ tests/Factory/createStream_002.phpt | 36 +++ tests/Factory/createUploadedFile_001.phpt | 50 ++++ tests/Factory/createUploadedFile_002.phpt | 50 ++++ tests/Factory/createUploadedFile_003.phpt | 43 ++++ tests/Request/__construct_001.phpt | 34 +-- tests/Response/__construct_001.phpt | 18 +- tests/ServerRequest/__construct_001.phpt | 46 ++-- tests/ServerRequest/__construct_002.phpt | 70 +++--- tests/ServerRequest/__construct_003.phpt | 174 ++++++------- tests/ServerRequest/__construct_004.phpt | 20 +- tests/ServerRequest/parsedBody_001.phpt | 4 +- tests/Stream/__construct_001.phpt | 29 ++- tests/Stream/__construct_002.phpt | 29 +-- tests/Stream/__construct_003.phpt | 35 +++ tests/Stream/__construct_004.phpt | 35 +++ tests/Stream/__construct_err01.phpt | 2 +- tests/Stream/__construct_err02.phpt | 12 + tests/Stream/close_001.phpt | 10 +- tests/Stream/close_002.phpt | 8 +- tests/Stream/detach_001.phpt | 8 +- tests/Stream/getMetadata_003.phpt | 30 +++ tests/UploadedFile/__construct_001.phpt | 18 +- tests/UploadedFile/__construct_002.phpt | 18 +- tests/UploadedFile/__construct_003.phpt | 22 +- tests/UploadedFile/__construct_004.phpt | 22 +- tests/UploadedFile/__construct_005.phpt | 48 ++++ tests/UploadedFile/getStream_001.phpt | 4 +- tests/UploadedFile/getStream_002.phpt | 4 +- tests/UploadedFile/moveTo_001.phpt | 8 +- tests/UploadedFile/moveTo_002.phpt | 5 +- tests/UploadedFile/moveTo_003.phpt | 22 ++ tests/Uri/__construct_001.phpt | 20 +- tests/Uri/__construct_002.phpt | 20 +- tests/Uri/__construct_003.phpt | 20 +- tests/Uri/__construct_004.phpt | 20 +- tests/Uri/__construct_005.phpt | 20 +- tests/Uri/__construct_006.phpt | 18 +- tests/Uri/__construct_007.phpt | 18 +- tests/Uri/__construct_008.phpt | 20 +- uploaded_file.c | 133 ++++++---- uri.c | 72 +++--- 64 files changed, 1992 insertions(+), 790 deletions(-) create mode 100644 response.h create mode 100644 stream.h create mode 100644 tests/Factory/createRequest_001.phpt create mode 100644 tests/Factory/createRequest_002.phpt create mode 100644 tests/Factory/createResponse_001.phpt create mode 100644 tests/Factory/createResponse_002.phpt create mode 100644 tests/Factory/createResponse_003.phpt create mode 100644 tests/Factory/createServerRequest_001.phpt create mode 100644 tests/Factory/createServerRequest_002.phpt create mode 100644 tests/Factory/createServerRequest_003.phpt create mode 100644 tests/Factory/createStreamFromFile_001.phpt create mode 100644 tests/Factory/createStreamFromFile_002.phpt create mode 100644 tests/Factory/createStreamFromFile_003.phpt create mode 100644 tests/Factory/createStreamFromResource_001.phpt create mode 100644 tests/Factory/createStream_001.phpt create mode 100644 tests/Factory/createStream_002.phpt create mode 100644 tests/Factory/createUploadedFile_001.phpt create mode 100644 tests/Factory/createUploadedFile_002.phpt create mode 100644 tests/Factory/createUploadedFile_003.phpt create mode 100644 tests/Stream/__construct_003.phpt create mode 100644 tests/Stream/__construct_004.phpt create mode 100644 tests/Stream/__construct_err02.phpt create mode 100644 tests/Stream/getMetadata_003.phpt create mode 100644 tests/UploadedFile/__construct_005.phpt create mode 100644 tests/UploadedFile/moveTo_003.phpt diff --git a/Makefile.frag b/Makefile.frag index 5d94d43..d2bf0cc 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -12,7 +12,7 @@ PHP_TEST_SHARED_EXTENSIONS = ` \ fi` clean-tests: - rm -f tests/*.diff tests/*.exp tests/*.log tests/*.out tests/*.php tests/*.sh + rm -f tests/*/*.diff tests/*/*.exp tests/*/*.log tests/*/*.out tests/*/*.php tests/*/*.sh mrproper: clean rm -rf autom4te.cache build modules vendor diff --git a/factory.c b/factory.c index 08b5555..21d7445 100644 --- a/factory.c +++ b/factory.c @@ -35,111 +35,153 @@ #include "php.h" #include "php_http_message.h" #include "macros.h" +#include "response.h" +#include "stream.h" #include "uploaded_file.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_string.h" -#include "ext/standard/php_string.h" -#include "ext/psr/psr_http_message.h" #include "ext/psr/psr_http_factory.h" #if HAVE_HTTP_MESSAGE zend_class_entry *HttpMessage_Factory_ce = NULL; +int uri_param_as_object(zval *uri) +{ + zval uri_str; + zend_class_entry *uri_interface = HTTP_MESSAGE_PSR_INTERFACE("uri"); + + if (uri_interface == NULL) { + zend_throw_error(NULL, "Psr\\Http\\Message\\UriInterface not found"); + return FAILURE; + } + + if (Z_TYPE_P(uri) == IS_STRING) { + ZVAL_COPY(&uri_str, uri); + NEW_OBJECT_CONSTRUCT(uri, HttpMessage_Uri_ce, 1, &uri_str); + } else if (UNEXPECTED(Z_TYPE_P(uri) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(uri), uri_interface))) { + zend_type_error("Expected parameter 1 to be a string or object that implements " + "Psr\\Http\\Message\\UriInterface, %s given", zend_zval_type_name(uri)); + return FAILURE; + } + + return SUCCESS; +} + PHP_METHOD(Factory, createRequest) { - zval *method, *uri; + zend_string *method = NULL; + zval *uri = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) - Z_PARAM_ZVAL_STRING(method) + Z_PARAM_STR(method) Z_PARAM_ZVAL(uri) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Request_ce); - zend_call_method_with_1_params(return_value, HttpMessage_Request_ce, NULL, "withMethod", return_value, method); - zend_call_method_with_1_params(return_value, HttpMessage_Request_ce, NULL, "withUri", return_value, uri); + if (uri_param_as_object(uri) == FAILURE) return; + + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 0); + zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("method"), method); + zend_update_property(HttpMessage_Request_ce, return_value, ZEND_STRL("uri"), uri); } PHP_METHOD(Factory, createResponse) { - zval *code = NULL, *reasonPhrase = NULL; + zend_long code = 200; + zend_bool code_is_null = 0; + zend_string *phrase = NULL; + const char *suggested_phrase; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 2) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_LONG(code) - Z_PARAM_ZVAL_STRING(reasonPhrase) + Z_PARAM_LONG_EX(code, code_is_null, 0, 0) + Z_PARAM_STR(phrase) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Response_ce); - - if (code != NULL) { - zend_call_method_with_2_params(return_value, HttpMessage_Response_ce, NULL, "withStatus", return_value, code, - reasonPhrase); - } + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Response_ce, 0); + response_set_status(return_value, !code_is_null ? code : 200, phrase); } PHP_METHOD(Factory, createServerRequest) { - zval *method, *uri, *serverParams = NULL; + zend_string *method = NULL; + zval *uri = NULL, *serverParams = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 3) - Z_PARAM_ZVAL_STRING(method) + Z_PARAM_STR(method) Z_PARAM_ZVAL(uri) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_ARRAY_EX(serverParams, 1, 0) + Z_PARAM_ARRAY_EX(serverParams, 1, 0) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_ServerRequest_ce, serverParams); - zend_call_method_with_1_params(return_value, HttpMessage_ServerRequest_ce, NULL, "withMethod", return_value, - method); - zend_call_method_with_1_params(return_value, HttpMessage_ServerRequest_ce, NULL, "withUri", return_value, uri); + if (uri_param_as_object(uri) == FAILURE) return; + + if (serverParams == NULL) { + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_ServerRequest_ce, 0); + } else { + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_ServerRequest_ce, 1, serverParams); + } + + zend_update_property_str(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("method"), method); + zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("uri"), uri); } PHP_METHOD(Factory, createStream) { - zval *content; + php_stream *stream; + zval resource; + zend_string *content = NULL; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_ZVAL_STRING(content) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(content) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_0(return_value, HttpMessage_Stream_ce); - zend_call_method_with_1_params(return_value, HttpMessage_Stream_ce, NULL, "write", NULL, content); + if (open_temp_stream(&resource) == FAILURE) return; + + if (content != NULL && ZSTR_LEN(content) > 0) { + php_stream_from_zval(stream, &resource); + php_stream_write(stream, ZSTR_VAL(content), ZSTR_LEN(content)); + } + + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Stream_ce, 1, &resource); } PHP_METHOD(Factory, createStreamFromFile) { - char *file; - size_t file_len; + char *file = NULL, *mode = NULL; + size_t file_len = 0, mode_len = 0; php_stream *stream; zval resource; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_STRING(file, file_len) + Z_PARAM_OPTIONAL + Z_PARAM_STRING(mode, mode_len) ZEND_PARSE_PARAMETERS_END(); file[file_len] = '\0'; - stream = php_stream_open_wrapper(file, "r+", 0, NULL); + stream = php_stream_open_wrapper(file, mode != NULL ? mode : "r", 0, NULL); if (stream == NULL) { - zend_throw_error(NULL, "Failed to open 'php://temp' stream"); + zend_throw_error(NULL, "Failed to open '%s' stream", file); return; } php_stream_to_zval(stream, &resource); - NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Stream_ce, &resource); + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Stream_ce, 1, &resource); } PHP_METHOD(Factory, createStreamFromResource) { - zval *resource; + zval *resource = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_ZVAL(resource) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Stream_ce, resource); + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Stream_ce, 1, resource); } PHP_METHOD(Factory, createUploadedFile) @@ -148,7 +190,7 @@ PHP_METHOD(Factory, createUploadedFile) zend_long size = -1, error = 0; zend_string *clientFilename = NULL, *clientMediaType = NULL; zend_bool size_is_null = 1; - zend_class_entry *stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + zend_class_entry *stream_interface = HTTP_MESSAGE_PSR_INTERFACE("stream"); ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 5) Z_PARAM_OBJECT_OF_CLASS(stream, stream_interface) @@ -166,41 +208,45 @@ PHP_METHOD(Factory, createUploadedFile) PHP_METHOD(Factory, createUri) { - zval *uri = NULL; + zend_string *uri = NULL; + zval zuri; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 0) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_STRING_EX(uri, 1, 0) + Z_PARAM_STR_EX(uri, 1, 0) ZEND_PARSE_PARAMETERS_END(); - NEW_OBJECT_CONSTRUCT_1(return_value, HttpMessage_Request_ce, uri); + if (uri == NULL) { + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 0); + } else { + ZVAL_STR(&zuri, uri); + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 1, &zuri); + } } /* Define HttpMessage\Factory class */ static const zend_function_entry request_functions[] = { - HTTP_MESSAGE_ME_EX(Factory, RequestFactory, createRequest) - HTTP_MESSAGE_ME_EX(Factory, ResponseFactory, createResponse) - HTTP_MESSAGE_ME_EX(Factory, ServerRequestFactory, createServerRequest) - HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStream) - HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromFile) - HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromResource) - HTTP_MESSAGE_ME_EX(Factory, UploadedFileFactory, createUploadedFile) - HTTP_MESSAGE_ME_EX(Factory, UriFactory, createUri) - PHP_FE_END + HTTP_MESSAGE_ME_EX(Factory, RequestFactory, createRequest) + HTTP_MESSAGE_ME_EX(Factory, ResponseFactory, createResponse) + HTTP_MESSAGE_ME_EX(Factory, ServerRequestFactory, createServerRequest) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStream) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromFile) + HTTP_MESSAGE_ME_EX(Factory, StreamFactory, createStreamFromResource) + HTTP_MESSAGE_ME_EX(Factory, UploadedFileFactory, createUploadedFile) + HTTP_MESSAGE_ME_EX(Factory, UriFactory, createUri) + PHP_FE_END }; PHP_MINIT_FUNCTION(http_message_factory) { zend_class_entry ce; - zend_class_entry *request_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestfactoryinterface")); - zend_class_entry *response_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\responsefactoryinterface")); - zend_class_entry *serverrequest_factory - = get_internal_ce(ZEND_STRL("psr\\http\\message\\serverrequestfactoryinterface")); - zend_class_entry *stream_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\streamfactoryinterface")); - zend_class_entry *uploadedfile_factory - = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfilefactoryinterface")); - zend_class_entry *uri_factory = get_internal_ce(ZEND_STRL("psr\\http\\message\\urifactoryinterface")); + zend_class_entry *request_factory = HTTP_MESSAGE_PSR_INTERFACE("requestfactory"); + zend_class_entry *response_factory = HTTP_MESSAGE_PSR_INTERFACE("responsefactory"); + zend_class_entry *serverrequest_factory = HTTP_MESSAGE_PSR_INTERFACE("serverrequestfactory"); + zend_class_entry *stream_factory = HTTP_MESSAGE_PSR_INTERFACE("streamfactory"); + zend_class_entry *uploadedfile_factory = HTTP_MESSAGE_PSR_INTERFACE("uploadedfilefactory"); + zend_class_entry *uri_factory = HTTP_MESSAGE_PSR_INTERFACE("urifactory"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(request_factory, "Factory", "RequestFactory"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(response_factory, "Factory", "ResponseFactory"); diff --git a/macros.h b/macros.h index ddee3b3..8989ee6 100644 --- a/macros.h +++ b/macros.h @@ -1,6 +1,7 @@ /* +----------------------------------------------------------------------+ | HTTP Message PHP extension | + | Generic macros for this library | +----------------------------------------------------------------------+ | Copyright (c) 2019 Arnold Daniels | +----------------------------------------------------------------------+ @@ -60,17 +61,19 @@ ZEND_END_ARG_INFO() #define HTTP_MESSAGE_ME(className, method) \ HTTP_MESSAGE_ME_EX(className, className, method) +#define HTTP_MESSAGE_PSR_INTERFACE(interfaceName) \ + get_internal_ce(ZEND_STRL("psr\\http\\message\\" interfaceName "interface")) + #define NEW_OBJECT(zval, ce) \ object_init_ex(zval, ce); \ if (EXPECTED(zval != NULL)) object_properties_init(Z_OBJ_P(zval), ce) -#define NEW_OBJECT_CONSTRUCT_0(zval, ce) \ - NEW_OBJECT(zval, ce); \ - if (EXPECTED(zval != NULL)) zend_call_method_with_0_params(zval, ce, &ce->constructor, "__construct", NULL) - -#define NEW_OBJECT_CONSTRUCT_1(zval, ce, arg) \ +#define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ NEW_OBJECT(zval, ce); \ - if (EXPECTED(zval != NULL)) zend_call_method_with_1_params(zval, ce, &ce->constructor, "__construct", NULL, arg) + if (EXPECTED(zval != NULL)) \ + zend_call_method_with_## argc ##_params( \ + zval, ce, &ce->constructor, "__construct", NULL, ##__VA_ARGS__ \ + ) #define IS_STREAM_RESOURCE(zstream) \ ( \ @@ -103,6 +106,8 @@ ZEND_END_ARG_INFO() #define STRLEN_NULL(str) str != NULL ? strlen(str) : 0 +#define STR_CLOSE(str, len) str[len] = '\0' // Is buffer big enough? yolo! + static zend_always_inline zend_class_entry* get_internal_ce(const char *class_name, size_t class_name_len) { zend_class_entry* temp_ce; @@ -125,49 +130,4 @@ static zend_always_inline zend_class_entry* get_internal_ce(const char *class_na #define ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(ce, className) \ ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(ce, className, className) -// Parameter as zval, but with type checking - -#define Z_PARAM_ZVAL_STRING_EX(dest, check_null, separate) \ - Z_PARAM_PROLOGUE(separate, separate); \ - if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_STRING, &dest, check_null))) { \ - _expected_type = Z_EXPECTED_STRING; \ - error_code = ZPP_ERROR_WRONG_ARG; \ - break; \ - } - -#define Z_PARAM_ZVAL_STRING(dest) \ - Z_PARAM_ZVAL_STRING_EX(dest, 0, 0) - -#define Z_PARAM_ZVAL_LONG_EX(dest, check_null, separate) \ - Z_PARAM_PROLOGUE(separate, separate); \ - if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_LONG, &dest, check_null))) { \ - _expected_type = Z_EXPECTED_LONG; \ - error_code = ZPP_ERROR_WRONG_ARG; \ - break; \ - } - -#define Z_PARAM_ZVAL_LONG(dest) \ - Z_PARAM_ZVAL_LONG_EX(dest, 0, 0) - -#define Z_PARAM_ZVAL_ARRAY_EX(dest, check_null, separate) \ - Z_PARAM_PROLOGUE(separate, separate); \ - if (UNEXPECTED(!zend_parse_arg_zval_ceck(_arg, IS_ARRAY, &dest, check_null))) { \ - _expected_type = Z_EXPECTED_ARRAY; \ - error_code = ZPP_ERROR_WRONG_ARG; \ - break; \ - } - -#define Z_PARAM_ZVAL_ARRAY(dest) \ - Z_PARAM_ZVAL_ARRAY_EX(dest, 0, 0) - -static zend_always_inline int zend_parse_arg_zval_ceck(zval *arg, u_char type, zval **dest, int check_null) -{ - if (EXPECTED(Z_TYPE_P(arg) == type)) { - *dest = arg; - } else if (check_null && Z_TYPE_P(arg) == IS_NULL) { - *dest = NULL; - } - return 1; -} - #endif //HTTP_MESSAGE_MACROS_H diff --git a/message.c b/message.c index 0b059ba..3dcffa0 100644 --- a/message.c +++ b/message.c @@ -45,7 +45,7 @@ zend_class_entry *HttpMessage_Message_ce = NULL; -void add_header(zval *object, char *name, size_t name_len, zend_string *value, zend_bool added) +void add_header(zval *object, zend_string *name, zend_string *value, zend_bool added) { zval rv, *headers_prop, *header_values; HashTable *headers; @@ -58,9 +58,9 @@ void add_header(zval *object, char *name, size_t name_len, zend_string *value, z headers = zend_array_dup(Z_ARR_P(headers_prop)); - header_values = zend_hash_str_find(headers, name, name_len); + header_values = zend_hash_find(headers, name); if (header_values == NULL) { - header_values = zend_hash_str_add_empty_element(headers, name, name_len); + header_values = zend_hash_add_empty_element(headers, name); array_init(header_values); } else if (!added) { ZVAL_DEREF(header_values); @@ -78,8 +78,8 @@ PHP_METHOD(Message, __construct) zval rv, *body; /* $this->body = new Stream() */ - body = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("body"), 0, &rv); - NEW_OBJECT_CONSTRUCT_0(body, HttpMessage_Stream_ce); + body = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + NEW_OBJECT_CONSTRUCT(body, HttpMessage_Stream_ce, 0); INIT_ARRAY_PROPERTY(HttpMessage_Message_ce, "headers", rv); } @@ -98,18 +98,15 @@ PHP_METHOD(Message, getProtocolVersion) PHP_METHOD(Message, withProtocolVersion) { - char *value; - size_t value_len = 0; + zend_string *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl( - HttpMessage_Message_ce, return_value, ZEND_STRL("protocolVersion"), value, value_len - ); + zend_update_property_str(HttpMessage_Message_ce, return_value, ZEND_STRL("protocolVersion"), value); } @@ -127,17 +124,15 @@ PHP_METHOD(Message, getHeaders) PHP_METHOD(Message, hasHeader) { zval rv, *headers; - char *name; - size_t name_len = 0; + zend_string *name; zend_bool exists; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - - exists = zend_hash_str_exists(Z_ARRVAL_P(headers), name, name_len); + exists = zend_hash_exists(Z_ARRVAL_P(headers), name); RETVAL_BOOL(exists); } @@ -145,15 +140,14 @@ PHP_METHOD(Message, hasHeader) PHP_METHOD(Message, getHeader) { zval rv, *headers, *header_values; - char *name; - size_t name_len = 0; + zend_string *name; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - header_values = zend_hash_str_find(Z_ARRVAL_P(headers), name, name_len); + header_values = zend_hash_find(Z_ARRVAL_P(headers), name); if (header_values == NULL) { array_init(return_value); @@ -166,16 +160,14 @@ PHP_METHOD(Message, getHeader) PHP_METHOD(Message, getHeaderLine) { zval rv, *headers, *header_values; - char *name; - size_t name_len = 0; - zend_string *glue; + zend_string *name, *glue; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); - header_values = zend_hash_str_find(Z_ARRVAL_P(headers), name, name_len); + header_values = zend_hash_find(Z_ARRVAL_P(headers), name); if (header_values == NULL) { RETURN_EMPTY_STRING(); @@ -189,44 +181,40 @@ PHP_METHOD(Message, getHeaderLine) PHP_METHOD(Message, withHeader) { - char *name; - size_t name_len = 0; - zend_string *value; + zend_string *name, *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - add_header(return_value, name, name_len, value, 0); + add_header(return_value, name, value, 0); } -PHP_METHOD(Message, withAddedHeader) { - char *name; - size_t name_len = 0; - zend_string *value; +PHP_METHOD(Message, withAddedHeader) +{ + zend_string *name, *value; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) - Z_PARAM_STRING(name, name_len) - Z_PARAM_STR(value) + Z_PARAM_STR(name) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - add_header(return_value, name, name_len, value, 1); + add_header(return_value, name, value, 1); } PHP_METHOD(Message, withoutHeader) { zval rv, *headers_prop; HashTable *headers; - char *name; - size_t name_len = 0; + zend_string *name; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); @@ -234,7 +222,7 @@ PHP_METHOD(Message, withoutHeader) headers_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), 0, &rv); headers = zend_array_dup(Z_ARR_P(headers_prop)); - zend_hash_str_del(headers, name, name_len); + zend_hash_del(headers, name); ZVAL_ARR(headers_prop, headers); } @@ -254,10 +242,10 @@ PHP_METHOD(Message, getBody) PHP_METHOD(Message, withBody) { zval *value; - zend_class_entry *stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + zend_class_entry *stream_interface = HTTP_MESSAGE_PSR_INTERFACE("stream"); if (stream_interface == NULL) { - zend_throw_error(NULL, "Psr\\Http\\Message\\StreamInterface not foud"); + zend_throw_error(NULL, "Psr\\Http\\Message\\StreamInterface not found"); return; } @@ -292,7 +280,7 @@ static const zend_function_entry message_functions[] = { PHP_MINIT_FUNCTION(http_message_message) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\messageinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("message"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Message"); @@ -304,10 +292,10 @@ PHP_MINIT_FUNCTION(http_message_message) /* Properties */ zend_declare_property_string( - HttpMessage_Message_ce, ZEND_STRL("protocolVersion"), "1.1", ZEND_ACC_PROTECTED + HttpMessage_Message_ce, ZEND_STRL("protocolVersion"), "1.1", ZEND_ACC_PRIVATE ); - zend_declare_property_null(HttpMessage_Message_ce, ZEND_STRL("headers"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_Message_ce, ZEND_STRL("body"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_Message_ce, ZEND_STRL("headers"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_Message_ce, ZEND_STRL("body"), ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/request.c b/request.c index 4163b35..2b1cfd8 100644 --- a/request.c +++ b/request.c @@ -108,7 +108,7 @@ PHP_METHOD(Request, withRequestTarget) ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - if (value != NULL) { + if (EXPECTED(value != NULL)) { zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value); } else { zend_update_property_null(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget")); @@ -129,18 +129,17 @@ PHP_METHOD(Request, getMethod) PHP_METHOD(Request, withMethod) { - char *value; - size_t value_len; + int u; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) + u = _i + 5; ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl( - HttpMessage_Request_ce, return_value, ZEND_STRL("method"), value, value_len - ); + zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("method"), value); } @@ -157,11 +156,11 @@ PHP_METHOD(Request, getUri) PHP_METHOD(Request, withUri) { - zval *value; - zend_class_entry *uri_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uriinterface")); + zval *value = NULL; + zend_class_entry *uri_interface = HTTP_MESSAGE_PSR_INTERFACE("uri"); if (uri_interface == NULL) { - zend_throw_error(NULL, "Psr\\Http\\Message\\UriInterface not foud"); + zend_throw_error(NULL, "Psr\\Http\\Message\\UriInterface not found"); return; } @@ -191,7 +190,7 @@ static const zend_function_entry request_functions[] = { PHP_MINIT_FUNCTION(http_message_request) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\requestinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("request"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Request"); if (HttpMessage_Message_ce == NULL) return FAILURE; @@ -202,9 +201,9 @@ PHP_MINIT_FUNCTION(http_message_request) zend_class_implements(HttpMessage_Request_ce, 1, interface); /* Properties */ - zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("requestTarget"), ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Request_ce, ZEND_STRL("method"), "", ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("uri"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("requestTarget"), ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Request_ce, ZEND_STRL("method"), "", ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_Request_ce, ZEND_STRL("uri"), ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/response.c b/response.c index a152b67..150a65f 100644 --- a/response.c +++ b/response.c @@ -33,41 +33,63 @@ #endif #include "php.h" +#include "ext/psr/psr_http_message.h" +#include "ext/spl/spl_exceptions.h" #include "php_http_message.h" #include "macros.h" +#include "response.h" #include "zend_exceptions.h" #include "zend_interfaces.h" -#include "http_status_codes.h" -#include "ext/psr/psr_http_message.h" #if HAVE_HTTP_MESSAGE zend_class_entry *HttpMessage_Response_ce; +int response_set_status(zval *obj, zend_long code, zend_string *phrase) +{ + const char *suggested_phrase; -/* Helper function to get reason phrase from status code */ + if (code < 100 || code > 999) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid HTTP status code %ld", code); + return FAILURE; + } -static int status_comp(const void *a, const void *b) -{ - const http_response_status_code_pair *pa = (const http_response_status_code_pair *) a; - const http_response_status_code_pair *pb = (const http_response_status_code_pair *) b; + zend_update_property_long(HttpMessage_Response_ce, obj, ZEND_STRL("statusCode"), code); - if (pa->code < pb->code) { - return -1; - } else if (pa->code > pb->code) { - return 1; + if (phrase != NULL) { + zend_update_property_str(HttpMessage_Response_ce, obj, ZEND_STRL("reasonPhrase"), phrase); + } else { + suggested_phrase = get_status_string((int)code); + zend_update_property_stringl( + HttpMessage_Response_ce, obj, ZEND_STRL("reasonPhrase"), + suggested_phrase, strlen(suggested_phrase) + ); } - return 0; + return SUCCESS; } -static const char *get_status_string(int code) +/* __construct */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageServerRequest_construct, 0, 0, 0) + ZEND_ARG_TYPE_INFO(0, statusCode, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, reasonPhrase, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(Response, __construct) { - http_response_status_code_pair needle = {code, NULL}, *result = NULL; + zend_long code = 0; + zend_string *phrase = NULL; - result = bsearch(&needle, http_status_map, http_status_map_len, sizeof(needle), status_comp); + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(code); + Z_PARAM_STR_EX(phrase, 1, 0) + ZEND_PARSE_PARAMETERS_END(); - return result ? result->str : ""; + if (code > 0) { + response_set_status(getThis(), code, phrase); + } } @@ -93,32 +115,18 @@ PHP_METHOD(Response, getReasonPhrase) PHP_METHOD(Response, withStatus) { - zend_long code; - char *phrase; - size_t phrase_len = 0; - const char *suggested_phrase; + zend_long code = 0; + zend_string *phrase = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_LONG(code) Z_PARAM_OPTIONAL - Z_PARAM_STRING(phrase, phrase_len) + Z_PARAM_STR_EX(phrase, 1, 0) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_long(HttpMessage_Response_ce, return_value, ZEND_STRL("statusCode"), code); - - if (phrase_len > 0) { - zend_update_property_stringl( - HttpMessage_Response_ce, return_value, ZEND_STRL("reasonPhrase"), phrase, phrase_len - ); - } else { - suggested_phrase = get_status_string((int)code); - zend_update_property_stringl( - HttpMessage_Response_ce, return_value, ZEND_STRL("reasonPhrase"), - suggested_phrase, strlen(suggested_phrase) - ); - } + response_set_status(return_value, code, phrase); } @@ -134,7 +142,7 @@ static const zend_function_entry response_functions[] = { PHP_MINIT_FUNCTION(http_message_response) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\responseinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("response"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Response"); if (HttpMessage_Message_ce == NULL) return FAILURE; @@ -145,8 +153,8 @@ PHP_MINIT_FUNCTION(http_message_response) zend_class_implements(HttpMessage_Response_ce, 1, interface); /* Properties */ - zend_declare_property_long(HttpMessage_Response_ce, ZEND_STRL("statusCode"), 0, ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Response_ce, ZEND_STRL("reasonPhrase"), "", ZEND_ACC_PROTECTED); + zend_declare_property_long(HttpMessage_Response_ce, ZEND_STRL("statusCode"), 0, ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Response_ce, ZEND_STRL("reasonPhrase"), "", ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/response.h b/response.h new file mode 100644 index 0000000..d7aab2f --- /dev/null +++ b/response.h @@ -0,0 +1,62 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension | + | Helper function to get reason phrase from status code | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifndef HTTP_MESSAGE_RESPONSE_H +#define HTTP_MESSAGE_RESPONSE_H + +#include "http_status_codes.h" + +static int status_comp(const void *a, const void *b) +{ + const http_response_status_code_pair *pa = (const http_response_status_code_pair *) a; + const http_response_status_code_pair *pb = (const http_response_status_code_pair *) b; + + if (pa->code < pb->code) { + return -1; + } else if (pa->code > pb->code) { + return 1; + } + + return 0; +} + +static const char *get_status_string(int code) +{ + http_response_status_code_pair needle = {code, NULL}, *result = NULL; + + result = bsearch(&needle, http_status_map, http_status_map_len, sizeof(needle), status_comp); + + return result ? result->str : ""; +} + +int response_set_status(zval *obj, zend_long code, zend_string *phrase); + +#endif //HTTP_MESSAGE_RESPONSE_H diff --git a/server_request.c b/server_request.c index 7c4728f..6b110ff 100644 --- a/server_request.c +++ b/server_request.c @@ -32,14 +32,14 @@ # include "config.h" #endif -#include -#include "php.h" +#include +#include "ext/spl/spl_exceptions.h" +#include "ext/psr/psr_http_message.h" #include "php_http_message.h" #include "macros.h" #include "uploaded_file.h" #include "zend_exceptions.h" #include "zend_interfaces.h" -#include "ext/psr/psr_http_message.h" #if HAVE_HTTP_MESSAGE @@ -48,7 +48,7 @@ zend_class_entry *HttpMessage_ServerRequest_ce = NULL; int assert_uploaded_files(HashTable *array) { zval *entry; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("uploadedfile"); if (interface == NULL) { zend_throw_error(NULL, "Psr\\Http\\Message\\UploadedFileInterface not found"); @@ -139,7 +139,7 @@ void init_uri_from_params(zval *object, HashTable *serverParams) zend_long port = -1, default_port = -1; zend_bool is_http; - uri = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("uri"), 0, &rv); + uri = zend_read_property(HttpMessage_Request_ce, object, ZEND_STRL("uri"), 0, &rv); request_target = zend_hash_str_find(serverParams, ZEND_STRL("REQUEST_URI")); zend_call_method(uri, HttpMessage_Uri_ce, &HttpMessage_Uri_ce->constructor, ZEND_STRL("__construct"), NULL, @@ -347,7 +347,7 @@ PHP_METHOD(ServerRequest, withParsedBody) ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - if (value != NULL) { + if (EXPECTED(value != NULL)) { zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody"), value); } else { zend_update_property_null(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody")); @@ -361,7 +361,7 @@ PHP_METHOD(ServerRequest, getAttributes) { zval rv, *attributes; - attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); + attributes = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); RETURN_ZVAL(attributes, 1, 0); } @@ -369,18 +369,17 @@ PHP_METHOD(ServerRequest, getAttributes) PHP_METHOD(ServerRequest, getAttribute) { zval rv, *attributes, *value, *default_value = NULL; - char *name; - size_t name_len; + zend_string *name; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(default_value) ZEND_PARSE_PARAMETERS_END(); - attributes = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); + attributes = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); - value = zend_hash_str_find(Z_ARRVAL_P(attributes), name, name_len); + value = zend_hash_find(Z_ARRVAL_P(attributes), name); /* value is only NULL if the entry wasn't found. A null value is still a zval. */ if (value != NULL) { @@ -396,40 +395,38 @@ PHP_METHOD(ServerRequest, withAttribute) { zval rv, *value, *attributes_prop; HashTable *attributes; - char *name; - size_t name_len; + zend_string *name; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - attributes_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("attributes"), 0, &rv); attributes = zend_array_dup(Z_ARR_P(attributes_prop)); - zend_symtable_str_update(attributes, name, name_len, value); + zend_symtable_update(attributes, name, value); ZVAL_ARR(attributes_prop, attributes); } PHP_METHOD(ServerRequest, withoutAttribute) { + zend_string *name; zval rv, *attributes_prop; HashTable *attributes; - char *name; - size_t name_len; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - attributes_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("attributes"), 0, &rv); attributes = zend_array_dup(Z_ARR_P(attributes_prop)); - zend_symtable_str_del(attributes, name, name_len); + zend_symtable_del(attributes, name); ZVAL_ARR(attributes_prop, attributes); } @@ -457,7 +454,7 @@ static const zend_function_entry request_functions[] = { PHP_MINIT_FUNCTION(http_message_serverrequest) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\serverrequestinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("serverrequest"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "ServerRequest"); if (HttpMessage_Request_ce == NULL) return FAILURE; @@ -468,12 +465,12 @@ PHP_MINIT_FUNCTION(http_message_serverrequest) zend_class_implements(HttpMessage_ServerRequest_ce, 1, interface); /* Properties */ - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("serverParams"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("cookieParams"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("queryParams"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("uploadedFiles"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("parsedBody"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("attributes"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("serverParams"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("cookieParams"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("queryParams"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("uploadedFiles"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("parsedBody"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_ServerRequest_ce, ZEND_STRL("attributes"), ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/stream.c b/stream.c index 832253d..f3f69b4 100644 --- a/stream.c +++ b/stream.c @@ -34,7 +34,7 @@ #include "php.h" #include "macros.h" -#include "php_streams.h" +#include "stream.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "ext/psr/psr_http_message.h" @@ -44,58 +44,92 @@ zend_class_entry *HttpMessage_Stream_ce = NULL; -zend_bool string_contains_char(char *haystack, char chr) +void stream_seek(zval *this, zend_long offset, zend_long whence, zval* return_value) { - char *p = strchr(haystack, chr); + zval rv, *resource; + php_stream *stream; + + resource = zend_read_property(HttpMessage_Stream_ce, this, ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", + Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); + return; + } + + if (whence > 3) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Invalid value for whence"); + return; + } + + php_stream_from_zval(stream, resource); - return (p != NULL); + if (!stream->ops->seek || (stream->flags & PHP_STREAM_FLAG_NO_SEEK) != 0) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is not seekable"); + return; + }; + + php_stream_seek(stream, offset, whence); } /* __construct */ ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageStream_construct, 0, 0, 0) - ZEND_ARG_TYPE_INFO(0, uri, IS_RESOURCE, 0) + ZEND_ARG_INFO(0, uri) ZEND_END_ARG_INFO() PHP_METHOD(Stream, __construct) { - zval *zstream = NULL, newstream; + zval *input = NULL, resource; + char *file = NULL, *mode = NULL; + size_t mode_len = 0; php_stream *stream; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 2) Z_PARAM_OPTIONAL - Z_PARAM_RESOURCE(zstream) + Z_PARAM_ZVAL(input) + Z_PARAM_STRING(mode, mode_len) ZEND_PARSE_PARAMETERS_END(); - if (zstream == NULL) { - stream = php_stream_open_wrapper("php://temp", "w+", 0, NULL); + if (UNEXPECTED(input != NULL && Z_TYPE_P(input) != IS_STRING && Z_TYPE_P(input) != IS_RESOURCE)) { + zend_type_error("Expected parameter 1 to be a string or resource, %s given ", zend_zval_type_name(input)); + return; + } + + if (input == NULL) { + if (open_temp_stream(&resource) == FAILURE) return; + } else if (Z_TYPE_P(input) == IS_STRING) { + file = Z_STRVAL_P(input); + file[Z_STRLEN_P(input)] = '\0'; + stream = php_stream_open_wrapper(file, mode != NULL ? mode : "r", 0, NULL); if (stream == NULL) { - zend_throw_error(NULL, "Failed to open 'php://temp' stream"); + zend_throw_error(NULL, "Failed to open '%s' stream", file); return; } - php_stream_to_zval(stream, &newstream); - zstream = &newstream; - } else if (!IS_STREAM_RESOURCE(zstream)) { + php_stream_to_zval(stream, &resource); + } else if (EXPECTED(IS_STREAM_RESOURCE(input))) { + ZVAL_COPY(&resource, input); + } else { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Resource is not a stream"); + return; } - zend_update_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), zstream); + zend_update_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), &resource); } PHP_METHOD(Stream, __toString) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; zend_string *contents; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_EMPTY_STRING(); } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { RETURN_EMPTY_STRING(); @@ -112,7 +146,7 @@ PHP_METHOD(Stream, __toString) strcmp(stream->ops->label, "Input") == 0 ) { stream = php_stream_open_wrapper(stream->orig_path, stream->mode, 0, NULL); - php_stream_to_zval(stream, zstream); + php_stream_to_zval(stream, resource); } if ((contents = php_stream_copy_to_mem(stream, (ssize_t)PHP_STREAM_COPY_ALL, 0))) { @@ -124,42 +158,42 @@ PHP_METHOD(Stream, __toString) PHP_METHOD(Stream, close) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (Z_TYPE_P(zstream) != IS_RESOURCE) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (Z_TYPE_P(resource) != IS_RESOURCE) { return; } - if (IS_STREAM_RESOURCE(zstream)) { - php_stream_from_zval(stream, zstream); + if (IS_STREAM_RESOURCE(resource)) { + php_stream_from_zval(stream, resource); php_stream_close(stream); } } PHP_METHOD(Stream, detach) { - zval rv, *zstream; + zval rv, *resource; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - ZVAL_COPY(return_value, zstream); + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + ZVAL_COPY(return_value, resource); zend_update_property_null(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream")); } PHP_METHOD(Stream, getSize) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; php_stream_statbuf ssb; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_NULL(); } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); php_stream_stat(stream, &ssb); RETURN_LONG(ssb.sb.st_size); @@ -167,18 +201,18 @@ PHP_METHOD(Stream, getSize) PHP_METHOD(Stream, tell) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; size_t pos; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", - Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); return; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); pos = php_stream_tell(stream); RETURN_LONG(pos); @@ -186,16 +220,16 @@ PHP_METHOD(Stream, tell) PHP_METHOD(Stream, eof) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; zend_bool eof; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_TRUE; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); eof = php_stream_eof(stream); RETURN_BOOL(eof); @@ -203,16 +237,16 @@ PHP_METHOD(Stream, eof) PHP_METHOD(Stream, isSeekable) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; zend_bool seekable; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); seekable = (stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0; RETURN_BOOL(seekable); @@ -220,9 +254,7 @@ PHP_METHOD(Stream, isSeekable) PHP_METHOD(Stream, seek) { - zval rv, *zstream; - php_stream *stream; - size_t offset, whence = SEEK_SET; + zend_long offset = 0, whence = SEEK_SET; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2) Z_PARAM_LONG(offset) @@ -230,108 +262,79 @@ PHP_METHOD(Stream, seek) Z_PARAM_LONG(whence) ZEND_PARSE_PARAMETERS_END(); - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", - Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); - return; - } - - if (whence > 3) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Invalid value for whence"); - return; - } - - php_stream_from_zval(stream, zstream); - - if (!stream->ops->seek || (stream->flags & PHP_STREAM_FLAG_NO_SEEK) != 0) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is not seekable"); - return; - }; - - php_stream_seek(stream, offset, whence); + stream_seek(getThis(), offset, whence, return_value); } PHP_METHOD(Stream, rewind) { - zval offset; - - ZVAL_LONG(&offset, 0); - - zend_call_method_with_1_params(getThis(), HttpMessage_Stream_ce, NULL, "seek", return_value, &offset); + stream_seek(getThis(), 0, SEEK_SET, return_value); } PHP_METHOD(Stream, isWritable) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; - zend_bool writable; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } - php_stream_from_zval(stream, zstream); - writable = !string_contains_char(stream->mode, 'r') || string_contains_char(stream->mode, '+'); + php_stream_from_zval(stream, resource); - RETURN_BOOL(writable); + RETURN_BOOL(stream_is_writable(stream)); } PHP_METHOD(Stream, write) { - zval rv, *zstream; - char *input; - size_t len, ret; + zval rv, *resource; + char *input = NULL; + size_t len = 0, ret = 0; php_stream *stream; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STRING(input, len) ZEND_PARSE_PARAMETERS_END(); - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", - Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); return; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); - if (string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { + if (!stream_is_writable(stream)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not writable"); return; } - if (len == 0) { - RETURN_LONG(0); + if (len > 0) { + ret = php_stream_write(stream, input, len); } - ret = php_stream_write(stream, input, len); - RETURN_LONG(ret); } PHP_METHOD(Stream, isReadable) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; - zend_bool writable; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } - php_stream_from_zval(stream, zstream); - writable = string_contains_char(stream->mode, 'r') || string_contains_char(stream->mode, '+'); + php_stream_from_zval(stream, resource); - RETURN_BOOL(writable); + RETURN_BOOL(stream_is_readable(stream)); } PHP_METHOD(Stream, read) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; zend_long len = 0; zend_string *contents; @@ -345,14 +348,14 @@ PHP_METHOD(Stream, read) return; } - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", - Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); return; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not readable"); @@ -368,18 +371,18 @@ PHP_METHOD(Stream, read) PHP_METHOD(Stream, getContents) { - zval rv, *zstream; + zval rv, *resource; php_stream *stream; zend_string *contents; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - if (!IS_STREAM_RESOURCE(zstream)) { + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", - Z_TYPE_P(zstream) == IS_RESOURCE ? "closed" : "detached"); + Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); return; } - php_stream_from_zval(stream, zstream); + php_stream_from_zval(stream, resource); if (!string_contains_char(stream->mode, 'r') && !string_contains_char(stream->mode, '+')) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream not readable"); @@ -395,16 +398,16 @@ PHP_METHOD(Stream, getContents) PHP_METHOD(Stream, getMetadata) { - zval rv, fname, *zstream, *zvalue; + zval rv, fname, *resource, *zvalue; zend_string *key = NULL; - zstream = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR(key) ZEND_PARSE_PARAMETERS_END(); - if (!IS_STREAM_RESOURCE(zstream)) { + if (!IS_STREAM_RESOURCE(resource)) { if (key == NULL) { array_init(return_value); } else { @@ -414,7 +417,7 @@ PHP_METHOD(Stream, getMetadata) } ZVAL_STRING(&fname, "stream_get_meta_data"); - call_user_function(NULL, NULL, &fname, return_value, 1, zstream); + call_user_function(NULL, NULL, &fname, return_value, 1, resource); if (key != NULL) { zvalue = zend_hash_find(Z_ARR(*return_value), key); @@ -453,7 +456,7 @@ static const zend_function_entry stream_functions[] = { PHP_MINIT_FUNCTION(http_message_stream) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("stream"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Stream"); @@ -463,7 +466,7 @@ PHP_MINIT_FUNCTION(http_message_stream) zend_class_implements(HttpMessage_Stream_ce, 1, interface); /* Properties */ - zend_declare_property_null(HttpMessage_Stream_ce, ZEND_STRL("stream"), ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_Stream_ce, ZEND_STRL("stream"), ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/stream.h b/stream.h new file mode 100644 index 0000000..fa6d3c2 --- /dev/null +++ b/stream.h @@ -0,0 +1,68 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension | + | Helper function to work with streams | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifndef HTTP_MESSAGE_STREAM_H +#define HTTP_MESSAGE_STREAM_H + +#include "php_streams.h" + +static int open_temp_stream(zval *zstream) +{ + php_stream *stream = php_stream_open_wrapper("php://temp", "w+", 0, NULL); + + if (stream == NULL) { + zend_throw_error(NULL, "Failed to open 'php://temp' stream"); + return FAILURE; + } + + php_stream_to_zval(stream, zstream); + + return SUCCESS; +} + +zend_always_inline static zend_bool string_contains_char(char *haystack, char chr) +{ + char *p = strchr(haystack, chr); + + return (p != NULL); +} + +zend_always_inline static zend_bool stream_is_writable(php_stream *stream) +{ + return !string_contains_char(stream->mode, 'r') || string_contains_char(stream->mode, '+'); +} + +zend_always_inline static zend_bool stream_is_readable(php_stream *stream) +{ + return string_contains_char(stream->mode, 'r') || string_contains_char(stream->mode, '+'); +} + +#endif //HTTP_MESSAGE_STREAM_H diff --git a/tests/Factory/createRequest_001.phpt b/tests/Factory/createRequest_001.phpt new file mode 100644 index 0000000..c13a881 --- /dev/null +++ b/tests/Factory/createRequest_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +Factory::createRequest() +--FILE-- +createRequest('GET', 'https://www.example.com/'); + +var_dump($request); + +?> +--EXPECTF-- +object(HttpMessage\Request)#%d (6) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["requestTarget":"HttpMessage\Request":private]=> + NULL + ["method":"HttpMessage\Request":private]=> + string(3) "GET" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(15) "www.example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } +} diff --git a/tests/Factory/createRequest_002.phpt b/tests/Factory/createRequest_002.phpt new file mode 100644 index 0000000..c7ca40e --- /dev/null +++ b/tests/Factory/createRequest_002.phpt @@ -0,0 +1,48 @@ +--TEST-- +Factory::createRequest() with Uri object +--FILE-- +createRequest('GET', $uri); + +var_dump($request); +var_dump($request->getUri() === $uri); + +?> +--EXPECTF-- +object(HttpMessage\Request)#%d (6) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["requestTarget":"HttpMessage\Request":private]=> + NULL + ["method":"HttpMessage\Request":private]=> + string(3) "GET" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(15) "www.example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } +} +bool(true) diff --git a/tests/Factory/createResponse_001.phpt b/tests/Factory/createResponse_001.phpt new file mode 100644 index 0000000..8ea4c49 --- /dev/null +++ b/tests/Factory/createResponse_001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Factory::createResponse() without arguments +--FILE-- +createResponse(); + +var_dump($response); + +?> +--EXPECTF-- +object(HttpMessage\Response)#%d (5) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["statusCode":"HttpMessage\Response":private]=> + int(200) + ["reasonPhrase":"HttpMessage\Response":private]=> + string(2) "OK" +} diff --git a/tests/Factory/createResponse_002.phpt b/tests/Factory/createResponse_002.phpt new file mode 100644 index 0000000..bac0c42 --- /dev/null +++ b/tests/Factory/createResponse_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Factory::createResponse() with status code +--FILE-- +createResponse(400); +var_dump($response); + +var_dump($factory->createResponse(100)->getStatusCode()); +var_dump($factory->createResponse(100)->getReasonPhrase()); +var_dump($factory->createResponse(200)->getReasonPhrase()); +var_dump($factory->createResponse(404)->getReasonPhrase()); + +?> +--EXPECTF-- +object(HttpMessage\Response)#%d (5) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["statusCode":"HttpMessage\Response":private]=> + int(400) + ["reasonPhrase":"HttpMessage\Response":private]=> + string(11) "Bad Request" +} +int(100) +string(8) "Continue" +string(2) "OK" +string(9) "Not Found" diff --git a/tests/Factory/createResponse_003.phpt b/tests/Factory/createResponse_003.phpt new file mode 100644 index 0000000..3018474 --- /dev/null +++ b/tests/Factory/createResponse_003.phpt @@ -0,0 +1,27 @@ +--TEST-- +Factory::createResponse() with status code and reason phrase +--FILE-- +createResponse(400, "Foo Bar"); +var_dump($response); + +?> +--EXPECTF-- +object(HttpMessage\Response)#%d (5) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["statusCode":"HttpMessage\Response":private]=> + int(400) + ["reasonPhrase":"HttpMessage\Response":private]=> + string(7) "Foo Bar" +} \ No newline at end of file diff --git a/tests/Factory/createServerRequest_001.phpt b/tests/Factory/createServerRequest_001.phpt new file mode 100644 index 0000000..f25134a --- /dev/null +++ b/tests/Factory/createServerRequest_001.phpt @@ -0,0 +1,80 @@ +--TEST-- +Factory::createServerRequest() +--FILE-- +createServerRequest('GET', 'https://www.example.com/'); + +var_dump($request); + +?> +--EXPECTF-- +object(HttpMessage\ServerRequest)#%d (14) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["requestTarget":"HttpMessage\Request":private]=> + NULL + ["method":"HttpMessage\Request":private]=> + string(0) "" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(0) "" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(0) "" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } + ["serverParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["cookieParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["queryParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["uploadedFiles":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["parsedBody":"HttpMessage\ServerRequest":private]=> + NULL + ["attributes":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["method"]=> + string(3) "GET" + ["uri"]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(15) "www.example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } +} \ No newline at end of file diff --git a/tests/Factory/createServerRequest_002.phpt b/tests/Factory/createServerRequest_002.phpt new file mode 100644 index 0000000..a409e72 --- /dev/null +++ b/tests/Factory/createServerRequest_002.phpt @@ -0,0 +1,84 @@ +--TEST-- +Factory::createServerRequest() with Uri object +--FILE-- +createServerRequest('GET', $uri); + +var_dump($request); +var_dump($request->getUri() === $uri); + +?> +--EXPECTF-- +object(HttpMessage\ServerRequest)#%d (14) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["requestTarget":"HttpMessage\Request":private]=> + NULL + ["method":"HttpMessage\Request":private]=> + string(0) "" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(0) "" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(0) "" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } + ["serverParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["cookieParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["queryParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["uploadedFiles":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["parsedBody":"HttpMessage\ServerRequest":private]=> + NULL + ["attributes":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["method"]=> + string(3) "GET" + ["uri"]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(15) "www.example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } +} +bool(false) \ No newline at end of file diff --git a/tests/Factory/createServerRequest_003.phpt b/tests/Factory/createServerRequest_003.phpt new file mode 100644 index 0000000..e8a2243 --- /dev/null +++ b/tests/Factory/createServerRequest_003.phpt @@ -0,0 +1,150 @@ +--TEST-- +Factory::createServerRequest() with server params +--FILE-- + 'HTTP/1.1', + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'example.com', + 'REQUEST_URI' => '/foos/?bar=1', + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + 'CONTENT_LENGTH' => 1324, + 'HTTP_ACCEPT' => 'text/html', + 'HTTP_ACCEPT_CHARSET' => 'utf-8', + 'HTTP_ACCEPT_ENCODING' => 'zip, deflate', + 'PHP_AUTH_USER' => 'john', + 'PHP_AUTH_PASS' => 'secret', + 'SERVER_PORT' => 80, +]; + +$factory = new HttpMessage\Factory(); +$request = $factory->createServerRequest('QUERY', 'https://www.example.com/foo/bar/22?q=1', $params); + +var_dump($request); + +?> +--EXPECTF-- +object(HttpMessage\ServerRequest)#%d (14) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(6) { + ["Host"]=> + array(1) { + [0]=> + string(11) "example.com" + } + ["Accept"]=> + array(1) { + [0]=> + string(9) "text/html" + } + ["Accept-Charset"]=> + array(1) { + [0]=> + string(5) "utf-8" + } + ["Accept-Encoding"]=> + array(1) { + [0]=> + string(12) "zip, deflate" + } + ["Content-Type"]=> + array(1) { + [0]=> + string(33) "application/x-www-form-urlencoded" + } + ["Content-Length"]=> + array(1) { + [0]=> + int(1324) + } + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["requestTarget":"HttpMessage\Request":private]=> + NULL + ["method":"HttpMessage\Request":private]=> + string(0) "" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(4) "http" + ["userInfo":"HttpMessage\Uri":private]=> + string(11) "john:secret" + ["host":"HttpMessage\Uri":private]=> + string(11) "example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(6) "/foos/" + ["query":"HttpMessage\Uri":private]=> + string(5) "bar=1" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } + ["serverParams":"HttpMessage\ServerRequest":private]=> + array(12) { + ["SERVER_PROTOCOL"]=> + string(8) "HTTP/1.1" + ["REQUEST_METHOD"]=> + string(4) "POST" + ["HTTP_HOST"]=> + string(11) "example.com" + ["REQUEST_URI"]=> + string(12) "/foos/?bar=1" + ["CONTENT_TYPE"]=> + string(33) "application/x-www-form-urlencoded" + ["CONTENT_LENGTH"]=> + int(1324) + ["HTTP_ACCEPT"]=> + string(9) "text/html" + ["HTTP_ACCEPT_CHARSET"]=> + string(5) "utf-8" + ["HTTP_ACCEPT_ENCODING"]=> + string(12) "zip, deflate" + ["PHP_AUTH_USER"]=> + string(4) "john" + ["PHP_AUTH_PASS"]=> + string(6) "secret" + ["SERVER_PORT"]=> + int(80) + } + ["cookieParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["queryParams":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["uploadedFiles":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["parsedBody":"HttpMessage\ServerRequest":private]=> + NULL + ["attributes":"HttpMessage\ServerRequest":private]=> + array(0) { + } + ["method"]=> + string(5) "QUERY" + ["uri"]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(15) "www.example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(11) "/foo/bar/22" + ["query":"HttpMessage\Uri":private]=> + string(3) "q=1" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" + } +} \ No newline at end of file diff --git a/tests/Factory/createStreamFromFile_001.phpt b/tests/Factory/createStreamFromFile_001.phpt new file mode 100644 index 0000000..e732c28 --- /dev/null +++ b/tests/Factory/createStreamFromFile_001.phpt @@ -0,0 +1,43 @@ +--TEST-- +Factory::createStreamFromFile() +--FILE-- +createStreamFromFile(__FILE__); + +var_dump($stream); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); + +fseek($resource, 0); +var_dump(fread($resource, 16)); + +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> + string(5) "STDIO" + ["mode"]=> + string(1) "r" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(%d) "%screateStreamFromFile_001.php" +} +string(16) "createStreamFromFile(__FILE__, "r+"); + +var_dump($stream); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); + +fseek($resource, 0); +var_dump(fread($resource, 16)); + +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> + string(5) "STDIO" + ["mode"]=> + string(2) "r+" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(%d) "%screateStreamFromFile_002.php" +} +string(16) "createStreamFromFile('php://memory', 'w+'); + +var_dump($stream); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); + +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(6) "MEMORY" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(12) "php://memory" +} \ No newline at end of file diff --git a/tests/Factory/createStreamFromResource_001.phpt b/tests/Factory/createStreamFromResource_001.phpt new file mode 100644 index 0000000..868e5ec --- /dev/null +++ b/tests/Factory/createStreamFromResource_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +Factory::createStreamFromResource() +--FILE-- +createStreamFromResource($resource); + +var_dump($stream); +var_dump($stream->detach() === $resource); +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +bool(true) \ No newline at end of file diff --git a/tests/Factory/createStream_001.phpt b/tests/Factory/createStream_001.phpt new file mode 100644 index 0000000..ae3067e --- /dev/null +++ b/tests/Factory/createStream_001.phpt @@ -0,0 +1,36 @@ +--TEST-- +Factory::createStream() +--FILE-- +createStream(); + +var_dump($stream); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); + +fseek($resource, 0); +var_dump(fread($resource, 1024)); + +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(6) { + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(4) "TEMP" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(10) "php://temp" +} +string(0) "" \ No newline at end of file diff --git a/tests/Factory/createStream_002.phpt b/tests/Factory/createStream_002.phpt new file mode 100644 index 0000000..6a3c160 --- /dev/null +++ b/tests/Factory/createStream_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Factory::createStream() with content +--FILE-- +createStream("hello"); + +var_dump($stream); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); + +fseek($resource, 0); +var_dump(fread($resource, 1024)); + +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(6) { + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(4) "TEMP" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(10) "php://temp" +} +string(5) "hello" \ No newline at end of file diff --git a/tests/Factory/createUploadedFile_001.phpt b/tests/Factory/createUploadedFile_001.phpt new file mode 100644 index 0000000..f435dc7 --- /dev/null +++ b/tests/Factory/createUploadedFile_001.phpt @@ -0,0 +1,50 @@ +--TEST-- +Factory::createUploadedFile() with a stream +--FILE-- +createUploadedFile($stream); + +var_dump($upload); +var_dump($upload->getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +var_dump($upload->getStream() === $stream); +var_dump($upload->getStream()); + +?> +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["file":"HttpMessage\UploadedFile":private]=> + NULL + ["size":"HttpMessage\UploadedFile":private]=> + NULL + ["error":"HttpMessage\UploadedFile":private]=> + int(0) + ["clientFilename":"HttpMessage\UploadedFile":private]=> + NULL + ["clientMediaType":"HttpMessage\UploadedFile":private]=> + NULL + ["moved":"HttpMessage\UploadedFile":private]=> + bool(false) + ["checkUploaded":"HttpMessage\UploadedFile":private]=> + bool(false) +} +NULL +int(0) +NULL +NULL +bool(true) +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} \ No newline at end of file diff --git a/tests/Factory/createUploadedFile_002.phpt b/tests/Factory/createUploadedFile_002.phpt new file mode 100644 index 0000000..94eb11c --- /dev/null +++ b/tests/Factory/createUploadedFile_002.phpt @@ -0,0 +1,50 @@ +--TEST-- +Factory::createUploadedFile() +--FILE-- +createUploadedFile($stream, 99, UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); + +var_dump($upload); +var_dump($upload->getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +var_dump($upload->getStream() === $stream); +var_dump($upload->getStream()); + +?> +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["file":"HttpMessage\UploadedFile":private]=> + NULL + ["size":"HttpMessage\UploadedFile":private]=> + int(99) + ["error":"HttpMessage\UploadedFile":private]=> + int(0) + ["clientFilename":"HttpMessage\UploadedFile":private]=> + string(10) "myfile.txt" + ["clientMediaType":"HttpMessage\UploadedFile":private]=> + string(10) "text/plain" + ["moved":"HttpMessage\UploadedFile":private]=> + bool(false) + ["checkUploaded":"HttpMessage\UploadedFile":private]=> + bool(false) +} +int(99) +int(0) +string(10) "myfile.txt" +string(10) "text/plain" +bool(true) +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} \ No newline at end of file diff --git a/tests/Factory/createUploadedFile_003.phpt b/tests/Factory/createUploadedFile_003.phpt new file mode 100644 index 0000000..d6ab638 --- /dev/null +++ b/tests/Factory/createUploadedFile_003.phpt @@ -0,0 +1,43 @@ +--TEST-- +Factory::createUploadedFile() with a stream and error +--FILE-- +createUploadedFile($stream, NULL, UPLOAD_ERR_INI_SIZE); + +var_dump($upload); +var_dump($upload->getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +?> +--CLEAN-- + +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> + NULL + ["file":"HttpMessage\UploadedFile":private]=> + NULL + ["size":"HttpMessage\UploadedFile":private]=> + NULL + ["error":"HttpMessage\UploadedFile":private]=> + int(1) + ["clientFilename":"HttpMessage\UploadedFile":private]=> + NULL + ["clientMediaType":"HttpMessage\UploadedFile":private]=> + NULL + ["moved":"HttpMessage\UploadedFile":private]=> + bool(false) + ["checkUploaded":"HttpMessage\UploadedFile":private]=> + bool(false) +} +NULL +int(1) +NULL +NULL \ No newline at end of file diff --git a/tests/Request/__construct_001.phpt b/tests/Request/__construct_001.phpt index d54fd2a..e929012 100644 --- a/tests/Request/__construct_001.phpt +++ b/tests/Request/__construct_001.phpt @@ -11,36 +11,36 @@ var_dump($request->getBody()->getMetadata('uri')); ?> --EXPECTF-- -object(HttpMessage\Request)#1 (6) { - ["protocolVersion":protected]=> +object(HttpMessage\Request)#%d (6) { + ["protocolVersion":"HttpMessage\Message":private]=> string(3) "1.1" - ["headers":protected]=> + ["headers":"HttpMessage\Message":private]=> array(0) { } - ["body":protected]=> - object(HttpMessage\Stream)#2 (1) { - ["stream":protected]=> + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } - ["requestTarget":protected]=> + ["requestTarget":"HttpMessage\Request":private]=> NULL - ["method":protected]=> + ["method":"HttpMessage\Request":private]=> string(0) "" - ["uri":protected]=> - object(HttpMessage\Uri)#3 (7) { - ["scheme":protected]=> + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } } diff --git a/tests/Response/__construct_001.phpt b/tests/Response/__construct_001.phpt index 92c2acb..a112db0 100644 --- a/tests/Response/__construct_001.phpt +++ b/tests/Response/__construct_001.phpt @@ -8,20 +8,20 @@ var_dump($response); var_dump($response->getBody()->getMetadata('uri')); ?> --EXPECTF-- -object(HttpMessage\Response)#1 (5) { - ["protocolVersion":protected]=> +object(HttpMessage\Response)#%d (5) { + ["protocolVersion":"HttpMessage\Message":private]=> string(3) "1.1" - ["headers":protected]=> + ["headers":"HttpMessage\Message":private]=> array(0) { } - ["body":protected]=> - object(HttpMessage\Stream)#2 (1) { - ["stream":protected]=> + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } - ["statusCode":protected]=> + ["statusCode":"HttpMessage\Response":private]=> int(0) - ["reasonPhrase":protected]=> + ["reasonPhrase":"HttpMessage\Response":private]=> string(0) "" } -string(10) "php://temp" +string(10) "php://temp" \ No newline at end of file diff --git a/tests/ServerRequest/__construct_001.phpt b/tests/ServerRequest/__construct_001.phpt index 27640f9..48a6405 100644 --- a/tests/ServerRequest/__construct_001.phpt +++ b/tests/ServerRequest/__construct_001.phpt @@ -8,53 +8,53 @@ var_dump($request); ?> --EXPECTF-- -object(HttpMessage\ServerRequest)#1 (12) { - ["protocolVersion":protected]=> +object(HttpMessage\ServerRequest)#%d (12) { + ["protocolVersion":"HttpMessage\Message":private]=> string(3) "1.1" - ["headers":protected]=> + ["headers":"HttpMessage\Message":private]=> array(0) { } - ["body":protected]=> - object(HttpMessage\Stream)#2 (1) { - ["stream":protected]=> + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } - ["requestTarget":protected]=> + ["requestTarget":"HttpMessage\Request":private]=> NULL - ["method":protected]=> + ["method":"HttpMessage\Request":private]=> string(0) "" - ["uri":protected]=> - object(HttpMessage\Uri)#3 (7) { - ["scheme":protected]=> + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } - ["serverParams":protected]=> + ["serverParams":"HttpMessage\ServerRequest":private]=> array(0) { } - ["cookieParams":protected]=> + ["cookieParams":"HttpMessage\ServerRequest":private]=> array(0) { } - ["queryParams":protected]=> + ["queryParams":"HttpMessage\ServerRequest":private]=> array(0) { } - ["uploadedFiles":protected]=> + ["uploadedFiles":"HttpMessage\ServerRequest":private]=> array(0) { } - ["parsedBody":protected]=> + ["parsedBody":"HttpMessage\ServerRequest":private]=> NULL - ["attributes":protected]=> + ["attributes":"HttpMessage\ServerRequest":private]=> array(0) { } } \ No newline at end of file diff --git a/tests/ServerRequest/__construct_002.phpt b/tests/ServerRequest/__construct_002.phpt index 3b5e8fc..e551e9b 100644 --- a/tests/ServerRequest/__construct_002.phpt +++ b/tests/ServerRequest/__construct_002.phpt @@ -26,10 +26,10 @@ var_dump($request); ?> --EXPECTF-- -object(HttpMessage\ServerRequest)#1 (12) { - ["protocolVersion":protected]=> +object(HttpMessage\ServerRequest)#%d (13) { + ["protocolVersion":"HttpMessage\Message":private]=> string(3) "1.1" - ["headers":protected]=> + ["headers":"HttpMessage\Message":private]=> array(1) { ["Host"]=> array(1) { @@ -37,33 +37,33 @@ object(HttpMessage\ServerRequest)#1 (12) { string(11) "example.com" } } - ["body":protected]=> - object(HttpMessage\Stream)#2 (1) { - ["stream":protected]=> + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } - ["requestTarget":protected]=> + ["requestTarget":"HttpMessage\Request":private]=> NULL - ["method":protected]=> - string(4) "POST" - ["uri":protected]=> - object(HttpMessage\Uri)#3 (7) { - ["scheme":protected]=> + ["method":"HttpMessage\Request":private]=> + string(0) "" + ["uri":"HttpMessage\Request":private]=> + object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(11) "example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(6) "/foos/" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } - ["serverParams":protected]=> + ["serverParams":"HttpMessage\ServerRequest":private]=> array(3) { ["REQUEST_METHOD"]=> string(4) "POST" @@ -72,41 +72,41 @@ object(HttpMessage\ServerRequest)#1 (12) { ["REQUEST_URI"]=> string(6) "/foos/" } - ["cookieParams":protected]=> + ["cookieParams":"HttpMessage\ServerRequest":private]=> array(1) { ["session"]=> int(999) } - ["queryParams":protected]=> + ["queryParams":"HttpMessage\ServerRequest":private]=> array(2) { ["id"]=> string(2) "42" ["persist"]=> string(3) "yes" } - ["uploadedFiles":protected]=> + ["uploadedFiles":"HttpMessage\ServerRequest":private]=> array(1) { ["document"]=> - object(HttpMessage\UploadedFile)#4 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile" + ["size":"HttpMessage\UploadedFile":private]=> int(2822) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> string(12) "document.pdf" - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> string(15) "application/pdf" - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } } - ["parsedBody":protected]=> + ["parsedBody":"HttpMessage\ServerRequest":private]=> array(3) { ["id"]=> int(42) @@ -120,7 +120,9 @@ object(HttpMessage\ServerRequest)#1 (12) { int(44) } } - ["attributes":protected]=> + ["attributes":"HttpMessage\ServerRequest":private]=> array(0) { } + ["method"]=> + string(4) "POST" } \ No newline at end of file diff --git a/tests/ServerRequest/__construct_003.phpt b/tests/ServerRequest/__construct_003.phpt index 9d0a74a..e3712b2 100644 --- a/tests/ServerRequest/__construct_003.phpt +++ b/tests/ServerRequest/__construct_003.phpt @@ -85,184 +85,184 @@ var_dump($request->getUploadedFiles()); --EXPECTF-- array(3) { ["document"]=> - object(HttpMessage\UploadedFile)#4 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile01" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile01" + ["size":"HttpMessage\UploadedFile":private]=> int(2822) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> string(12) "document.pdf" - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> string(15) "application/pdf" - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } ["attachments"]=> array(2) { [0]=> - object(HttpMessage\UploadedFile)#5 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile02" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile02" + ["size":"HttpMessage\UploadedFile":private]=> int(3724) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> string(11) "copy-id.pdf" - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> string(9) "image/jpg" - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } [1]=> - object(HttpMessage\UploadedFile)#6 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile03" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile03" + ["size":"HttpMessage\UploadedFile":private]=> int(263) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> string(22) "proof-of-residence.pdf" - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> string(15) "application/pdf" - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } } ["forms"]=> array(3) { ["g201"]=> - object(HttpMessage\UploadedFile)#7 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile04" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile04" + ["size":"HttpMessage\UploadedFile":private]=> int(942) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } ["g202"]=> array(3) { ["a"]=> - object(HttpMessage\UploadedFile)#8 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile05" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile05" + ["size":"HttpMessage\UploadedFile":private]=> int(2391) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } ["b"]=> - object(HttpMessage\UploadedFile)#9 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> NULL - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> NULL - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(4) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } ["c"]=> - object(HttpMessage\UploadedFile)#10 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> NULL - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> int(485) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(3) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } } ["g301"]=> array(2) { [0]=> - object(HttpMessage\UploadedFile)#11 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> - string(%d) "%s/uploadedfile07" - ["size":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> + string(%d) "%suploadedfile07" + ["size":"HttpMessage\UploadedFile":private]=> int(4732) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } [1]=> - object(HttpMessage\UploadedFile)#12 (8) { - ["stream":protected]=> + object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> NULL - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> int(124901432) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(2) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } } diff --git a/tests/ServerRequest/__construct_004.phpt b/tests/ServerRequest/__construct_004.phpt index d8ef1b2..cb2fcaf 100644 --- a/tests/ServerRequest/__construct_004.phpt +++ b/tests/ServerRequest/__construct_004.phpt @@ -24,22 +24,22 @@ var_dump($request->getUri()); var_dump($request->getHeaders()); ?> ---EXPECT-- -string(4) "POST" -object(HttpMessage\Uri)#3 (7) { - ["scheme":protected]=> +--EXPECTF-- +string(0) "" +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(4) "http" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(11) "john:secret" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(11) "example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(6) "/foos/" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(5) "bar=1" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } array(6) { diff --git a/tests/ServerRequest/parsedBody_001.phpt b/tests/ServerRequest/parsedBody_001.phpt index ea82db8..8b37527 100644 --- a/tests/ServerRequest/parsedBody_001.phpt +++ b/tests/ServerRequest/parsedBody_001.phpt @@ -22,7 +22,7 @@ var_dump($objRequest->getParsedBody()); var_dump($nullRequest->getParsedBody()); ?> ---EXPECT-- +--EXPECTF-- array(3) { ["foo"]=> string(3) "bar" @@ -31,7 +31,7 @@ array(3) { ["user"]=> int(22) } -object(stdClass)#5 (2) { +object(stdClass)#%d (2) { ["color"]=> string(3) "red" ["user"]=> diff --git a/tests/Stream/__construct_001.phpt b/tests/Stream/__construct_001.phpt index f673d18..4b3cf55 100644 --- a/tests/Stream/__construct_001.phpt +++ b/tests/Stream/__construct_001.phpt @@ -1,16 +1,29 @@ --TEST-- -Create Stream with resource +Create Stream without arguments --FILE-- detach() === $resource); + +$resource = $stream->detach(); +var_dump(stream_get_meta_data($resource)); ?> --EXPECTF-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } -bool(true) \ No newline at end of file +array(6) { + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(4) "TEMP" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(10) "php://temp" +} \ No newline at end of file diff --git a/tests/Stream/__construct_002.phpt b/tests/Stream/__construct_002.phpt index 2ece024..581334c 100644 --- a/tests/Stream/__construct_002.phpt +++ b/tests/Stream/__construct_002.phpt @@ -1,29 +1,16 @@ --TEST-- -Create Stream without arguments +Create Stream with resource --FILE-- detach(); -var_dump(stream_get_meta_data($resource)); +$stream = new HttpMessage\Stream($resource); +var_dump($stream); +var_dump($stream->detach() === $resource); ?> --EXPECTF-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } -array(6) { - ["wrapper_type"]=> - string(3) "PHP" - ["stream_type"]=> - string(4) "TEMP" - ["mode"]=> - string(3) "w+b" - ["unread_bytes"]=> - int(0) - ["seekable"]=> - bool(true) - ["uri"]=> - string(10) "php://temp" -} \ No newline at end of file +bool(true) \ No newline at end of file diff --git a/tests/Stream/__construct_003.phpt b/tests/Stream/__construct_003.phpt new file mode 100644 index 0000000..8fde2aa --- /dev/null +++ b/tests/Stream/__construct_003.phpt @@ -0,0 +1,35 @@ +--TEST-- +Create Stream with file name +--FILE-- +detach(); +var_dump(stream_get_meta_data($resource)); +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> + string(5) "STDIO" + ["mode"]=> + string(1) "r" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(%d) "%s__construct_003.php" +} \ No newline at end of file diff --git a/tests/Stream/__construct_004.phpt b/tests/Stream/__construct_004.phpt new file mode 100644 index 0000000..2634434 --- /dev/null +++ b/tests/Stream/__construct_004.phpt @@ -0,0 +1,35 @@ +--TEST-- +Create Stream with PHP stream name and mode +--FILE-- +detach(); +var_dump(stream_get_meta_data($resource)); +?> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(3) "PHP" + ["stream_type"]=> + string(6) "MEMORY" + ["mode"]=> + string(3) "w+b" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(12) "php://memory" +} \ No newline at end of file diff --git a/tests/Stream/__construct_err01.phpt b/tests/Stream/__construct_err01.phpt index 826145a..ddf21d1 100644 --- a/tests/Stream/__construct_err01.phpt +++ b/tests/Stream/__construct_err01.phpt @@ -1,5 +1,5 @@ --TEST-- -Create Stream error: closed stream +Create Stream with closed stream --FILE-- getMessage(); +} +?> +--EXPECT-- +Expected parameter 1 to be a string or resource, array given diff --git a/tests/Stream/close_001.phpt b/tests/Stream/close_001.phpt index 946c19f..a508ad6 100644 --- a/tests/Stream/close_001.phpt +++ b/tests/Stream/close_001.phpt @@ -12,9 +12,9 @@ var_dump(get_resource_type($resource)); $stream->close(); // No error ?> ---EXPECT-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> - resource(5) of type (Unknown) +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (Unknown) } -string(7) "Unknown" +string(7) "Unknown" \ No newline at end of file diff --git a/tests/Stream/close_002.phpt b/tests/Stream/close_002.phpt index 2074228..e43fc46 100644 --- a/tests/Stream/close_002.phpt +++ b/tests/Stream/close_002.phpt @@ -12,11 +12,11 @@ $stream->close(); var_dump($stream); ?> --EXPECTF-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (Unknown) } -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (Unknown) } \ No newline at end of file diff --git a/tests/Stream/detach_001.phpt b/tests/Stream/detach_001.phpt index 7a21d83..934ce1e 100644 --- a/tests/Stream/detach_001.phpt +++ b/tests/Stream/detach_001.phpt @@ -15,11 +15,11 @@ var_dump($stream->detach()); $stream->close(); // Calling close() while detached should be ignored ?> ---EXPECT-- -object(HttpMessage\Stream)#1 (1) { - ["stream":protected]=> +--EXPECTF-- +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> NULL } bool(true) string(6) "stream" -NULL +NULL \ No newline at end of file diff --git a/tests/Stream/getMetadata_003.phpt b/tests/Stream/getMetadata_003.phpt new file mode 100644 index 0000000..74525e1 --- /dev/null +++ b/tests/Stream/getMetadata_003.phpt @@ -0,0 +1,30 @@ +--TEST-- +Stream::getMetadata() +--FILE-- +getMetadata()); + +?> +--EXPECTF-- +array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> + string(5) "STDIO" + ["mode"]=> + string(1) "r" + ["unread_bytes"]=> + int(0) + ["seekable"]=> + bool(true) + ["uri"]=> + string(71) "%sgetMetadata_003.php" +} diff --git a/tests/UploadedFile/__construct_001.phpt b/tests/UploadedFile/__construct_001.phpt index 202f67b..10bbb10 100644 --- a/tests/UploadedFile/__construct_001.phpt +++ b/tests/UploadedFile/__construct_001.phpt @@ -19,22 +19,22 @@ var_dump($upload->getClientMediaType()); unlink(sys_get_temp_dir() . '/uploadedfile'); ?> --EXPECTF-- -object(HttpMessage\UploadedFile)#1 (8) { - ["stream":protected]=> +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> string(%d) "%s/uploadedfile" - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> int(99) - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> string(10) "myfile.txt" - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> string(10) "text/plain" - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } int(99) diff --git a/tests/UploadedFile/__construct_002.phpt b/tests/UploadedFile/__construct_002.phpt index 0bc5ecb..8b61383 100644 --- a/tests/UploadedFile/__construct_002.phpt +++ b/tests/UploadedFile/__construct_002.phpt @@ -19,22 +19,22 @@ var_dump($upload->getClientMediaType()); unlink(sys_get_temp_dir() . '/uploadedfile'); ?> --EXPECTF-- -object(HttpMessage\UploadedFile)#1 (8) { - ["stream":protected]=> +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> string(%d) "%s/uploadedfile" - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> NULL - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(0) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } NULL diff --git a/tests/UploadedFile/__construct_003.phpt b/tests/UploadedFile/__construct_003.phpt index 83ab6fb..0c28021 100644 --- a/tests/UploadedFile/__construct_003.phpt +++ b/tests/UploadedFile/__construct_003.phpt @@ -1,5 +1,5 @@ --TEST-- -Create UploadedFile with only a path +Create UploadedFile with path and error --FILE-- getClientMediaType()); ---EXPECT-- -object(HttpMessage\UploadedFile)#1 (8) { - ["stream":protected]=> +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> NULL - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> NULL - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(1) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } NULL diff --git a/tests/UploadedFile/__construct_004.phpt b/tests/UploadedFile/__construct_004.phpt index 02624b1..c995015 100644 --- a/tests/UploadedFile/__construct_004.phpt +++ b/tests/UploadedFile/__construct_004.phpt @@ -1,5 +1,5 @@ --TEST-- -Create UploadedFile with only a path +Create UploadedFile with only an error --FILE-- getClientFilename()); var_dump($upload->getClientMediaType()); ?> ---EXPECT-- -object(HttpMessage\UploadedFile)#1 (8) { - ["stream":protected]=> +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> NULL - ["file":protected]=> + ["file":"HttpMessage\UploadedFile":private]=> NULL - ["size":protected]=> + ["size":"HttpMessage\UploadedFile":private]=> NULL - ["error":protected]=> + ["error":"HttpMessage\UploadedFile":private]=> int(4) - ["clientFilename":protected]=> + ["clientFilename":"HttpMessage\UploadedFile":private]=> NULL - ["clientMediaType":protected]=> + ["clientMediaType":"HttpMessage\UploadedFile":private]=> NULL - ["moved":protected]=> + ["moved":"HttpMessage\UploadedFile":private]=> bool(false) - ["checkUploaded":protected]=> + ["checkUploaded":"HttpMessage\UploadedFile":private]=> bool(false) } NULL diff --git a/tests/UploadedFile/__construct_005.phpt b/tests/UploadedFile/__construct_005.phpt new file mode 100644 index 0000000..af79d5a --- /dev/null +++ b/tests/UploadedFile/__construct_005.phpt @@ -0,0 +1,48 @@ +--TEST-- +Create UploadedFile with a stream +--FILE-- +getSize()); +var_dump($upload->getError()); +var_dump($upload->getClientFilename()); +var_dump($upload->getClientMediaType()); + +var_dump($upload->getStream() === $stream); +var_dump($upload->getStream()); + +?> +--EXPECTF-- +object(HttpMessage\UploadedFile)#%d (8) { + ["stream":"HttpMessage\UploadedFile":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["file":"HttpMessage\UploadedFile":private]=> + NULL + ["size":"HttpMessage\UploadedFile":private]=> + NULL + ["error":"HttpMessage\UploadedFile":private]=> + int(0) + ["clientFilename":"HttpMessage\UploadedFile":private]=> + NULL + ["clientMediaType":"HttpMessage\UploadedFile":private]=> + NULL + ["moved":"HttpMessage\UploadedFile":private]=> + bool(false) + ["checkUploaded":"HttpMessage\UploadedFile":private]=> + bool(false) +} +NULL +int(0) +NULL +NULL +bool(true) +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) +} diff --git a/tests/UploadedFile/getStream_001.phpt b/tests/UploadedFile/getStream_001.phpt index df63490..19dbbe6 100644 --- a/tests/UploadedFile/getStream_001.phpt +++ b/tests/UploadedFile/getStream_001.phpt @@ -20,8 +20,8 @@ var_dump($stream == $upload->getStream()); unlink(sys_get_temp_dir() . '/uploadedfile'); ?> --EXPECTF-- -object(HttpMessage\Stream)#2 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } string(%d) "%s/uploadedfile" diff --git a/tests/UploadedFile/getStream_002.phpt b/tests/UploadedFile/getStream_002.phpt index 29d95eb..15d2abc 100644 --- a/tests/UploadedFile/getStream_002.phpt +++ b/tests/UploadedFile/getStream_002.phpt @@ -28,8 +28,8 @@ if (file_exists(sys_get_temp_dir() . '/uploadedfile') { } ?> --EXPECTF-- -object(HttpMessage\Stream)#3 (1) { - ["stream":protected]=> +object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> resource(%d) of type (stream) } string(%d) "%s/uploadedfile" diff --git a/tests/UploadedFile/moveTo_001.phpt b/tests/UploadedFile/moveTo_001.phpt index 3b2b28f..1d62c16 100644 --- a/tests/UploadedFile/moveTo_001.phpt +++ b/tests/UploadedFile/moveTo_001.phpt @@ -15,12 +15,8 @@ var_dump(file_get_contents($target)); ?> --CLEAN-- --EXPECT-- string(3) "foo" \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_002.phpt b/tests/UploadedFile/moveTo_002.phpt index 1645c62..7413256 100644 --- a/tests/UploadedFile/moveTo_002.phpt +++ b/tests/UploadedFile/moveTo_002.phpt @@ -21,9 +21,8 @@ var_dump(file_get_contents($target)); ?> --CLEAN-- --EXPECT-- string(3) "foo" \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_003.phpt b/tests/UploadedFile/moveTo_003.phpt new file mode 100644 index 0000000..b2022e7 --- /dev/null +++ b/tests/UploadedFile/moveTo_003.phpt @@ -0,0 +1,22 @@ +--TEST-- +UploadedFile::moveTo() with stream +--FILE-- +moveTo($target); + +var_dump(file_get_contents($target)); + +?> +--CLEAN-- + +--EXPECT-- +string(3) "foo" \ No newline at end of file diff --git a/tests/Uri/__construct_001.phpt b/tests/Uri/__construct_001.phpt index fe96837..3095ccb 100644 --- a/tests/Uri/__construct_001.phpt +++ b/tests/Uri/__construct_001.phpt @@ -4,20 +4,20 @@ Create Uri without arguments ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/Uri/__construct_002.phpt b/tests/Uri/__construct_002.phpt index 25079c9..b01db3d 100644 --- a/tests/Uri/__construct_002.phpt +++ b/tests/Uri/__construct_002.phpt @@ -4,20 +4,20 @@ Create Uri with a basic url ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(5) "https" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(15) "www.example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/Uri/__construct_003.phpt b/tests/Uri/__construct_003.phpt index 1fbc37a..ebfa8b8 100644 --- a/tests/Uri/__construct_003.phpt +++ b/tests/Uri/__construct_003.phpt @@ -4,20 +4,20 @@ Create Uri with a full url ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(4) "http" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(4) "acme" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(15) "www.example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> int(8000) - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(4) "/foo" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(9) "answer=42" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(8) "question" -} +} \ No newline at end of file diff --git a/tests/Uri/__construct_004.phpt b/tests/Uri/__construct_004.phpt index 7d3e8ff..b472627 100644 --- a/tests/Uri/__construct_004.phpt +++ b/tests/Uri/__construct_004.phpt @@ -4,20 +4,20 @@ Create Uri with username and password ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(5) "https" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(11) "acme:secure" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(15) "www.example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/Uri/__construct_005.phpt b/tests/Uri/__construct_005.phpt index 63a6683..3b5af9f 100644 --- a/tests/Uri/__construct_005.phpt +++ b/tests/Uri/__construct_005.phpt @@ -4,20 +4,20 @@ Create Uri with a basic url without a path ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(5) "https" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(15) "www.example.com" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(0) "" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" -} +} \ No newline at end of file diff --git a/tests/Uri/__construct_006.phpt b/tests/Uri/__construct_006.phpt index 09c478e..17e209b 100644 --- a/tests/Uri/__construct_006.phpt +++ b/tests/Uri/__construct_006.phpt @@ -4,20 +4,20 @@ Create Uri with a domain name ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(15) "www.example.com" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } \ No newline at end of file diff --git a/tests/Uri/__construct_007.phpt b/tests/Uri/__construct_007.phpt index 303af4f..7f965c1 100644 --- a/tests/Uri/__construct_007.phpt +++ b/tests/Uri/__construct_007.phpt @@ -4,20 +4,20 @@ Create Uri with an absolute path ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(4) "/foo" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" } \ No newline at end of file diff --git a/tests/Uri/__construct_008.phpt b/tests/Uri/__construct_008.phpt index a30eaec..92905a0 100644 --- a/tests/Uri/__construct_008.phpt +++ b/tests/Uri/__construct_008.phpt @@ -4,20 +4,20 @@ Create Uri with a relative path ---EXPECT-- -object(HttpMessage\Uri)#1 (7) { - ["scheme":protected]=> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> string(0) "" - ["userInfo":protected]=> + ["userInfo":"HttpMessage\Uri":private]=> string(0) "" - ["host":protected]=> + ["host":"HttpMessage\Uri":private]=> string(0) "" - ["port":protected]=> + ["port":"HttpMessage\Uri":private]=> NULL - ["path":protected]=> + ["path":"HttpMessage\Uri":private]=> string(3) "foo" - ["query":protected]=> + ["query":"HttpMessage\Uri":private]=> string(0) "" - ["fragment":protected]=> + ["fragment":"HttpMessage\Uri":private]=> string(0) "" -} +} \ No newline at end of file diff --git a/uploaded_file.c b/uploaded_file.c index e76dab9..4102e9a 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -46,16 +46,29 @@ zend_class_entry *HttpMessage_UploadedFile_ce = NULL; -int assert_file_available(zval *file, zval *moved) +int assert_file_available(zval *file, zval *stream, zval *moved) { - if (ZVAL_IS_NULL(file)) { + zval stream_file, arg1; + char *filename; + + if ((file == NULL || ZVAL_IS_NULL(file)) && (stream == NULL || ZVAL_IS_NULL(stream))) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "No file was uploaded or uploaded file not available"); return FAILURE; } if (Z_TYPE_P(moved) == IS_TRUE) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Uploaded file '%s' has already been moved", - Z_STRVAL_P(file)); + if (!ZVAL_IS_NULL(file)) { + filename = Z_STRVAL_P(file); + STR_CLOSE(filename, Z_STRLEN_P(file)); + } else { + // Can be any StreamInterface object, doesn't need to be Stream from this lib. + ZVAL_STRINGL(&arg1, "uri", 3); + zend_call_method_with_1_params(stream, NULL, NULL, "getMetadata", &stream_file, &arg1); + filename = Z_STRVAL(stream_file); + STR_CLOSE(filename, Z_STRLEN(stream_file)); + } + + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Uploaded file '%s' has already been moved", filename); return FAILURE; } @@ -91,6 +104,8 @@ int move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_p HashTable *uploaded_files; zend_bool successful = 0; + STR_CLOSE(new_path, new_path_len); + if (php_check_open_basedir_ex(new_path, 1)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to move uploaded file '%s' to '%s'; open_basedir restriction in effect", path, new_path); @@ -121,6 +136,37 @@ int move_uploaded_file(char *path, size_t path_len, char *new_path, size_t new_p return SUCCESS; } +int move_uploaded_stream(zval *stream, char *new_path, size_t new_path_len) +{ + zval resource; + php_stream *source, *target; + size_t len; + int ret; + + // Can be any StreamInterface object, doesn't need to be Stream from this lib. + zend_call_method_with_0_params(stream, NULL, NULL, "detach", &resource); + source = (php_stream*)zend_fetch_resource2_ex(&resource, "stream", php_file_le_stream(), php_file_le_pstream()); + + STR_CLOSE(new_path, new_path_len); + target = php_stream_open_wrapper(new_path, "w", 0, NULL); + + if (EXPECTED(source != NULL && target != NULL)) { + if (source->ops->seek && (source->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { + php_stream_seek(source, 0, SEEK_SET); + }; + + ret = php_stream_copy_to_stream_ex(source, target, PHP_STREAM_COPY_ALL, &len); + } else { + ret = FAILURE; + } + + if (ret == FAILURE) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to stream uploaded file to '%s'", new_path); + } + + return ret; +} + void construct_uploaded_file( zval* object, zval *stream, @@ -131,19 +177,20 @@ void construct_uploaded_file( zend_string *clientMediaType, char checkUploaded ) { - zval zfile, zarg1; + zval zreadable; if (error == 0 && stream != NULL) { // Must be verified it's a StreamInterface object before passing it to this function. - zend_update_property(HttpMessage_UploadedFile_ce, object, ZEND_STRL("stream"), stream); + // Can be any StreamInterface object, doesn't need to be Stream from this lib. + zend_call_method_with_0_params(stream, NULL, NULL, "isReadable", &zreadable); - if (file == NULL) { - ZVAL_STRINGL(&zarg1, "uri", 3); - zend_call_method_with_1_params(stream, NULL, NULL, "getMetadata", &zfile, &zarg1); - file = Z_STR_P(&zfile); + if (UNEXPECTED(Z_TYPE(zreadable) != IS_TRUE)) { + zend_throw_exception( + spl_ce_InvalidArgumentException, "Stream provided for uploaded file is not readable", 0 + ); } - } - if (error == 0 && file != NULL) { + zend_update_property(HttpMessage_UploadedFile_ce, object, ZEND_STRL("stream"), stream); + } else if (error == 0 && file != NULL) { zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("file"), file); } @@ -285,11 +332,11 @@ PHP_METHOD(UploadedFile, __construct) if (Z_TYPE_P(fileOrStream) == IS_STRING) { file = Z_STR_P(fileOrStream); - } else { - stream_interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\streaminterface")); + } else if (Z_TYPE_P(fileOrStream) != IS_NULL) { + stream_interface = HTTP_MESSAGE_PSR_INTERFACE("stream"); if (UNEXPECTED( - Z_TYPE_P(fileOrStream) == IS_OBJECT && instanceof_function(Z_OBJCE_P(fileOrStream), stream_interface) + Z_TYPE_P(fileOrStream) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(fileOrStream), stream_interface) )) { zend_type_error("Expected parameter 1 to be a string or object that implements " "Psr\\Http\\Message\\StreamInterface, %s given", zend_zval_type_name(fileOrStream)); @@ -305,28 +352,20 @@ PHP_METHOD(UploadedFile, __construct) PHP_METHOD(UploadedFile, getStream) { - zval rv, *stream, *file, *moved, resource; - php_stream *resource_stream; - - stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + zval rv, *stream, *file, *moved, mode; file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); + stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); - if (assert_file_available(file, moved) == FAILURE) { + if (assert_file_available(file, stream, moved) == FAILURE) { return; } // Stream isn't set: create new stream for file if (ZVAL_IS_NULL(stream)) { - resource_stream = php_stream_open_wrapper(Z_STRVAL_P(file), "r", 0, NULL); - if (resource_stream == NULL) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to open stream for '%s'", Z_STRVAL_P(file)); - return; - } - - php_stream_to_zval(resource_stream, &resource); - NEW_OBJECT_CONSTRUCT_1(stream, HttpMessage_Stream_ce, &resource); + ZVAL_STRINGL(&mode, "r", 1); + NEW_OBJECT_CONSTRUCT(stream, HttpMessage_Stream_ce, 2, file, &mode); } RETURN_ZVAL(stream, 1, 0); @@ -334,9 +373,9 @@ PHP_METHOD(UploadedFile, getStream) PHP_METHOD(UploadedFile, moveTo) { - zval rv, *file, *moved, *checkUploaded; - char *new_path; - size_t new_path_len; + zval rv, *file, *moved, *stream, *checkUploaded; + char *new_path = NULL; + size_t new_path_len = 0; int move_ret; ZEND_PARSE_PARAMETERS_START(1, 1) @@ -344,17 +383,23 @@ PHP_METHOD(UploadedFile, moveTo) ZEND_PARSE_PARAMETERS_END(); file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); + stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); checkUploaded = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("checkUploaded"), 0, &rv); if ( - assert_file_available(file, moved) == FAILURE || - (Z_TYPE_P(checkUploaded) == IS_TRUE && assert_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file)) == FAILURE) + assert_file_available(file, stream, moved) == FAILURE || + (Z_TYPE_P(checkUploaded) == IS_TRUE && assert_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file) == FAILURE)) ) { return; } - move_ret = move_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file), new_path, new_path_len); + if (!ZVAL_IS_NULL(file)) { + move_ret = move_uploaded_file(Z_STRVAL_P(file), Z_STRLEN_P(file), new_path, new_path_len); + } else { + move_ret = move_uploaded_stream(stream, new_path, new_path_len); + } + ZVAL_BOOL(moved, move_ret == SUCCESS); } @@ -410,7 +455,7 @@ static const zend_function_entry methods[] = { PHP_MINIT_FUNCTION(http_message_uploadedfile) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uploadedfileinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("uploadedfile"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "UploadedFile"); @@ -420,15 +465,15 @@ PHP_MINIT_FUNCTION(http_message_uploadedfile) zend_class_implements(HttpMessage_UploadedFile_ce, 1, interface); /* Properties */ - zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("stream"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("file"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("size"), ZEND_ACC_PROTECTED); - zend_declare_property_long(HttpMessage_UploadedFile_ce, ZEND_STRL("error"), 0, ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientFilename"), ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientMediaType"), ZEND_ACC_PROTECTED); - - zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("moved"), 0, ZEND_ACC_PROTECTED); - zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("checkUploaded"), 0, ZEND_ACC_PROTECTED); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("stream"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("file"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("size"), ZEND_ACC_PRIVATE); + zend_declare_property_long(HttpMessage_UploadedFile_ce, ZEND_STRL("error"), 0, ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientFilename"), ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_UploadedFile_ce, ZEND_STRL("clientMediaType"), ZEND_ACC_PRIVATE); + + zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("moved"), 0, ZEND_ACC_PRIVATE); + zend_declare_property_bool(HttpMessage_UploadedFile_ce, ZEND_STRL("checkUploaded"), 0, ZEND_ACC_PRIVATE); return SUCCESS; } diff --git a/uri.c b/uri.c index c02267d..a0ee490 100644 --- a/uri.c +++ b/uri.c @@ -77,7 +77,7 @@ ZEND_END_ARG_INFO() PHP_METHOD(Uri, __construct) { php_url *info; - char *value; + char *value = NULL; size_t value_len = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) @@ -201,16 +201,15 @@ PHP_METHOD(Uri, getScheme) PHP_METHOD(Uri, withScheme) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("scheme"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("scheme"), value); } @@ -259,16 +258,15 @@ PHP_METHOD(Uri, getUserInfo) PHP_METHOD(Uri, withUserInfo) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("userInfo"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("userInfo"), value); } @@ -285,16 +283,15 @@ PHP_METHOD(Uri, getHost) PHP_METHOD(Uri, withHost) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("host"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("host"), value); } @@ -311,19 +308,19 @@ PHP_METHOD(Uri, getPort) PHP_METHOD(Uri, withPort) { - long value; - zend_bool is_null; + zend_long value = 0; + zend_bool value_is_null = 1; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_LONG_EX(value, is_null, 1, 0) + Z_PARAM_LONG_EX(value, value_is_null,1, 0) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - if (is_null) { - zend_update_property_null(HttpMessage_Uri_ce, return_value, ZEND_STRL("port")); - } else { + if (!value_is_null) { zend_update_property_long(HttpMessage_Uri_ce, return_value, ZEND_STRL("port"), value); + } else { + zend_update_property_null(HttpMessage_Uri_ce, return_value, ZEND_STRL("port")); } } @@ -341,16 +338,15 @@ PHP_METHOD(Uri, getPath) PHP_METHOD(Uri, withPath) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("path"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("path"), value); } @@ -367,16 +363,15 @@ PHP_METHOD(Uri, getQuery) PHP_METHOD(Uri, withQuery) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("query"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("query"), value); } @@ -393,16 +388,15 @@ PHP_METHOD(Uri, getFragment) PHP_METHOD(Uri, withFragment) { - char *value; - size_t value_len; + zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); - zend_update_property_stringl(HttpMessage_Uri_ce, return_value, ZEND_STRL("fragment"), value, value_len); + zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("fragment"), value); } @@ -432,7 +426,7 @@ static const zend_function_entry uri_functions[] = { PHP_MINIT_FUNCTION(http_message_uri) { zend_class_entry ce; - zend_class_entry *interface = get_internal_ce(ZEND_STRL("psr\\http\\message\\uriinterface")); + zend_class_entry *interface = HTTP_MESSAGE_PSR_INTERFACE("uri"); ASSERT_HTTP_MESSAGE_INTERFACE_FOUND(interface, "Uri"); @@ -442,13 +436,13 @@ PHP_MINIT_FUNCTION(http_message_uri) zend_class_implements(HttpMessage_Uri_ce, 1, interface); /* Properties */ - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("scheme"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("userInfo"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("host"), "", ZEND_ACC_PROTECTED); - zend_declare_property_null(HttpMessage_Uri_ce, ZEND_STRL("port"), ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("path"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("query"), "", ZEND_ACC_PROTECTED); - zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("fragment"), "", ZEND_ACC_PROTECTED); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("scheme"), "", ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("userInfo"), "", ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("host"), "", ZEND_ACC_PRIVATE); + zend_declare_property_null(HttpMessage_Uri_ce, ZEND_STRL("port"), ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("path"), "", ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("query"), "", ZEND_ACC_PRIVATE); + zend_declare_property_string(HttpMessage_Uri_ce, ZEND_STRL("fragment"), "", ZEND_ACC_PRIVATE); return SUCCESS; } From e6ab2c18957510cf5b521751e9f05d895b083ed0 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 3 Sep 2019 00:39:07 +0200 Subject: [PATCH 45/67] Tests and minor fixes for invalid arguments --- factory.c | 7 ++- macros.h | 13 +++++ response.c | 2 +- stream.c | 2 +- tests/Factory/createResponse_004.phpt | 27 ++++++++++ tests/Factory/createResponse_err01.phpt | 22 ++++++++ tests/Factory/createResponse_err02.phpt | 15 ++++++ tests/Factory/createServerRequest_err01.phpt | 36 +++++++++++++ tests/Factory/createStreamFromFile_002.phpt | 49 +++++------------- tests/Factory/createStreamFromFile_err01.phpt | 22 ++++++++ tests/Factory/createStreamFromFile_err02.phpt | 15 ++++++ .../createStreamFromResource_err01.phpt | 15 ++++++ .../createStreamFromResource_err02.phpt | 18 +++++++ tests/Factory/createStream_err01.phpt | 15 ++++++ tests/Factory/createUploadedFile_err01.phpt | 51 +++++++++++++++++++ tests/Factory/createUploadedFile_err02.phpt | 20 ++++++++ tests/Response/status_004.phpt | 14 +++++ tests/Response/status_err02.phpt | 15 ++++++ tests/ServerRequest/__construct_err01.phpt | 49 ++++++++++++++++++ tests/Stream/__construct_err03.phpt | 12 +++++ tests/UploadedFile/__construct_err01.phpt | 50 ++++++++++++++++++ tests/UploadedFile/__construct_err02.phpt | 15 ++++++ tests/UploadedFile/getStream_err03.phpt | 14 +++++ tests/UploadedFile/moveTo_err05.phpt | 22 ++++++++ uploaded_file.c | 12 +++-- 25 files changed, 488 insertions(+), 44 deletions(-) create mode 100644 tests/Factory/createResponse_004.phpt create mode 100644 tests/Factory/createResponse_err01.phpt create mode 100644 tests/Factory/createResponse_err02.phpt create mode 100644 tests/Factory/createServerRequest_err01.phpt create mode 100644 tests/Factory/createStreamFromFile_err01.phpt create mode 100644 tests/Factory/createStreamFromFile_err02.phpt create mode 100644 tests/Factory/createStreamFromResource_err01.phpt create mode 100644 tests/Factory/createStreamFromResource_err02.phpt create mode 100644 tests/Factory/createStream_err01.phpt create mode 100644 tests/Factory/createUploadedFile_err01.phpt create mode 100644 tests/Factory/createUploadedFile_err02.phpt create mode 100644 tests/Response/status_004.phpt create mode 100644 tests/Response/status_err02.phpt create mode 100644 tests/ServerRequest/__construct_err01.phpt create mode 100644 tests/Stream/__construct_err03.phpt create mode 100644 tests/UploadedFile/__construct_err01.phpt create mode 100644 tests/UploadedFile/__construct_err02.phpt create mode 100644 tests/UploadedFile/getStream_err03.phpt create mode 100644 tests/UploadedFile/moveTo_err05.phpt diff --git a/factory.c b/factory.c index 21d7445..d60526b 100644 --- a/factory.c +++ b/factory.c @@ -42,6 +42,7 @@ #include "zend_interfaces.h" #include "zend_string.h" #include "ext/psr/psr_http_factory.h" +#include "ext/spl/spl_exceptions.h" #if HAVE_HTTP_MESSAGE @@ -61,8 +62,7 @@ int uri_param_as_object(zval *uri) ZVAL_COPY(&uri_str, uri); NEW_OBJECT_CONSTRUCT(uri, HttpMessage_Uri_ce, 1, &uri_str); } else if (UNEXPECTED(Z_TYPE_P(uri) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(uri), uri_interface))) { - zend_type_error("Expected parameter 1 to be a string or object that implements " - "Psr\\Http\\Message\\UriInterface, %s given", zend_zval_type_name(uri)); + custom_parameter_type_error(1, "a string or object that implements Psr\\Http\\Message\\UriInterface", uri); return FAILURE; } @@ -91,7 +91,6 @@ PHP_METHOD(Factory, createResponse) zend_long code = 200; zend_bool code_is_null = 0; zend_string *phrase = NULL; - const char *suggested_phrase; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 2) Z_PARAM_OPTIONAL @@ -165,7 +164,7 @@ PHP_METHOD(Factory, createStreamFromFile) stream = php_stream_open_wrapper(file, mode != NULL ? mode : "r", 0, NULL); if (stream == NULL) { - zend_throw_error(NULL, "Failed to open '%s' stream", file); + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to open '%s' stream", file); return; } diff --git a/macros.h b/macros.h index 8989ee6..403e2e8 100644 --- a/macros.h +++ b/macros.h @@ -119,6 +119,19 @@ static zend_always_inline zend_class_entry* get_internal_ce(const char *class_na return temp_ce; } +static zend_always_inline void custom_parameter_type_error(int num, char *expected, zval *arg) +{ + const char *space; + const char *class_name; + + if (EG(exception)) { + return; + } + class_name = get_active_class_name(&space); + zend_type_error("%s%s%s() expects parameter %d to be %s, %s given", + class_name, space, get_active_function_name(), num, expected, zend_zval_type_name(arg)); +} + #define ASSERT_HTTP_MESSAGE_INTERFACE_FOUND_EX(ce, className, psrClassName) \ if (UNEXPECTED(ce == NULL)) { \ zend_error(E_CORE_WARNING, \ diff --git a/response.c b/response.c index 150a65f..0bb9a2f 100644 --- a/response.c +++ b/response.c @@ -50,7 +50,7 @@ int response_set_status(zval *obj, zend_long code, zend_string *phrase) const char *suggested_phrase; if (code < 100 || code > 999) { - zend_throw_exception(spl_ce_InvalidArgumentException, "Invalid HTTP status code %ld", code); + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid HTTP status code %ld", code); return FAILURE; } diff --git a/stream.c b/stream.c index f3f69b4..963a2e2 100644 --- a/stream.c +++ b/stream.c @@ -103,7 +103,7 @@ PHP_METHOD(Stream, __construct) stream = php_stream_open_wrapper(file, mode != NULL ? mode : "r", 0, NULL); if (stream == NULL) { - zend_throw_error(NULL, "Failed to open '%s' stream", file); + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Failed to open '%s' stream", file); return; } diff --git a/tests/Factory/createResponse_004.phpt b/tests/Factory/createResponse_004.phpt new file mode 100644 index 0000000..b02e157 --- /dev/null +++ b/tests/Factory/createResponse_004.phpt @@ -0,0 +1,27 @@ +--TEST-- +Factory::createResponse() with unknown status code +--FILE-- +createResponse(990); +var_dump($response); + +?> +--EXPECTF-- +object(HttpMessage\Response)#%d (5) { + ["protocolVersion":"HttpMessage\Message":private]=> + string(3) "1.1" + ["headers":"HttpMessage\Message":private]=> + array(0) { + } + ["body":"HttpMessage\Message":private]=> + object(HttpMessage\Stream)#%d (1) { + ["stream":"HttpMessage\Stream":private]=> + resource(%d) of type (stream) + } + ["statusCode":"HttpMessage\Response":private]=> + int(990) + ["reasonPhrase":"HttpMessage\Response":private]=> + string(0) "" +} \ No newline at end of file diff --git a/tests/Factory/createResponse_err01.phpt b/tests/Factory/createResponse_err01.phpt new file mode 100644 index 0000000..84cbda0 --- /dev/null +++ b/tests/Factory/createResponse_err01.phpt @@ -0,0 +1,22 @@ +--TEST-- +Factory::createResponse() with invalid arguments +--FILE-- +createResponse('ok'); +} catch (TypeError $e) { + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; +} + +try { + $factory->createResponse(200, ['foo', 'bar']); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Factory::createResponse() must be of the type int, string given +Argument 2 passed to HttpMessage\Factory::createResponse() must be of the type string, array given diff --git a/tests/Factory/createResponse_err02.phpt b/tests/Factory/createResponse_err02.phpt new file mode 100644 index 0000000..cc262bc --- /dev/null +++ b/tests/Factory/createResponse_err02.phpt @@ -0,0 +1,15 @@ +--TEST-- +Factory::createResponse() with invalid status code +--FILE-- +createResponse(-1); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Invalid HTTP status code -1 \ No newline at end of file diff --git a/tests/Factory/createServerRequest_err01.phpt b/tests/Factory/createServerRequest_err01.phpt new file mode 100644 index 0000000..a36e8a7 --- /dev/null +++ b/tests/Factory/createServerRequest_err01.phpt @@ -0,0 +1,36 @@ +--TEST-- +Factory::createServerRequest() with invalid arguments +--FILE-- +createServerRequest(); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request = $factory->createServerRequest(42); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request = $factory->createServerRequest("GET", []); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $request = $factory->createServerRequest("GET", "http://www.example.com/", "hello"); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 0 given +HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 1 given +HttpMessage\Factory::createServerRequest() expects parameter 1 to be a string or object that implements Psr\Http\Message\UriInterface, array given +Argument 3 passed to HttpMessage\Factory::createServerRequest() must be of the type array, string given diff --git a/tests/Factory/createStreamFromFile_002.phpt b/tests/Factory/createStreamFromFile_002.phpt index 80178e3..3fe8934 100644 --- a/tests/Factory/createStreamFromFile_002.phpt +++ b/tests/Factory/createStreamFromFile_002.phpt @@ -1,43 +1,22 @@ --TEST-- -Factory::createStreamFromFile() +Factory::createStreamFromFile() with mode --FILE-- createStreamFromFile(__FILE__, "r+"); -var_dump($stream); - -$resource = $stream->detach(); -var_dump(stream_get_meta_data($resource)); +try { + $stream = $factory->createStreamFromFile([]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} -fseek($resource, 0); -var_dump(fread($resource, 16)); +try { + $stream = $factory->createStreamFromFile(__FILE__, []); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} ?> ---EXPECTF-- -object(HttpMessage\Stream)#%d (1) { - ["stream":"HttpMessage\Stream":private]=> - resource(%d) of type (stream) -} -array(9) { - ["timed_out"]=> - bool(false) - ["blocked"]=> - bool(true) - ["eof"]=> - bool(false) - ["wrapper_type"]=> - string(9) "plainfile" - ["stream_type"]=> - string(5) "STDIO" - ["mode"]=> - string(2) "r+" - ["unread_bytes"]=> - int(0) - ["seekable"]=> - bool(true) - ["uri"]=> - string(%d) "%screateStreamFromFile_002.php" -} -string(16) "createStreamFromFile([]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $factory->createStreamFromFile(__FILE__, []); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given +Argument 2 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given \ No newline at end of file diff --git a/tests/Factory/createStreamFromFile_err02.phpt b/tests/Factory/createStreamFromFile_err02.phpt new file mode 100644 index 0000000..688463f --- /dev/null +++ b/tests/Factory/createStreamFromFile_err02.phpt @@ -0,0 +1,15 @@ +--TEST-- +Factory::createStreamFromFile() with non-existing file +--FILE-- +createStreamFromFile(__DIR__ . '/not/exists'); +} catch (RuntimeException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Failed to open '/home/arnold/Projects/php/http-message/tests/Factory/not/exists' stream \ No newline at end of file diff --git a/tests/Factory/createStreamFromResource_err01.phpt b/tests/Factory/createStreamFromResource_err01.phpt new file mode 100644 index 0000000..73ce60c --- /dev/null +++ b/tests/Factory/createStreamFromResource_err01.phpt @@ -0,0 +1,15 @@ +--TEST-- +Factory::createStreamFromResource() with invalid argument +--FILE-- +createStreamFromResource([]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Expected parameter 1 to be a string or resource, array given \ No newline at end of file diff --git a/tests/Factory/createStreamFromResource_err02.phpt b/tests/Factory/createStreamFromResource_err02.phpt new file mode 100644 index 0000000..ce9104f --- /dev/null +++ b/tests/Factory/createStreamFromResource_err02.phpt @@ -0,0 +1,18 @@ +--TEST-- +Factory::createStreamFromResource() with closed stream +--FILE-- +createStreamFromResource($resource); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Resource is not a stream diff --git a/tests/Factory/createStream_err01.phpt b/tests/Factory/createStream_err01.phpt new file mode 100644 index 0000000..4cff867 --- /dev/null +++ b/tests/Factory/createStream_err01.phpt @@ -0,0 +1,15 @@ +--TEST-- +Factory::createStream() with invalid argument +--FILE-- +createStream([]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Factory::createStream() must be of the type string, array given \ No newline at end of file diff --git a/tests/Factory/createUploadedFile_err01.phpt b/tests/Factory/createUploadedFile_err01.phpt new file mode 100644 index 0000000..73cced9 --- /dev/null +++ b/tests/Factory/createUploadedFile_err01.phpt @@ -0,0 +1,51 @@ +--TEST-- +Factory::createUploadedFile() with invalid argument +--FILE-- +createUploadedFile('foo'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $factory->createUploadedFile((object)[]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $factory->createUploadedFile($stream, [], UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); +} catch (TypeError $e) { + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; +} + +try { + $factory->createUploadedFile($stream, 99, [], 'myfile.txt', 'text/plain'); +} catch (TypeError $e) { + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; +} + +try { + $factory->createUploadedFile($stream, 99, UPLOAD_ERR_OK, [], 'text/plain'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $factory->createUploadedFile($stream, 99, UPLOAD_ERR_OK, 'myfile.txt', []); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\Factory::createUploadedFile() must implement interface Psr\Http\Message\StreamInterface, string given +Argument 1 passed to HttpMessage\Factory::createUploadedFile() must implement interface Psr\Http\Message\StreamInterface, instance of stdClass given +Argument 2 passed to HttpMessage\Factory::createUploadedFile() must be of the type int or null, array given +Argument 3 passed to HttpMessage\Factory::createUploadedFile() must be of the type int, array given +Argument 4 passed to HttpMessage\Factory::createUploadedFile() must be of the type string or null, array given +Argument 5 passed to HttpMessage\Factory::createUploadedFile() must be of the type string or null, array given \ No newline at end of file diff --git a/tests/Factory/createUploadedFile_err02.phpt b/tests/Factory/createUploadedFile_err02.phpt new file mode 100644 index 0000000..5065000 --- /dev/null +++ b/tests/Factory/createUploadedFile_err02.phpt @@ -0,0 +1,20 @@ +--TEST-- +Factory::createUploadedFile() with non-readable stream +--FILE-- +createUploadedFile($stream); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--CLEAN-- + +--EXPECT-- +Stream provided for uploaded file is not readable \ No newline at end of file diff --git a/tests/Response/status_004.phpt b/tests/Response/status_004.phpt new file mode 100644 index 0000000..75e0b0f --- /dev/null +++ b/tests/Response/status_004.phpt @@ -0,0 +1,14 @@ +--TEST-- +Response::withStatus() with an unknown status code +--FILE-- +withStatus(990); +var_dump($newResponse->getStatusCode()); +var_dump($newResponse->getReasonPhrase()); + +?> +--EXPECT-- +int(990) +string(0) "" \ No newline at end of file diff --git a/tests/Response/status_err02.phpt b/tests/Response/status_err02.phpt new file mode 100644 index 0000000..f5040de --- /dev/null +++ b/tests/Response/status_err02.phpt @@ -0,0 +1,15 @@ +--TEST-- +Response::withStatus() with invalid status code +--FILE-- +withStatus(-1); +} catch (InvalidArgumentException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Invalid HTTP status code -1 diff --git a/tests/ServerRequest/__construct_err01.phpt b/tests/ServerRequest/__construct_err01.phpt new file mode 100644 index 0000000..358d824 --- /dev/null +++ b/tests/ServerRequest/__construct_err01.phpt @@ -0,0 +1,49 @@ +--TEST-- +Create ServerRequest with invalid arguments +--FILE-- +getMessage(), "\n"; +} + +try { + new HttpMessage\ServerRequest([], ''); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\ServerRequest([], [], ''); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\ServerRequest([], [], ''); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\ServerRequest([], [], [], ''); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\ServerRequest([], [], [], [], ''); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Argument 1 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +Argument 2 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +Argument 3 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +Argument 3 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +Argument 4 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +Argument 5 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given diff --git a/tests/Stream/__construct_err03.phpt b/tests/Stream/__construct_err03.phpt new file mode 100644 index 0000000..979d8e8 --- /dev/null +++ b/tests/Stream/__construct_err03.phpt @@ -0,0 +1,12 @@ +--TEST-- +Create Stream with non-existing file +--FILE-- +getMessage(), [DIRECTORY_SEPARATOR => '/']); +} +?> +--EXPECTF-- +Failed to open '%s/Stream/not/exists' stream diff --git a/tests/UploadedFile/__construct_err01.phpt b/tests/UploadedFile/__construct_err01.phpt new file mode 100644 index 0000000..35677d6 --- /dev/null +++ b/tests/UploadedFile/__construct_err01.phpt @@ -0,0 +1,50 @@ +--TEST-- +Create UploadedFile with invalid arguments +--FILE-- +getMessage(), "\n"; +} + +try { + new HttpMessage\UploadedFile((object)[]); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\UploadedFile($stream, [], UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +try { + new HttpMessage\UploadedFile($stream, 99, [], 'myfile.txt', 'text/plain'); +} catch (TypeError $e) { + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; +} + +try { + new HttpMessage\UploadedFile($stream, 99, UPLOAD_ERR_OK, [], 'text/plain'); +} catch (TypeError $e) { + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; +} + +try { + new HttpMessage\UploadedFile($stream, 99, UPLOAD_ERR_OK, 'myfile.txt', []); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +HttpMessage\UploadedFile::__construct() expects parameter 1 to be a string or object that implements Psr\Http\Message\StreamInterface, array given +HttpMessage\UploadedFile::__construct() expects parameter 1 to be a string or object that implements Psr\Http\Message\StreamInterface, object given +Argument 2 passed to HttpMessage\UploadedFile::__construct() must be of the type int or null, array given +Argument 3 passed to HttpMessage\UploadedFile::__construct() must be of the type int, array given +Argument 4 passed to HttpMessage\UploadedFile::__construct() must be of the type string or null, array given +Argument 5 passed to HttpMessage\UploadedFile::__construct() must be of the type string or null, array given \ No newline at end of file diff --git a/tests/UploadedFile/__construct_err02.phpt b/tests/UploadedFile/__construct_err02.phpt new file mode 100644 index 0000000..94233fc --- /dev/null +++ b/tests/UploadedFile/__construct_err02.phpt @@ -0,0 +1,15 @@ +--TEST-- +Create UploadedFile with a non-readable stream +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Stream provided for uploaded file is not readable \ No newline at end of file diff --git a/tests/UploadedFile/getStream_err03.phpt b/tests/UploadedFile/getStream_err03.phpt new file mode 100644 index 0000000..1658cd1 --- /dev/null +++ b/tests/UploadedFile/getStream_err03.phpt @@ -0,0 +1,14 @@ +--TEST-- +UploadedFile::getStream() with non-existing file +--FILE-- +getStream(); +} catch (RuntimeException $e) { + echo strtr($e->getMessage(), [DIRECTORY_SEPARATOR => '/']), "\n"; +} +?> +--EXPECTF-- +Failed to open '%s/UploadedFile/not/exist' stream \ No newline at end of file diff --git a/tests/UploadedFile/moveTo_err05.phpt b/tests/UploadedFile/moveTo_err05.phpt new file mode 100644 index 0000000..12ea517 --- /dev/null +++ b/tests/UploadedFile/moveTo_err05.phpt @@ -0,0 +1,22 @@ +--TEST-- +UploadedFile::moveTo() with non-existing file +--FILE-- +moveTo(sys_get_temp_dir() . '/movedfile'); +} catch (RuntimeException $e) { + echo strtr($e->getMessage(), [DIRECTORY_SEPARATOR => '/']), "\n"; +} + +?> +--CLEAN-- + +--EXPECTF-- +Warning: HttpMessage\UploadedFile::moveTo(%s): failed to open stream: No such file or directory in %s on line %d +Failed to move uploaded file '%s/UploadedFile/not/exist' to '%s/movedfile' diff --git a/uploaded_file.c b/uploaded_file.c index 4102e9a..0b2b60b 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -335,11 +335,17 @@ PHP_METHOD(UploadedFile, __construct) } else if (Z_TYPE_P(fileOrStream) != IS_NULL) { stream_interface = HTTP_MESSAGE_PSR_INTERFACE("stream"); + if (UNEXPECTED(stream_interface == NULL)) { + zend_throw_error(NULL, "Psr\\Http\\Message\\StreamInterface not found"); + return; + } + if (UNEXPECTED( - Z_TYPE_P(fileOrStream) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(fileOrStream), stream_interface) + Z_TYPE_P(fileOrStream) != IS_OBJECT || + !instanceof_function(Z_OBJCE_P(fileOrStream), stream_interface) )) { - zend_type_error("Expected parameter 1 to be a string or object that implements " - "Psr\\Http\\Message\\StreamInterface, %s given", zend_zval_type_name(fileOrStream)); + custom_parameter_type_error(1, + "a string or object that implements Psr\\Http\\Message\\StreamInterface", fileOrStream); return; } From 329a08d61ed19fd4c790f2f471389de48be9d078 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 3 Sep 2019 00:48:10 +0200 Subject: [PATCH 46/67] Travis fixup --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7083d6e..a7bdaa6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,8 @@ script: after_failure: - | for FILE in $(find tests -name '*.diff'); do - echo $FILE - cat FILE + echo "$FILE" + cat "$FILE" echo done From 2b8c31c917230855b91238dd5ba32893b4244f53 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 3 Sep 2019 01:04:15 +0200 Subject: [PATCH 47/67] Fix test expected paths --- tests/Factory/createStreamFromFile_err02.phpt | 6 +++--- tests/Stream/getMetadata_003.phpt | 2 +- tests/UploadedFile/__construct_err01.phpt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Factory/createStreamFromFile_err02.phpt b/tests/Factory/createStreamFromFile_err02.phpt index 688463f..ffba733 100644 --- a/tests/Factory/createStreamFromFile_err02.phpt +++ b/tests/Factory/createStreamFromFile_err02.phpt @@ -7,9 +7,9 @@ $factory = new HttpMessage\Factory(); try { $factory->createStreamFromFile(__DIR__ . '/not/exists'); } catch (RuntimeException $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), [DIRECTORY_SEPARATOR => '/']), "\n"; } ?> ---EXPECT-- -Failed to open '/home/arnold/Projects/php/http-message/tests/Factory/not/exists' stream \ No newline at end of file +--EXPECTF-- +Failed to open '%s/Factory/not/exists' stream \ No newline at end of file diff --git a/tests/Stream/getMetadata_003.phpt b/tests/Stream/getMetadata_003.phpt index 74525e1..2a33d28 100644 --- a/tests/Stream/getMetadata_003.phpt +++ b/tests/Stream/getMetadata_003.phpt @@ -26,5 +26,5 @@ array(9) { ["seekable"]=> bool(true) ["uri"]=> - string(71) "%sgetMetadata_003.php" + string(%d) "%sgetMetadata_003.php" } diff --git a/tests/UploadedFile/__construct_err01.phpt b/tests/UploadedFile/__construct_err01.phpt index 35677d6..6095895 100644 --- a/tests/UploadedFile/__construct_err01.phpt +++ b/tests/UploadedFile/__construct_err01.phpt @@ -19,7 +19,7 @@ try { try { new HttpMessage\UploadedFile($stream, [], UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; } try { @@ -31,7 +31,7 @@ try { try { new HttpMessage\UploadedFile($stream, 99, UPLOAD_ERR_OK, [], 'text/plain'); } catch (TypeError $e) { - echo strtr($e->getMessage(), ['integer' => 'int']), "\n"; + echo $e->getMessage(), "\n"; } try { From 4645637c90877b3e005e689b77cb3804da1ba69b Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 3 Sep 2019 01:23:26 +0200 Subject: [PATCH 48/67] Fix for Variadic Macros --- macros.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/macros.h b/macros.h index 403e2e8..51175f7 100644 --- a/macros.h +++ b/macros.h @@ -68,12 +68,17 @@ ZEND_END_ARG_INFO() object_init_ex(zval, ce); \ if (EXPECTED(zval != NULL)) object_properties_init(Z_OBJ_P(zval), ce) +#ifndef PHP_WIN32 #define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ NEW_OBJECT(zval, ce); \ if (EXPECTED(zval != NULL)) \ - zend_call_method_with_## argc ##_params( \ - zval, ce, &ce->constructor, "__construct", NULL, ##__VA_ARGS__ \ - ) + zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, ## __VA_ARGS__) +#else +#define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ + NEW_OBJECT(zval, ce); \ + if (EXPECTED(zval != NULL)) \ + zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, __VA_ARGS__) +#endif #define IS_STREAM_RESOURCE(zstream) \ ( \ From a06b8635c90614df1c2c454fe158550b17e9e2a0 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 3 Sep 2019 01:50:24 +0200 Subject: [PATCH 49/67] MSVC variadic macro --- macros.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/macros.h b/macros.h index 51175f7..58af012 100644 --- a/macros.h +++ b/macros.h @@ -33,6 +33,8 @@ #ifndef HTTP_MESSAGE_MACROS_H #define HTTP_MESSAGE_MACROS_H +#define EXPAND( x ) x + ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, 0, 0) ZEND_END_ARG_INFO() @@ -68,17 +70,10 @@ ZEND_END_ARG_INFO() object_init_ex(zval, ce); \ if (EXPECTED(zval != NULL)) object_properties_init(Z_OBJ_P(zval), ce) -#ifndef PHP_WIN32 -#define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ - NEW_OBJECT(zval, ce); \ - if (EXPECTED(zval != NULL)) \ - zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, ## __VA_ARGS__) -#else #define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ NEW_OBJECT(zval, ce); \ if (EXPECTED(zval != NULL)) \ - zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, __VA_ARGS__) -#endif + EXPAND(zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, ## __VA_ARGS__)) #define IS_STREAM_RESOURCE(zstream) \ ( \ From f3cb280a68aa3454b6bdfcf356d0e9741b867376 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 5 Sep 2019 03:20:46 +0200 Subject: [PATCH 50/67] Added script to support `make package.xml` --- Makefile.frag | 3 + build-packagexml.php | 423 +++++++++++++++++++++++++++++++++++++++++++ composer.json | 8 - 3 files changed, 426 insertions(+), 8 deletions(-) create mode 100644 build-packagexml.php delete mode 100644 composer.json diff --git a/Makefile.frag b/Makefile.frag index d2bf0cc..8177ecd 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -20,3 +20,6 @@ mrproper: clean configure configure.ac install-sh libtool ltmain.sh Makefile Makefile.fragments Makefile.global \ Makefile.objects missing mkinstalldirs run-tests.php +package.xml: php_$(PHP_PECL_EXTENSION).h + $(PHP_EXECUTABLE) build-packagexml.php + diff --git a/build-packagexml.php b/build-packagexml.php new file mode 100644 index 0000000..c751554 --- /dev/null +++ b/build-packagexml.php @@ -0,0 +1,423 @@ + + * @license PHP License + * @license MIT + */ + +declare (strict_types = 1); + +set_exception_handler(function (Throwable $exception): void { + $msg = ($exception instanceof RuntimeException ? "" : "Unexpected error: ") . $exception->getMessage(); + + fwrite(STDERR, "\033[0;31m" /* red */ . $msg . "\033[0m" . "\n"); + exit(1); +}); + +if (!extension_loaded('dom') || !extension_loaded('simplexml') || !extension_loaded('spl')) { + throw new RuntimeException("Following extensions are required: DOM, SimpleXML and SPL"); +} + +// 1. Load package.xml and create release +$package = (function (): PackageXMLElement { + return file_exists('package.xml') + ? simplexml_load_file('package.xml', PackageXMLElement::class) + : PackageXMLElement::create(); +})(); + +$release = new Release(); + +// 2. Process php_{extname}.h +(function () use ($package, $release): void { + $extname = (string)$package->name ?: getenv('PHP_PECL_EXTENSION') ?: null; + $filename = $extname !== null ? "php_{$extname}.h" : (glob('php_*.h')[0] ?? null); + + if (!file_exists($filename)) { + throw new RuntimeException("{$filename} not found"); + } + + $macroPrefix = strtoupper(pathinfo($filename, PATHINFO_FILENAME)); + $contents = file_get_contents($filename); + + preg_match_all("/^[ \t]*#define\s+{$macroPrefix}_(?\w+)[ \t]+\"(?.+)\"/m", $contents, $matches, + PREG_PATTERN_ORDER); + $macros = array_combine($matches['key'], $matches['value']); + + // Package name + if (!isset($macros['EXTNAME'])) { + throw new RuntimeException("$filename does not contain '{$macroPrefix}_EXTNAME' macro"); + } + if ((string)$package->name !== '' && (string)$package->name !== $macros['EXTNAME']) { + throw new RuntimeException("Package name '{$package->name}' (package.xml) doesn't match " + . "{$macroPrefix}_EXTNAME '{$macros['EXTNAME']}' ($filename)"); + } + $package->name = $macros['EXTNAME']; + + // Release version + if (!isset($macros['VERSION'])) { + throw new RuntimeException("$filename does not contain {$macroPrefix}_VERSION macro"); + } + $release->version = $macros['VERSION']; + if ($release->existsIn($package->changelog)) { + throw new RuntimeException("Version {$macros['VERSION']} already released. " + . "Please change {$macroPrefix}_VERSION in $filename."); + } +})(); + +// 3. Copy info from package to release +(function () use ($package, $release): void { + $release->license = (string)$package->license; + $release->licenseUri = (string)$package->license['uri']; + + if (strpos($release->version, 'alpha') !== false) { + $release->stability = 'alpha'; + } else if (strpos($release->version, 'beta') !== false || strpos($release->version, 'RC') !== false) { + $release->stability = 'beta'; + } else if (substr($release->version, 0, 1) === '0') { + $release->stability = ((string)$package->stability->release) ?: 'alpha'; + } else { + $release->stability = 'stable'; + } + + if ($release->isMajor((string)$package->version->release)) { + $release->apiVersion = $release->version; + $release->apiStability = $release->stability; + } else { + $release->apiVersion = (string)$package->version->api; + $release->apiStability = (string)$package->stability->api; + } +})(); + +// 4. Get release notes from stdin +$release->notes = (function (string $name, string $version): string { + if (function_exists('posix_isatty') && posix_isatty(STDIN)) { + fwrite(STDOUT, "Enter the release notes for $name $version (end with Ctrl-D):\n"); + } + + $notes = ''; + + do { + $notes .= fread(STDIN, 1024); + } while (!feof(STDIN)); + + return trim($notes); +})((string)$package->name, $release->version); + +// 5. Add release to package +$release->update($package->changelog->prependChild('release')); +$release->update($package); + +// 6. Removes files that no longer exist from package.xml +(function () use ($package): void { + $fileElements = $package->xpath('p:contents//p:file'); + + foreach ($fileElements as $element) { + $path = join("/", array_map('strval', $element->xpath('ancestor-or-self::*[@name!="/"]/@name'))); + + if (!file_exists($path)) { + unset($element[0]); + } + }; +})(); + +// 7. Add new files to package.xml +(function () use ($package): void { + $ext = ['c', 'h', 'phpt']; + + $dir = new RecursiveDirectoryIterator('.', FilesystemIterator::SKIP_DOTS | FilesystemIterator::CURRENT_AS_PATHNAME); + $itDir = new RecursiveIteratorIterator($dir); + $itReg = new RegexIterator($itDir, '~^./(.+\.(?:' . join('|', $ext) . '))$~', RegexIterator::GET_MATCH); + $files = iterable_column($itReg, 1); + + $newFiles = new CallbackFilterIterator($files, function ($path) use ($package): bool { + $file = basename($path); + $dirs = dirname($path) !== '.' ? explode('/', dirname($path)) : []; + array_unshift($dirs, '/'); + + $xpath = 'p:dir[@name="' . join('"]/p:dir[@name="', $dirs) . '"]/p:file[@name="' . $file . '"]'; + return count($package->contents->xpath($xpath)) === 0; + }); + + if (is_dir('.git')) { + $newFiles = gitignore_filter($newFiles); + } + + foreach ($newFiles as $file) { + $dirs = dirname($file) !== '.' ? explode('/', dirname($file)) : []; + + $dirElement = array_reduce($dirs, function (SimpleXMLElement $parent, string $dir): SimpleXMLElement { + $cur = $parent->xpath('p:dir[@name="' . $dir . '"]')[0] ?? null; + + if ($cur === null) { + $cur = $parent->addChild('dir'); + $cur['name'] = $dir; + } + + return $cur; + }, $package->contents->dir[0]); + + $fileElement = $dirElement->addChild('file'); + $fileElement['name'] = basename($file); + $fileElement['role'] = pathinfo($file, PATHINFO_EXTENSION) === 'phpt' ? 'test' : 'src'; + } +})(); + +// 8. Remove empty dirs from package.xml +(function () use ($package): void { + $emptyDirs = $package->xpath('p:contents//p:dir[not(descendant::*[local-name()="file"])]'); + + foreach (array_reverse($emptyDirs) as $element) { // reverse so children are deleted first + unset($element[0]); + } +})(); + +// 9. Sort files +(function () use ($package): void { + $dirElements = $package->xpath('p:contents//p:dir'); + + $sorter = function(SimpleXMLElement $first, SimpleXMLElement $second): int { + return + (($first->getName() !== 'file') <=> ($second->getName() !== 'file')) ?: + strcasecmp((string)$first['name'], (string)$second['name']); + }; + + foreach ($dirElements as $element) { + $element->sort($sorter); + } +})(); + +// 10. Save package.xml +$package->asXML('package.xml'); + +// :) friendly message +echo "\033[0;32m", /* green */ "Updated package.xml for {$package->name} {$release->version}", "\033[0;0m", "\n"; + +// ================= classes and functions ==================== + +class Release +{ + public $version; + public $apiVersion; + public $stability; + public $apiStability; + + public $license; + public $licenseUri; + public $notes; + + public function isMajor(string $oldVersion): bool + { + if ($oldVersion === '') { + return true; + } + + [$major, $minor] = explode('.', $this->version); + [$oldMajor, $oldMinor] = explode('.', $oldVersion); + + return ($major !== $oldMajor) || ($major === '0' && $minor !== $oldMinor); + } + + public function existsIn(SimpleXMLElement $changelog): bool + { + foreach ($changelog->release as $release) { + if ((string)($release->version->release) === $this->version) { + return true; + } + } + + return false; + } + + public function update(SimpleXMLElement $element) + { + $noTime = isset($element->date) && !isset($element->time); + + $element->date = date('Y-m-d'); + if (!$noTime) { + $element->time = date('H:i:s'); + } + + $element->version->release = $this->version; + $element->version->api = $this->apiVersion; + $element->stability->release = $this->stability; + $element->stability->api = $this->apiStability; + + $element->license = $this->license; + $element->license['uri'] = $this->licenseUri; + + $indent = str_repeat(' ', count($element->xpath('ancestor::*')) + 1); + $element->notes = "\n" . $this->notes . "\n$indent"; + } +}; + +class PackageXMLElement extends SimpleXMLElement +{ + private const BLANK_PACKAGE = << + + + pecl.php.net + + + + + + + yes + + + + + + + + + + + PHP License + + + + + + + + + + + + + + 7.0.0 + + + 1.4.3 + + + + + + + +XML; + + public static function create(): self + { + return new static(self::BLANK_PACKAGE); + } + + public function prependChild($name, $value = '') + { + $dom = dom_import_simplexml($this); + + $new = $dom->insertBefore( + $dom->ownerDocument->createElement($name, $value), + $dom->firstChild + ); + + return simplexml_import_dom($new, __CLASS__); + } + + public function sort(callable $sorter): void + { + if ($this->count() === 0) { + return; + } + + $children = iterator_to_array($this->children(), false); + usort($children, $sorter); + + $dom = dom_import_simplexml($this); + + while ($dom->hasChildNodes()) { + $dom->removeChild($dom->firstChild); + } + + foreach ($children as $child) { + $dom->appendChild(dom_import_simplexml($child)); + } + } + + public function asXML($filename = null) + { + $dom = new DOMDocument("1.0"); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + $dom->loadXML(parent::asXML()); + + $xml = $dom->saveXML(); + + // Go from 2 space indentation to 1. + $xml = preg_replace('~^([ ]+)\1<(?!/notes>)~m', '\1<', $xml); + + if ($filename === null) { + return $xml; + } + + if (file_exists($filename)) { + rename($filename, $filename . '~'); + } + file_put_contents($filename, $xml); + } + + public function xpath($xpath) + { + $this->registerXPathNamespace('p', 'http://pear.php.net/dtd/package-2.0'); + + return parent::xpath($xpath); + } +} + +function iterable_column(iterable $iterable, $column): Generator +{ + foreach ($iterable as $key => $item) { + yield $key => $item[$column]; + } +} + +function gitignore_filter(iterable $files): Generator +{ + $spec = [ + ["pipe", "r"], + ["pipe", "w"], + ["pipe", "w"], + ]; + + $process = proc_open('git check-ignore --non-matching --verbose --stdin', $spec, $pipes); + stream_set_timeout($pipes[1], 1); + stream_set_blocking($pipes[2], false); + + foreach ($files as $file) { + fwrite($pipes[0], $file . "\n"); + $line = fgets($pipes[1], 1024); + + if ($line === false || substr($line, 0, 2) === '::') { + yield $file; + } + } + + $err = fread($pipes[2], 10000); + + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + $ret = proc_close($process); + + if ($ret !== 0 && $err !== '') { + fwrite(STDERR, "\033[0;31m" /* red */ . $err . "\033[0m" /* no color */ . "\n"); + throw new RuntimeException("Checking .gitignore failed"); + } +} + diff --git a/composer.json b/composer.json deleted file mode 100644 index 17f6005..0000000 --- a/composer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "require-dev": { - "phpunit/phpunit": "^7.5", - "php-http/psr7-integration-tests": "dev-master", - "http-interop/http-factory-tests": "dev-master" - } -} - From 71fceb28a3fe89157ed80cdf71a3317d8e64bd07 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 5 Sep 2019 03:21:20 +0200 Subject: [PATCH 51/67] Release v0.2.0 --- package.xml | 431 +++++++++++++++++++++++++++------------------ php_http_message.h | 2 +- 2 files changed, 260 insertions(+), 173 deletions(-) diff --git a/package.xml b/package.xml index 1a0234e..5c437d3 100644 --- a/package.xml +++ b/package.xml @@ -1,5 +1,5 @@ - + http_message pecl.php.net PSR-7 HTTP Message implementation @@ -10,10 +10,10 @@ jasny@php.net yes - 2019-07-28 + 2019-09-05 - 0.1.1 - 0.1.0 + 0.2.0 + 0.2.0 beta @@ -21,171 +21,242 @@ MIT License -Fixed default value issue with ServerRequest::getAttribute(). The method only accepted one argument. +Added Factory class that implements all PSR-17 interfaces. +All properties private. +Allow filename and mode for Stream constructor. +Allow StreamInterface object for UploadedFile constructor. +Move uploaded file copies a stream if stream is supplied. +Fixes and cleanup. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -203,9 +274,29 @@ Fixed default value issue with ServerRequest::getAttribute(). The method only ac http_message - - + + + 2019-09-05 + + + 0.2.0 + 0.2.0 + + + beta + beta + + MIT License + +Added Factory class that implements all PSR-17 interfaces. +All properties private. +Allow filename and mode for Stream constructor. +Allow StreamInterface object for UploadedFile constructor. +Move uploaded file copies a stream if stream is supplied. +Fixes and cleanup. + + 2019-07-28 @@ -222,7 +313,6 @@ Fixed default value issue with ServerRequest::getAttribute(). The method only ac Fixed default value issue with ServerRequest::getAttribute(). The method only accepted one argument. - 2019-07-10 @@ -239,8 +329,5 @@ Fixed default value issue with ServerRequest::getAttribute(). The method only ac Initial release. - - - diff --git a/php_http_message.h b/php_http_message.h index ce10a6b..3d220b9 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.1.1" +#define PHP_HTTP_MESSAGE_VERSION "0.2.0" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 From 113e94426070eade6df5cddbb49346695a78966a Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 5 Sep 2019 03:32:08 +0200 Subject: [PATCH 52/67] Updated README.md Fixed link to appveyor [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c585b41..8f3f9c4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # PSR-7 HTTP Message as PHP extension [![Build Status](https://travis-ci.org/improved-php-library/http-message.svg?branch=master)](https://travis-ci.org/improved-php-library/http-message) -[![Build status](https://ci.appveyor.com/api/projects/status/7rof1vr8mv4kam17/branch/master?svg=true)](https://ci.appveyor.com/project/jasny/http_message/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/7rof1vr8mv4kam17/branch/master?svg=true)](https://ci.appveyor.com/project/jasny/http-message/branch/master) [PSR-7 HTTP Message](https://www.php-fig.org/psr/psr-7/) implementation as PHP extension written in C. From 850aa5c4d90e701b1aed6258c3919cc92d6dd105 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Wed, 11 Sep 2019 00:06:02 +0200 Subject: [PATCH 53/67] Changed build-packagexml.php not to create release for dev versions --- build-packagexml.php | 39 +++++++++++++++++++++++++++++---------- php_http_message.h | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/build-packagexml.php b/build-packagexml.php index c751554..f5093c2 100644 --- a/build-packagexml.php +++ b/build-packagexml.php @@ -41,12 +41,28 @@ // 2. Process php_{extname}.h (function () use ($package, $release): void { $extname = (string)$package->name ?: getenv('PHP_PECL_EXTENSION') ?: null; - $filename = $extname !== null ? "php_{$extname}.h" : (glob('php_*.h')[0] ?? null); - if (!file_exists($filename)) { - throw new RuntimeException("{$filename} not found"); + if ($extname !== null) { + $filename = "php_{$extname}.h"; + + if (!file_exists($filename)) { + throw new RuntimeException("{$filename} not found"); + } + } else { + $filename = glob('php_*.h')[0] ?? null; + + if ($filename === null) { + throw new RuntimeException("Couldn't find the main header file (php_*.h)"); + } + + $extname = preg_replace('/^php_(.+)\.h$/', '$1', $filename); } + if ((string)$package->name === '') { + $package->name = $extname; + } + + $macroPrefix = strtoupper(pathinfo($filename, PATHINFO_FILENAME)); $contents = file_get_contents($filename); @@ -55,20 +71,23 @@ $macros = array_combine($matches['key'], $matches['value']); // Package name - if (!isset($macros['EXTNAME'])) { - throw new RuntimeException("$filename does not contain '{$macroPrefix}_EXTNAME' macro"); - } - if ((string)$package->name !== '' && (string)$package->name !== $macros['EXTNAME']) { - throw new RuntimeException("Package name '{$package->name}' (package.xml) doesn't match " - . "{$macroPrefix}_EXTNAME '{$macros['EXTNAME']}' ($filename)"); + if (isset($macros['EXTNAME'])) { + if ((string)$package->name !== '' && (string)$package->name !== $macros['EXTNAME']) { + throw new RuntimeException("Package name '{$package->name}' (package.xml) doesn't match " + . "{$macroPrefix}_EXTNAME '{$macros['EXTNAME']}' ($filename)"); + } } - $package->name = $macros['EXTNAME']; // Release version if (!isset($macros['VERSION'])) { throw new RuntimeException("$filename does not contain {$macroPrefix}_VERSION macro"); } $release->version = $macros['VERSION']; + + if (strpos($release->version, 'dev') !== 0) { + throw new RuntimeException("Development versions shouldn't be released ({$macros['VERSION']}). " + . "Please change {$macroPrefix}_VERSION in $filename."); + } if ($release->existsIn($package->changelog)) { throw new RuntimeException("Version {$macros['VERSION']} already released. " . "Please change {$macroPrefix}_VERSION in $filename."); diff --git a/php_http_message.h b/php_http_message.h index 3d220b9..044acd7 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.2.0" +#define PHP_HTTP_MESSAGE_VERSION "0.2.0-dev" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 From 05cbfaf9f0c7c37f1fb884604ea410f33238c8f8 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 7 Nov 2019 02:16:25 +0100 Subject: [PATCH 54/67] Added `HttpMessage\Emitter`. Emitter outputs header and body. XDebug is needed to test emitter. Fixed segfault for `withHeader()` when using a non-string var. --- CMakeLists.txt | 12 +- Makefile.frag | 2 +- config.m4 | 2 +- config.w32 | 2 +- emitter.c | 214 +++++++++++++++++++++++++++++++++ factory.c | 4 +- http_message.c | 5 +- message.c | 8 +- php_http_message.h | 2 + tests/Emitter/emit_001.phpt | 26 ++++ tests/Emitter/emit_002.phpt | 28 +++++ tests/Emitter/emit_003.phpt | 29 +++++ tests/Emitter/emit_004.phpt | 36 ++++++ tests/Emitter/emit_005.phpt | 35 ++++++ tests/Message/headers_003.phpt | 19 +++ tests/smoke.php | 1 + 16 files changed, 413 insertions(+), 12 deletions(-) create mode 100644 emitter.c create mode 100644 tests/Emitter/emit_001.phpt create mode 100644 tests/Emitter/emit_002.phpt create mode 100644 tests/Emitter/emit_003.phpt create mode 100644 tests/Emitter/emit_004.phpt create mode 100644 tests/Emitter/emit_005.phpt create mode 100644 tests/Message/headers_003.phpt diff --git a/CMakeLists.txt b/CMakeLists.txt index a5b8b47..ea3d6b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,17 @@ project(http_message C) add_compile_definitions(HAVE_HTTP_MESSAGE) set(SOURCE_FILES php_http_message - http_message.c message.c request.c uri.c server_request.c response.c stream.c uploaded_file.c factory.c) + http_message.c + message.c + request.c + server_request.c + response.c + uri.c + stream.c + uploaded_file.c + factory.c + emitter.c +) execute_process ( COMMAND php-config --include-dir diff --git a/Makefile.frag b/Makefile.frag index 8177ecd..33613e3 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -1,5 +1,5 @@ PHP_TEST_SHARED_EXTENSIONS = ` \ - echo "-d extension=$(EXTENSION_DIR)/psr.so"; \ + echo "-d extension=$(EXTENSION_DIR)/psr.so" "-d zend_extension=$(EXTENSION_DIR)/xdebug.so"; \ if test "x$(PHP_MODULES)" != "x"; then \ for i in $(PHP_MODULES)""; do \ . $$i; $(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \ diff --git a/config.m4 b/config.m4 index 35a20df..6bfded3 100644 --- a/config.m4 +++ b/config.m4 @@ -12,7 +12,7 @@ if test "$PHP_HTTP_MESSAGE" != "no"; then PECL_HAVE_PHP_EXT([psr], [PECL_HAVE_PHP_EXT_HEADER([psr])], [AC_MSG_ERROR([please install and enable the psr extension])]) AC_DEFINE(HAVE_HTTP_MESSAGE, 1, [Whether you have http_message]) - PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c, $ext_shared) + PHP_NEW_EXTENSION(http_message, http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c emitter.c, $ext_shared) PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/http_message], [php_http_message.h]) diff --git a/config.w32 b/config.w32 index b941d1d..13006d3 100644 --- a/config.w32 +++ b/config.w32 @@ -4,7 +4,7 @@ ARG_ENABLE("http-message", "enable http_message", "no"); if (PHP_HTTP_MESSAGE != "no") { - EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c"); + EXTENSION("http_message", "http_message.c message.c request.c server_request.c response.c stream.c uri.c uploaded_file.c factory.c emitter.c"); AC_DEFINE('HAVE_HTTP_MESSAGE', 1 , 'enable http_message support'); PHP_INSTALL_HEADERS("ext/http_message/", "php_http_message.h"); } diff --git a/emitter.c b/emitter.c new file mode 100644 index 0000000..2950893 --- /dev/null +++ b/emitter.c @@ -0,0 +1,214 @@ +/* + +----------------------------------------------------------------------+ + | HTTP Message PHP extension - Stream class | + +----------------------------------------------------------------------+ + | Copyright (c) 2019 Arnold Daniels | + +----------------------------------------------------------------------+ + | Permission is hereby granted, free of charge, to any person | + | obtaining a copy of this software and associated documentation files | + | (the "Software"), to deal in the Software without restriction, | + | including without limitation the rights to use, copy, modify, merge, | + | publish, distribute, sublicense, and/or sell copies of the Software, | + | and to permit persons to whom the Software is furnished to do so, | + | subject to the following conditions: | + | | + | The above copyright notice and this permission notice shall be | + | included in all copies or substantial portions of the Software. | + | | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | + | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | + | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | + | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | + | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | + | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | + | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | + | SOFTWARE. | + +----------------------------------------------------------------------+ + | Author: Arnold Daniels | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "SAPI.h" +#include "php.h" +#include "macros.h" +#include "response.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "ext/spl/spl_exceptions.h" + +#if HAVE_HTTP_MESSAGE + +zend_class_entry *HttpMessage_Emitter_ce = NULL; + +int assert_no_headers_sent() +{ + if (!SG(headers_sent)) { + return SUCCESS; + } + + const char *file = php_output_get_start_filename(); + int line = php_output_get_start_lineno(); + + if (file != NULL) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, + "Cannot send session cookie - headers already sent by (output started at %s:%d)", file, line); + } else { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot send session cookie - headers already sent"); + } + + return FAILURE; +} + +int read_response_body(zval *response, zval *contents) +{ + zval body; + + ZVAL_NULL(&body); + ZVAL_NULL(contents); + + zend_call_method_with_0_params(response, NULL, NULL, "getBody",&body); + + if (EXPECTED(Z_TYPE(body) == IS_OBJECT)) { + zend_call_method_with_0_params(&body, NULL, NULL, "__toString", contents); + } + + if (UNEXPECTED(Z_TYPE_P(contents) != IS_STRING)) { + return FAILURE; // Something went wrong, assuming an error was already thrown. + } + + return SUCCESS; +} + +void emit_status(zval *response) +{ + zval version, status_code, reason_phrase; + zend_long code; + char *phrase = NULL; + size_t phrase_len = 0; + sapi_header_line ctr = {NULL, 0, 0}; + + ZVAL_NULL(&status_code); + ZVAL_NULL(&reason_phrase); + + zend_call_method_with_0_params(response, NULL, NULL, "getProtocolVersion", &version); + zend_call_method_with_0_params(response, NULL, NULL, "getStatusCode",&status_code); + zend_call_method_with_0_params(response, NULL, NULL, "getReasonPhrase",&reason_phrase); + + code = Z_LVAL(status_code); + + if (Z_STRLEN(reason_phrase) > 0) { + phrase = Z_STRVAL(reason_phrase); + phrase_len = Z_STRLEN(reason_phrase); + } else { + phrase = (char *)get_status_string((int)code); + phrase_len = strlen(phrase); + } + + ctr.line_len = Z_STRLEN(version) + phrase_len + 10; + ctr.line = emalloc(ctr.line_len); + zend_sprintf(ctr.line, "HTTP/%.*s %3lu %.*s", Z_STRLEN(version), Z_STRVAL(version), code, phrase_len, phrase); + ctr.response_code = code; + + sapi_header_op(SAPI_HEADER_REPLACE, &ctr); + + efree(ctr.line); +} + +void emit_header(zend_string *header_name, zend_array *header_lines) +{ + zval *header_line; + size_t max_header_size = 256; + sapi_header_line ctr = {NULL, 0, 0}; + ctr.line = emalloc(256); + + ZEND_HASH_FOREACH_VAL(header_lines, header_line){ + ctr.line_len = ZSTR_LEN(header_name) + Z_STRLEN_P(header_line) + 2; + + // Reuse ctr: resize if needed. + if (ctr.line_len >= max_header_size) { + efree(ctr.line); + max_header_size = (ctr.line_len + 255) - ((ctr.line_len + 255) % 256); + ctr.line = emalloc(max_header_size); + } + + zend_sprintf(ctr.line, "%s: %s", ZSTR_VAL(header_name), Z_STRVAL_P(header_line)); + sapi_header_op(SAPI_HEADER_ADD, &ctr); + } ZEND_HASH_FOREACH_END(); + + efree(ctr.line); +} + +void emit_headers(zval *response) +{ + zval headers; + zval *header_lines; + zend_string *header_name; + zend_long index; + + zend_call_method_with_0_params(response, NULL, NULL, "getHeaders", &headers); + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARR(headers), index, header_name, header_lines) { + if (UNEXPECTED(header_name == NULL)) { + zend_error(E_WARNING, "Unexpected response header key '%d': header names should not be numeric", index); + continue; + } + + emit_header(header_name, Z_ARR_P(header_lines)); + } ZEND_HASH_FOREACH_END(); +} + +ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageEmitter_emit, 0, 0, 0) + ZEND_ARG_OBJ_INFO(0, serverParams, Psr\\Http\\Message\\ResponseInterface, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(Emitter, emit) +{ + zval *response = NULL; + zval contents; + + zend_class_entry *response_interface = HTTP_MESSAGE_PSR_INTERFACE("response"); + + if (UNEXPECTED(response_interface == NULL)) { + zend_throw_error(NULL, "Psr\\Http\\Message\\ResponseInterface not found"); + return; + } + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) + Z_PARAM_OBJECT_OF_CLASS(response, response_interface) + ZEND_PARSE_PARAMETERS_END(); + + if (UNEXPECTED(assert_no_headers_sent() == FAILURE)) { + return; + } + + if (UNEXPECTED(read_response_body(response, &contents) == FAILURE)) { + return; + } + + emit_headers(response); + emit_status(response); + zend_write(Z_STRVAL(contents), Z_STRLEN(contents)); +} + +/* Define HttpMessage\Emitter class */ + +static const zend_function_entry methods[] = { + PHP_ME(Emitter, emit, arginfo_HttpMessageEmitter_emit, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +PHP_MINIT_FUNCTION(http_message_emitter) +{ + zend_class_entry ce; + + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Emitter", methods); + HttpMessage_Emitter_ce = zend_register_internal_class(&ce); + + return SUCCESS; +} + +#endif diff --git a/factory.c b/factory.c index d60526b..0b9409c 100644 --- a/factory.c +++ b/factory.c @@ -225,7 +225,7 @@ PHP_METHOD(Factory, createUri) /* Define HttpMessage\Factory class */ -static const zend_function_entry request_functions[] = { +static const zend_function_entry methods[] = { HTTP_MESSAGE_ME_EX(Factory, RequestFactory, createRequest) HTTP_MESSAGE_ME_EX(Factory, ResponseFactory, createResponse) HTTP_MESSAGE_ME_EX(Factory, ServerRequestFactory, createServerRequest) @@ -261,7 +261,7 @@ PHP_MINIT_FUNCTION(http_message_factory) return FAILURE; } - INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Factory", request_functions); + INIT_NS_CLASS_ENTRY(ce, "HttpMessage", "Factory", methods); HttpMessage_Factory_ce = zend_register_internal_class(&ce); zend_class_implements(HttpMessage_Factory_ce, 6, request_factory, response_factory, serverrequest_factory, diff --git a/http_message.c b/http_message.c index 403c13b..13dca6f 100644 --- a/http_message.c +++ b/http_message.c @@ -69,8 +69,9 @@ PHP_MINIT_FUNCTION(http_message) PHP_MINIT(http_message_response)(INIT_FUNC_ARGS_PASSTHRU) + PHP_MINIT(http_message_stream)(INIT_FUNC_ARGS_PASSTHRU) + PHP_MINIT(http_message_uri)(INIT_FUNC_ARGS_PASSTHRU) + - PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU); - PHP_MINIT(http_message_factory)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(http_message_uploadedfile)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_factory)(INIT_FUNC_ARGS_PASSTHRU) + + PHP_MINIT(http_message_emitter)(INIT_FUNC_ARGS_PASSTHRU); return ZEND_NORMALIZE_BOOL(success); } diff --git a/message.c b/message.c index 3dcffa0..8df39c8 100644 --- a/message.c +++ b/message.c @@ -66,7 +66,7 @@ void add_header(zval *object, zend_string *name, zend_string *value, zend_bool a ZVAL_DEREF(header_values); array_init(header_values); } - add_next_index_str(header_values, value); + add_next_index_str(header_values, zend_string_copy(value)); ZVAL_ARR(headers_prop, headers); } @@ -181,7 +181,7 @@ PHP_METHOD(Message, getHeaderLine) PHP_METHOD(Message, withHeader) { - zend_string *name, *value; + zend_string *name = NULL, *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) Z_PARAM_STR(name) @@ -195,7 +195,7 @@ PHP_METHOD(Message, withHeader) PHP_METHOD(Message, withAddedHeader) { - zend_string *name, *value; + zend_string *name = NULL, *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2) Z_PARAM_STR(name) @@ -211,7 +211,7 @@ PHP_METHOD(Message, withoutHeader) { zval rv, *headers_prop; HashTable *headers; - zend_string *name; + zend_string *name = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STR(name) diff --git a/php_http_message.h b/php_http_message.h index 044acd7..2604a61 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -53,6 +53,7 @@ extern PHP_MINIT_FUNCTION(http_message_stream); extern PHP_MINIT_FUNCTION(http_message_uri); extern PHP_MINIT_FUNCTION(http_message_uploadedfile); extern PHP_MINIT_FUNCTION(http_message_factory); +extern PHP_MINIT_FUNCTION(http_message_emitter); extern zend_module_entry http_message_module_entry; @@ -64,5 +65,6 @@ extern zend_class_entry *HttpMessage_Stream_ce; extern zend_class_entry *HttpMessage_Uri_ce; extern zend_class_entry *HttpMessage_UploadedFile_ce; extern zend_class_entry *HttpMessage_Factory_ce; +extern zend_class_entry *HttpMessage_Emitter_ce; #endif diff --git a/tests/Emitter/emit_001.phpt b/tests/Emitter/emit_001.phpt new file mode 100644 index 0000000..650b7c4 --- /dev/null +++ b/tests/Emitter/emit_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +Emitter::emit() with an empty response +--INI-- +default_mimetype=text/plain +default_charset=UTF-8 +--SKIPIF-- + +--FILE-- +emit($response); +echo "\n---\n"; + +var_dump(http_response_code()); +var_dump(xdebug_get_headers()); + +?> +--EXPECT-- +--- +bool(false) +array(1) { + [0]=> + string(39) "Content-type: text/plain; charset=UTF-8" +} \ No newline at end of file diff --git a/tests/Emitter/emit_002.phpt b/tests/Emitter/emit_002.phpt new file mode 100644 index 0000000..2803f6b --- /dev/null +++ b/tests/Emitter/emit_002.phpt @@ -0,0 +1,28 @@ +--TEST-- +Emitter::emit() with a response body +--INI-- +default_mimetype=text/plain +default_charset=UTF-8 +--SKIPIF-- + +--FILE-- +getBody()->write("Hello World"); + +$emitter->emit($response); +echo "\n---\n"; + +var_dump(http_response_code()); +var_dump(xdebug_get_headers()); + +?> +--EXPECT-- +Hello World +--- +bool(false) +array(1) { + [0]=> + string(39) "Content-type: text/plain; charset=UTF-8" +} \ No newline at end of file diff --git a/tests/Emitter/emit_003.phpt b/tests/Emitter/emit_003.phpt new file mode 100644 index 0000000..2e89e4b --- /dev/null +++ b/tests/Emitter/emit_003.phpt @@ -0,0 +1,29 @@ +--TEST-- +Emitter::emit() with a response status +--INI-- +default_mimetype=text/plain +default_charset=UTF-8 +--SKIPIF-- + +--FILE-- +withStatus(200, "Ok"); +$response->getBody()->write("Hello World"); + +$emitter->emit($response); +echo "\n---\n"; + +var_dump(http_response_code()); +var_dump(xdebug_get_headers()); + +?> +--EXPECT-- +Hello World +--- +int(200) +array(1) { + [0]=> + string(39) "Content-type: text/plain; charset=UTF-8" +} \ No newline at end of file diff --git a/tests/Emitter/emit_004.phpt b/tests/Emitter/emit_004.phpt new file mode 100644 index 0000000..1c7210b --- /dev/null +++ b/tests/Emitter/emit_004.phpt @@ -0,0 +1,36 @@ +--TEST-- +Emitter::emit() with a response with headers +--INI-- +default_mimetype=text/plain +default_charset=UTF-8 +--SKIPIF-- + +--FILE-- +withStatus(404, "Not Found") + ->withHeader("Content-Type", "text/html") + ->withHeader("Content-Length", 14) + ->withHeader("Foo", "bar"); +$response->getBody()->write("Page not found"); + +$emitter->emit($response); +echo "\n---\n"; + +var_dump(http_response_code()); +var_dump(xdebug_get_headers()); + +?> +--EXPECT-- +Page not found +--- +int(404) +array(3) { + [0]=> + string(37) "Content-type: text/html;charset=UTF-8" + [1]=> + string(18) "Content-Length: 14" + [2]=> + string(8) "Foo: bar" +} diff --git a/tests/Emitter/emit_005.phpt b/tests/Emitter/emit_005.phpt new file mode 100644 index 0000000..627476c --- /dev/null +++ b/tests/Emitter/emit_005.phpt @@ -0,0 +1,35 @@ +--TEST-- +Emitter::emit() with a response with duplicate headers +--INI-- +default_mimetype=text/plain +default_charset=UTF-8 +--SKIPIF-- + +--FILE-- +withAddedHeader("X-Message", "This is a") + ->withAddedHeader("X-Message", "log message") + ->withAddedHeader("X-Message", str_repeat("x", 1000)); + +$emitter->emit($response); +echo "\n---\n"; + +var_dump(http_response_code()); +var_dump(xdebug_get_headers()); + +?> +--EXPECT-- +--- +bool(false) +array(4) { + [0]=> + string(20) "X-Message: This is a" + [1]=> + string(22) "X-Message: log message" + [2]=> + string(1011) "X-Message: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + [3]=> + string(39) "Content-type: text/plain; charset=UTF-8" +} \ No newline at end of file diff --git a/tests/Message/headers_003.phpt b/tests/Message/headers_003.phpt new file mode 100644 index 0000000..c12d0fe --- /dev/null +++ b/tests/Message/headers_003.phpt @@ -0,0 +1,19 @@ +--TEST-- +Message header with numeric value +--FILE-- +withHeader('Content-Length', 100); + +var_dump($response->getHeaders()); + +?> +--EXPECT-- +array(1) { + ["Content-Length"]=> + array(1) { + [0]=> + string(3) "100" + } +} \ No newline at end of file diff --git a/tests/smoke.php b/tests/smoke.php index 14947c0..76b0a61 100644 --- a/tests/smoke.php +++ b/tests/smoke.php @@ -11,5 +11,6 @@ new HttpMessage\Response(); new HttpMessage\Factory(); +new HttpMessage\Emitter(); echo "ok"; From 29a57defacc0425e1f65b32736898e30e5626147 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 7 Nov 2019 02:36:18 +0100 Subject: [PATCH 55/67] Use phpt `EXPECTHEADERS` instead of needing xdebug --- Makefile.frag | 2 +- tests/Emitter/emit_001.phpt | 16 +--------------- tests/Emitter/emit_002.phpt | 16 +--------------- tests/Emitter/emit_003.phpt | 17 ++--------------- tests/Emitter/emit_004.phpt | 24 +++--------------------- tests/Emitter/emit_005.phpt | 25 ++++--------------------- tests/Emitter/emit_006.phpt | 16 ++++++++++++++++ tests/Emitter/emit_007.phpt | 17 +++++++++++++++++ 8 files changed, 45 insertions(+), 88 deletions(-) create mode 100644 tests/Emitter/emit_006.phpt create mode 100644 tests/Emitter/emit_007.phpt diff --git a/Makefile.frag b/Makefile.frag index 33613e3..8177ecd 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -1,5 +1,5 @@ PHP_TEST_SHARED_EXTENSIONS = ` \ - echo "-d extension=$(EXTENSION_DIR)/psr.so" "-d zend_extension=$(EXTENSION_DIR)/xdebug.so"; \ + echo "-d extension=$(EXTENSION_DIR)/psr.so"; \ if test "x$(PHP_MODULES)" != "x"; then \ for i in $(PHP_MODULES)""; do \ . $$i; $(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \ diff --git a/tests/Emitter/emit_001.phpt b/tests/Emitter/emit_001.phpt index 650b7c4..32ce78a 100644 --- a/tests/Emitter/emit_001.phpt +++ b/tests/Emitter/emit_001.phpt @@ -1,26 +1,12 @@ --TEST-- Emitter::emit() with an empty response ---INI-- -default_mimetype=text/plain -default_charset=UTF-8 ---SKIPIF-- - --FILE-- emit($response); -echo "\n---\n"; - -var_dump(http_response_code()); -var_dump(xdebug_get_headers()); ?> +--EXPECTHEADERS-- --EXPECT-- ---- -bool(false) -array(1) { - [0]=> - string(39) "Content-type: text/plain; charset=UTF-8" -} \ No newline at end of file diff --git a/tests/Emitter/emit_002.phpt b/tests/Emitter/emit_002.phpt index 2803f6b..87b0a4b 100644 --- a/tests/Emitter/emit_002.phpt +++ b/tests/Emitter/emit_002.phpt @@ -1,10 +1,5 @@ --TEST-- Emitter::emit() with a response body ---INI-- -default_mimetype=text/plain -default_charset=UTF-8 ---SKIPIF-- - --FILE-- getBody()->write("Hello World"); $emitter->emit($response); -echo "\n---\n"; - -var_dump(http_response_code()); -var_dump(xdebug_get_headers()); ?> +--EXPECTHEADERS-- --EXPECT-- Hello World ---- -bool(false) -array(1) { - [0]=> - string(39) "Content-type: text/plain; charset=UTF-8" -} \ No newline at end of file diff --git a/tests/Emitter/emit_003.phpt b/tests/Emitter/emit_003.phpt index 2e89e4b..e709216 100644 --- a/tests/Emitter/emit_003.phpt +++ b/tests/Emitter/emit_003.phpt @@ -1,10 +1,6 @@ --TEST-- Emitter::emit() with a response status --INI-- -default_mimetype=text/plain -default_charset=UTF-8 ---SKIPIF-- - --FILE-- getBody()->write("Hello World"); $emitter->emit($response); -echo "\n---\n"; - -var_dump(http_response_code()); -var_dump(xdebug_get_headers()); - ?> +--EXPECTHEADERS-- +HTTP/1.1 200 OK --EXPECT-- Hello World ---- -int(200) -array(1) { - [0]=> - string(39) "Content-type: text/plain; charset=UTF-8" -} \ No newline at end of file diff --git a/tests/Emitter/emit_004.phpt b/tests/Emitter/emit_004.phpt index 1c7210b..4f9d8b7 100644 --- a/tests/Emitter/emit_004.phpt +++ b/tests/Emitter/emit_004.phpt @@ -1,36 +1,18 @@ --TEST-- Emitter::emit() with a response with headers ---INI-- -default_mimetype=text/plain -default_charset=UTF-8 ---SKIPIF-- - --FILE-- withStatus(404, "Not Found") - ->withHeader("Content-Type", "text/html") ->withHeader("Content-Length", 14) ->withHeader("Foo", "bar"); $response->getBody()->write("Page not found"); $emitter->emit($response); -echo "\n---\n"; - -var_dump(http_response_code()); -var_dump(xdebug_get_headers()); ?> +--EXPECTHEADERS-- +Content-Length: 14 +Foo: bar --EXPECT-- Page not found ---- -int(404) -array(3) { - [0]=> - string(37) "Content-type: text/html;charset=UTF-8" - [1]=> - string(18) "Content-Length: 14" - [2]=> - string(8) "Foo: bar" -} diff --git a/tests/Emitter/emit_005.phpt b/tests/Emitter/emit_005.phpt index 627476c..6afbf35 100644 --- a/tests/Emitter/emit_005.phpt +++ b/tests/Emitter/emit_005.phpt @@ -1,10 +1,5 @@ --TEST-- Emitter::emit() with a response with duplicate headers ---INI-- -default_mimetype=text/plain -default_charset=UTF-8 ---SKIPIF-- - --FILE-- withAddedHeader("X-Message", str_repeat("x", 1000)); $emitter->emit($response); -echo "\n---\n"; - -var_dump(http_response_code()); -var_dump(xdebug_get_headers()); ?> +--EXPECTHEADERS-- +X-Message: This is a +X-Message: log message +X-Message: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --EXPECT-- ---- -bool(false) -array(4) { - [0]=> - string(20) "X-Message: This is a" - [1]=> - string(22) "X-Message: log message" - [2]=> - string(1011) "X-Message: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - [3]=> - string(39) "Content-type: text/plain; charset=UTF-8" -} \ No newline at end of file diff --git a/tests/Emitter/emit_006.phpt b/tests/Emitter/emit_006.phpt new file mode 100644 index 0000000..8d3c649 --- /dev/null +++ b/tests/Emitter/emit_006.phpt @@ -0,0 +1,16 @@ +--TEST-- +Emitter::emit() with a response with response status +--FILE-- +withStatus(404) + ->withHeader("Foo", "Bar"); + +$emitter->emit($response); + +?> +--EXPECTHEADERS-- +HTTP/1.1 404 Not Found +Foo: Bar +--EXPECT-- diff --git a/tests/Emitter/emit_007.phpt b/tests/Emitter/emit_007.phpt new file mode 100644 index 0000000..6b430f2 --- /dev/null +++ b/tests/Emitter/emit_007.phpt @@ -0,0 +1,17 @@ +--TEST-- +Emitter::emit() with a response with response status and custom reason +--FILE-- +withProtocolVersion("1.0") + ->withStatus(404, "Please go away") + ->withHeader("Foo", "Bar"); + +$emitter->emit($response); + +?> +--EXPECTHEADERS-- +HTTP/1.0 404 Please go away +Foo: Bar +--EXPECT-- From 338635218ebc8b917f5fc610002e3723cded0cab Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Thu, 7 Nov 2019 02:44:36 +0100 Subject: [PATCH 56/67] Version 0.2.1 --- build-packagexml.php | 9 ++++++++- package.xml | 46 ++++++++++++++++++++++++++++++++++++-------- php_http_message.h | 2 +- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/build-packagexml.php b/build-packagexml.php index f5093c2..6164ed3 100644 --- a/build-packagexml.php +++ b/build-packagexml.php @@ -84,7 +84,7 @@ } $release->version = $macros['VERSION']; - if (strpos($release->version, 'dev') !== 0) { + if (strpos($release->version, 'dev') !== false) { throw new RuntimeException("Development versions shouldn't be released ({$macros['VERSION']}). " . "Please change {$macroPrefix}_VERSION in $filename."); } @@ -134,6 +134,9 @@ })((string)$package->name, $release->version); // 5. Add release to package +if (!isset($package->changelog)) { + $package->addChild('changelog'); +} $release->update($package->changelog->prependChild('release')); $release->update($package); @@ -249,6 +252,10 @@ public function isMajor(string $oldVersion): bool public function existsIn(SimpleXMLElement $changelog): bool { + if (!isset($changelog->release)) { + return false; + } + foreach ($changelog->release as $release) { if ((string)($release->version->release) === $this->version) { return true; diff --git a/package.xml b/package.xml index 5c437d3..a684856 100644 --- a/package.xml +++ b/package.xml @@ -10,9 +10,9 @@ jasny@php.net yes - 2019-09-05 + 2019-11-07 - 0.2.0 + 0.2.1 0.2.0 @@ -21,18 +21,18 @@ MIT License -Added Factory class that implements all PSR-17 interfaces. -All properties private. -Allow filename and mode for Stream constructor. -Allow StreamInterface object for UploadedFile constructor. -Move uploaded file copies a stream if stream is supplied. -Fixes and cleanup. +Added `HttpMessage\Emitter`. +Emitter outputs header and body. +XDebug is needed to test emitter. + +Fixed segfault for `withHeader()` when using a non-string var. + @@ -54,6 +54,15 @@ Fixes and cleanup. + + + + + + + + + @@ -89,6 +98,7 @@ Fixes and cleanup. + @@ -276,6 +286,26 @@ Fixes and cleanup. http_message + + 2019-11-07 + + + 0.2.1 + 0.2.0 + + + beta + beta + + MIT License + +Added `HttpMessage\Emitter`. +Emitter outputs header and body. +XDebug is needed to test emitter. + +Fixed segfault for `withHeader()` when using a non-string var. + + 2019-09-05 diff --git a/php_http_message.h b/php_http_message.h index 2604a61..ddd6e2f 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.2.0-dev" +#define PHP_HTTP_MESSAGE_VERSION "0.2.1" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 From 058abb5494687902328d0ad98cdc5dea6d370ad1 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 25 Aug 2020 13:17:34 +0200 Subject: [PATCH 57/67] Fix + test Factory::createUri() --- emitter.c | 14 +++++++------- factory.c | 6 +++--- tests/Factory/createUri_001.phpt | 28 ++++++++++++++++++++++++++++ tests/Factory/createUri_002.phpt | 28 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 tests/Factory/createUri_001.phpt create mode 100644 tests/Factory/createUri_002.phpt diff --git a/emitter.c b/emitter.c index 2950893..10933ff 100644 --- a/emitter.c +++ b/emitter.c @@ -70,7 +70,7 @@ int read_response_body(zval *response, zval *contents) ZVAL_NULL(&body); ZVAL_NULL(contents); - zend_call_method_with_0_params(response, NULL, NULL, "getBody",&body); + zend_call_method_with_0_params(response, NULL, NULL, "getBody", &body); if (EXPECTED(Z_TYPE(body) == IS_OBJECT)) { zend_call_method_with_0_params(&body, NULL, NULL, "__toString", contents); @@ -95,9 +95,9 @@ void emit_status(zval *response) ZVAL_NULL(&reason_phrase); zend_call_method_with_0_params(response, NULL, NULL, "getProtocolVersion", &version); - zend_call_method_with_0_params(response, NULL, NULL, "getStatusCode",&status_code); - zend_call_method_with_0_params(response, NULL, NULL, "getReasonPhrase",&reason_phrase); - + zend_call_method_with_0_params(response, NULL, NULL, "getStatusCode", &status_code); + zend_call_method_with_0_params(response, NULL, NULL, "getReasonPhrase", &reason_phrase); + code = Z_LVAL(status_code); if (Z_STRLEN(reason_phrase) > 0) { @@ -110,7 +110,7 @@ void emit_status(zval *response) ctr.line_len = Z_STRLEN(version) + phrase_len + 10; ctr.line = emalloc(ctr.line_len); - zend_sprintf(ctr.line, "HTTP/%.*s %3lu %.*s", Z_STRLEN(version), Z_STRVAL(version), code, phrase_len, phrase); + zend_sprintf(ctr.line, "HTTP/%.*s %3lu %.*s", (int)Z_STRLEN(version), Z_STRVAL(version), code, (int)phrase_len, phrase); ctr.response_code = code; sapi_header_op(SAPI_HEADER_REPLACE, &ctr); @@ -125,7 +125,7 @@ void emit_header(zend_string *header_name, zend_array *header_lines) sapi_header_line ctr = {NULL, 0, 0}; ctr.line = emalloc(256); - ZEND_HASH_FOREACH_VAL(header_lines, header_line){ + ZEND_HASH_FOREACH_VAL(header_lines, header_line) { ctr.line_len = ZSTR_LEN(header_name) + Z_STRLEN_P(header_line) + 2; // Reuse ctr: resize if needed. @@ -153,7 +153,7 @@ void emit_headers(zval *response) ZEND_HASH_FOREACH_KEY_VAL(Z_ARR(headers), index, header_name, header_lines) { if (UNEXPECTED(header_name == NULL)) { - zend_error(E_WARNING, "Unexpected response header key '%d': header names should not be numeric", index); + zend_error(E_WARNING, "Unexpected response header key '%ld': header names should not be numeric", index); continue; } diff --git a/factory.c b/factory.c index 0b9409c..9cd556c 100644 --- a/factory.c +++ b/factory.c @@ -210,16 +210,16 @@ PHP_METHOD(Factory, createUri) zend_string *uri = NULL; zval zuri; - ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 0) + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR_EX(uri, 1, 0) ZEND_PARSE_PARAMETERS_END(); if (uri == NULL) { - NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 0); + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Uri_ce, 0); } else { ZVAL_STR(&zuri, uri); - NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 1, &zuri); + NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Uri_ce, 1, &zuri); } } diff --git a/tests/Factory/createUri_001.phpt b/tests/Factory/createUri_001.phpt new file mode 100644 index 0000000..2520dd6 --- /dev/null +++ b/tests/Factory/createUri_001.phpt @@ -0,0 +1,28 @@ +--TEST-- +Factory::createUri() +--FILE-- +createUri(); + +var_dump($uri); + +?> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(0) "" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(0) "" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(0) "" + ["query":"HttpMessage\Uri":private]=> + string(0) "" + ["fragment":"HttpMessage\Uri":private]=> + string(0) "" +} + diff --git a/tests/Factory/createUri_002.phpt b/tests/Factory/createUri_002.phpt new file mode 100644 index 0000000..4a880e0 --- /dev/null +++ b/tests/Factory/createUri_002.phpt @@ -0,0 +1,28 @@ +--TEST-- +Factory::createUri() +--FILE-- +createUri("https://example.com/path?foo=1&bar=2#frag"); + +var_dump($uri); + +?> +--EXPECTF-- +object(HttpMessage\Uri)#%d (7) { + ["scheme":"HttpMessage\Uri":private]=> + string(5) "https" + ["userInfo":"HttpMessage\Uri":private]=> + string(0) "" + ["host":"HttpMessage\Uri":private]=> + string(11) "example.com" + ["port":"HttpMessage\Uri":private]=> + NULL + ["path":"HttpMessage\Uri":private]=> + string(5) "/path" + ["query":"HttpMessage\Uri":private]=> + string(11) "foo=1&bar=2" + ["fragment":"HttpMessage\Uri":private]=> + string(4) "frag" +} + From 72975c3dd7cbe551a8c0817352a6b79c82cacf5f Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 25 Aug 2020 13:20:53 +0200 Subject: [PATCH 58/67] Update package v0.2.2 --- package.xml | 28 +++++++++++++++++++++------- php_http_message.h | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/package.xml b/package.xml index a684856..97de2f8 100644 --- a/package.xml +++ b/package.xml @@ -10,9 +10,9 @@ jasny@php.net yes - 2019-11-07 + 2020-08-25 - 0.2.1 + 0.2.2 0.2.0 @@ -21,11 +21,7 @@ MIT License -Added `HttpMessage\Emitter`. -Emitter outputs header and body. -XDebug is needed to test emitter. - -Fixed segfault for `withHeader()` when using a non-string var. +Fixed HttpMessage\Factory::createUri() @@ -92,6 +88,8 @@ Fixed segfault for `withHeader()` when using a non-string var. + + @@ -286,6 +284,22 @@ Fixed segfault for `withHeader()` when using a non-string var. http_message + + 2020-08-25 + + + 0.2.2 + 0.2.0 + + + beta + beta + + MIT License + +Fixed HttpMessage\Factory::createUri() + + 2019-11-07 diff --git a/php_http_message.h b/php_http_message.h index ddd6e2f..80e419f 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.2.1" +#define PHP_HTTP_MESSAGE_VERSION "0.2.2" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32 From 79e8189c0ec666791bf6cf12c33af591fa3bba8f Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 26 Aug 2020 11:01:52 +0200 Subject: [PATCH 59/67] fix "static bu not defined" build warnings --- http_message.c | 30 +++++++++++++++--------------- php_http_message.h | 3 --- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/http_message.c b/http_message.c index 13dca6f..76ec02c 100644 --- a/http_message.c +++ b/http_message.c @@ -45,21 +45,6 @@ static const zend_module_dep deps[] = { {NULL, NULL, NULL} }; -zend_module_entry http_message_module_entry = { - STANDARD_MODULE_HEADER_EX, - NULL, - deps, - PHP_HTTP_MESSAGE_EXTNAME, - NULL, - PHP_MINIT(http_message), - NULL, - NULL, - NULL, - NULL, - PHP_HTTP_MESSAGE_VERSION, - STANDARD_MODULE_PROPERTIES -}; - PHP_MINIT_FUNCTION(http_message) { int success = @@ -76,6 +61,21 @@ PHP_MINIT_FUNCTION(http_message) return ZEND_NORMALIZE_BOOL(success); } +zend_module_entry http_message_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + deps, + PHP_HTTP_MESSAGE_EXTNAME, + NULL, + PHP_MINIT(http_message), + NULL, + NULL, + NULL, + NULL, + PHP_HTTP_MESSAGE_VERSION, + STANDARD_MODULE_PROPERTIES +}; + #ifdef COMPILE_DL_HTTP_MESSAGE ZEND_GET_MODULE(http_message) #endif diff --git a/php_http_message.h b/php_http_message.h index 80e419f..7df8474 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -42,9 +42,6 @@ # define PHP_HTTP_MESSAGE_API #endif -static PHP_MINFO_FUNCTION(http_message); -static PHP_MINIT_FUNCTION(http_message); - extern PHP_MINIT_FUNCTION(http_message_message); extern PHP_MINIT_FUNCTION(http_message_request); extern PHP_MINIT_FUNCTION(http_message_serverrequest); From a33ecedec096137de5b5b1715c95e8afeee67528 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 26 Aug 2020 11:15:40 +0200 Subject: [PATCH 60/67] fix unused build warnings --- request.c | 4 ++-- response.c | 2 ++ server_request.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/request.c b/request.c index 2b1cfd8..b6a8524 100644 --- a/request.c +++ b/request.c @@ -47,8 +47,10 @@ zend_class_entry *HttpMessage_Request_ce = NULL; /* __construct */ +/* unused ZEND_BEGIN_ARG_INFO_EX(arginfo_Request_construct, 0, 0, 0) ZEND_END_ARG_INFO() +*/ PHP_METHOD(Request, __construct) { @@ -129,12 +131,10 @@ PHP_METHOD(Request, getMethod) PHP_METHOD(Request, withMethod) { - int u; zend_string *value = NULL; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1) Z_PARAM_STR(value) - u = _i + 5; ZEND_PARSE_PARAMETERS_END(); ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); diff --git a/response.c b/response.c index 0bb9a2f..ed226be 100644 --- a/response.c +++ b/response.c @@ -71,10 +71,12 @@ int response_set_status(zval *obj, zend_long code, zend_string *phrase) /* __construct */ +/* unused ZEND_BEGIN_ARG_INFO_EX(arginfo_HttpMessageServerRequest_construct, 0, 0, 0) ZEND_ARG_TYPE_INFO(0, statusCode, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, reasonPhrase, IS_STRING, 0) ZEND_END_ARG_INFO() +*/ PHP_METHOD(Response, __construct) { diff --git a/server_request.c b/server_request.c index 6b110ff..9d9116f 100644 --- a/server_request.c +++ b/server_request.c @@ -115,6 +115,7 @@ void init_headers_from_params(zval *object, HashTable *serverParams) headers = Z_ARR_P(zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv)); ZEND_HASH_FOREACH_KEY_VAL(serverParams, index, key, val) { + (void)index; /* NOOP, to avoid unused warning */ if (UNEXPECTED(key == NULL)) continue; if (ZSTR_LEN(key) > 5 && strncmp("HTTP_", ZSTR_VAL(key), 5) == 0 && EXPECTED(Z_TYPE_P(val) == IS_STRING)) { From 787594dae4509287ae7d26b53e5edf0000f8624d Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 26 Aug 2020 12:13:53 +0200 Subject: [PATCH 61/67] fix for PHP 8.0.0beta3 --- emitter.c | 22 +++--- factory.c | 8 +-- macros.h | 22 +++--- message.c | 37 +++++----- request.c | 30 ++++---- response.c | 12 ++-- server_request.c | 58 +++++++-------- stream.c | 32 ++++----- tests/Factory/createResponse_err01.phpt | 6 +- tests/Factory/createServerRequest_err01.phpt | 4 +- tests/Factory/createStreamFromFile_002.phpt | 6 +- tests/Factory/createStreamFromFile_err01.phpt | 6 +- tests/Factory/createStream_err01.phpt | 4 +- tests/Factory/createUploadedFile_err01.phpt | 14 ++-- tests/Message/body_err01.phpt | 4 +- tests/Message/headers_err01.phpt | 6 +- tests/Message/headers_err02.phpt | 6 +- tests/Message/headers_err03.phpt | 6 +- tests/Message/headers_err04.phpt | 6 +- tests/Message/headers_err05.phpt | 6 +- tests/Message/protocolVersion_err01.phpt | 4 +- tests/Request/method_err01.phpt | 4 +- tests/Request/requestTarget_err01.phpt | 4 +- tests/Request/uri_err01.phpt | 4 +- tests/Response/status_err01.phpt | 6 +- tests/ServerRequest/__construct_err01.phpt | 14 ++-- tests/ServerRequest/attributes_err01.phpt | 4 +- tests/ServerRequest/cookieParams_err01.phpt | 4 +- tests/ServerRequest/parsedBody_err01.phpt | 4 +- tests/ServerRequest/queryParams_err01.phpt | 4 +- tests/Stream/read_err02.phpt | 2 +- tests/Stream/seek_err02.phpt | 4 +- tests/Stream/write_err02.phpt | 4 +- tests/UploadedFile/__construct_err01.phpt | 12 ++-- tests/UploadedFile/moveTo_err03.phpt | 4 +- tests/UploadedFile/moveTo_err05.phpt | 2 +- tests/Uri/__construct_err01.phpt | 4 +- tests/Uri/fragment_err01.phpt | 4 +- tests/Uri/host_error.phpt | 4 +- tests/Uri/path_err01.phpt | 4 +- tests/Uri/port_err01.phpt | 2 +- tests/Uri/query_err01.phpt | 4 +- tests/Uri/scheme_err01.phpt | 4 +- tests/Uri/userInfo_err01.phpt | 4 +- uploaded_file.c | 42 +++++------ uri.c | 70 +++++++++---------- 46 files changed, 263 insertions(+), 254 deletions(-) diff --git a/emitter.c b/emitter.c index 10933ff..7003918 100644 --- a/emitter.c +++ b/emitter.c @@ -70,10 +70,10 @@ int read_response_body(zval *response, zval *contents) ZVAL_NULL(&body); ZVAL_NULL(contents); - zend_call_method_with_0_params(response, NULL, NULL, "getBody", &body); + zend_call_method_with_0_params(PROPERTY_ARG(response), NULL, NULL, "getBody", &body); if (EXPECTED(Z_TYPE(body) == IS_OBJECT)) { - zend_call_method_with_0_params(&body, NULL, NULL, "__toString", contents); + zend_call_method_with_0_params(PROPERTY_ARG(&body), NULL, NULL, "__toString", contents); } if (UNEXPECTED(Z_TYPE_P(contents) != IS_STRING)) { @@ -94,9 +94,9 @@ void emit_status(zval *response) ZVAL_NULL(&status_code); ZVAL_NULL(&reason_phrase); - zend_call_method_with_0_params(response, NULL, NULL, "getProtocolVersion", &version); - zend_call_method_with_0_params(response, NULL, NULL, "getStatusCode", &status_code); - zend_call_method_with_0_params(response, NULL, NULL, "getReasonPhrase", &reason_phrase); + zend_call_method_with_0_params(PROPERTY_ARG(response), NULL, NULL, "getProtocolVersion", &version); + zend_call_method_with_0_params(PROPERTY_ARG(response), NULL, NULL, "getStatusCode", &status_code); + zend_call_method_with_0_params(PROPERTY_ARG(response), NULL, NULL, "getReasonPhrase", &reason_phrase); code = Z_LVAL(status_code); @@ -110,12 +110,12 @@ void emit_status(zval *response) ctr.line_len = Z_STRLEN(version) + phrase_len + 10; ctr.line = emalloc(ctr.line_len); - zend_sprintf(ctr.line, "HTTP/%.*s %3lu %.*s", (int)Z_STRLEN(version), Z_STRVAL(version), code, (int)phrase_len, phrase); + zend_sprintf((char *)ctr.line, "HTTP/%.*s %3lu %.*s", (int)Z_STRLEN(version), Z_STRVAL(version), code, (int)phrase_len, phrase); ctr.response_code = code; sapi_header_op(SAPI_HEADER_REPLACE, &ctr); - efree(ctr.line); + efree((char *)ctr.line); } void emit_header(zend_string *header_name, zend_array *header_lines) @@ -130,16 +130,16 @@ void emit_header(zend_string *header_name, zend_array *header_lines) // Reuse ctr: resize if needed. if (ctr.line_len >= max_header_size) { - efree(ctr.line); + efree((char *)ctr.line); max_header_size = (ctr.line_len + 255) - ((ctr.line_len + 255) % 256); ctr.line = emalloc(max_header_size); } - zend_sprintf(ctr.line, "%s: %s", ZSTR_VAL(header_name), Z_STRVAL_P(header_line)); + zend_sprintf((char *)ctr.line, "%s: %s", ZSTR_VAL(header_name), Z_STRVAL_P(header_line)); sapi_header_op(SAPI_HEADER_ADD, &ctr); } ZEND_HASH_FOREACH_END(); - efree(ctr.line); + efree((char *)ctr.line); } void emit_headers(zval *response) @@ -149,7 +149,7 @@ void emit_headers(zval *response) zend_string *header_name; zend_long index; - zend_call_method_with_0_params(response, NULL, NULL, "getHeaders", &headers); + zend_call_method_with_0_params(PROPERTY_ARG(response), NULL, NULL, "getHeaders", &headers); ZEND_HASH_FOREACH_KEY_VAL(Z_ARR(headers), index, header_name, header_lines) { if (UNEXPECTED(header_name == NULL)) { diff --git a/factory.c b/factory.c index 9cd556c..003e063 100644 --- a/factory.c +++ b/factory.c @@ -82,8 +82,8 @@ PHP_METHOD(Factory, createRequest) if (uri_param_as_object(uri) == FAILURE) return; NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_Request_ce, 0); - zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("method"), method); - zend_update_property(HttpMessage_Request_ce, return_value, ZEND_STRL("uri"), uri); + zend_update_property_str(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("method"), method); + zend_update_property(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("uri"), uri); } PHP_METHOD(Factory, createResponse) @@ -122,8 +122,8 @@ PHP_METHOD(Factory, createServerRequest) NEW_OBJECT_CONSTRUCT(return_value, HttpMessage_ServerRequest_ce, 1, serverParams); } - zend_update_property_str(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("method"), method); - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("uri"), uri); + zend_update_property_str(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("method"), method); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("uri"), uri); } PHP_METHOD(Factory, createStream) diff --git a/macros.h b/macros.h index 58af012..4be105b 100644 --- a/macros.h +++ b/macros.h @@ -35,21 +35,27 @@ #define EXPAND( x ) x +#if PHP_VERSION_ID < 80000 +#define PROPERTY_ARG(zv) (zv) +#else +#define PROPERTY_ARG(zv) Z_OBJ_P(zv) +#endif + ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, 0, 0) ZEND_END_ARG_INFO() #define INIT_ARRAY_PROPERTY(className, property, rv) \ - array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)) + array_init(zend_read_property(className, PROPERTY_ARG(getThis()), ZEND_STRL(property), 0, &rv)) #define SET_ARRAY_PROPERTY(className, property, zval, rv) \ - if (zval == NULL) array_init(zend_read_property(className, getThis(), ZEND_STRL(property), 0, &rv)); \ - else zend_update_property(className, getThis(), ZEND_STRL(property), zval) + if (zval == NULL) array_init(zend_read_property(className, PROPERTY_ARG(getThis()), ZEND_STRL(property), 0, &rv)); \ + else zend_update_property(className, PROPERTY_ARG(getThis()), ZEND_STRL(property), zval) #define SET_STRING_PROPERTY(className, property, val) \ - if (val != NULL) zend_update_property_stringl(className, getThis(), ZEND_STRL(property), val, strlen(val)) + if (val != NULL) zend_update_property_stringl(className, PROPERTY_ARG(getThis()), ZEND_STRL(property), val, strlen(val)) #define SET_STR_PROPERTY(className, property, val) \ - if (val != NULL) zend_update_property_str(className, getThis(), ZEND_STRL(property), val) + if (val != NULL) zend_update_property_str(className, PROPERTY_ARG(getThis()), ZEND_STRL(property), val) #if PHP_VERSION_ID < 70300 #define SET_URI_PROPERTY(className, property, val) SET_STRING_PROPERTY(className, property, val) @@ -73,7 +79,7 @@ ZEND_END_ARG_INFO() #define NEW_OBJECT_CONSTRUCT(zval, ce, argc, ...) \ NEW_OBJECT(zval, ce); \ if (EXPECTED(zval != NULL)) \ - EXPAND(zend_call_method_with_## argc ##_params(zval, ce, &ce->constructor, "__construct", NULL, ## __VA_ARGS__)) + EXPAND(zend_call_method_with_## argc ##_params(PROPERTY_ARG(zval), ce, &ce->constructor, "__construct", NULL, ## __VA_ARGS__)) #define IS_STREAM_RESOURCE(zstream) \ ( \ @@ -87,10 +93,10 @@ ZEND_END_ARG_INFO() #define ARRAY_GET(arr, index, key) \ arr != NULL ? (key == NULL ? zend_hash_index_find(arr, index) : zend_hash_find(arr, key)) : NULL -#define COPY_PROPERTY_FROM_ARRAY(arr, key, className, object, property, type, val) \ +#define COPY_PROPERTY_FROM_ARRAY(arr, key, object, className, property, type, val) \ val = zend_hash_str_find(arr, ZEND_STRL(key)); \ if (val != NULL && EXPECTED(Z_TYPE_P(val) == type)) { \ - zend_update_property(object, className, ZEND_STRL(property), val); \ + zend_update_property(className, PROPERTY_ARG(object), ZEND_STRL(property), val); \ } #define Z_ARR_P_NULL(zval) zval != NULL ? Z_ARR_P(zval) : NULL diff --git a/message.c b/message.c index 8df39c8..5d4d38a 100644 --- a/message.c +++ b/message.c @@ -50,7 +50,7 @@ void add_header(zval *object, zend_string *name, zend_string *value, zend_bool a zval rv, *headers_prop, *header_values; HashTable *headers; - headers_prop = zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv); + headers_prop = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(object), ZEND_STRL("headers"), 0, &rv); if (UNEXPECTED(Z_TYPE_P(headers_prop) != IS_ARRAY)) { return; // Shouldn't happen @@ -78,7 +78,7 @@ PHP_METHOD(Message, __construct) zval rv, *body; /* $this->body = new Stream() */ - body = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + body = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("body"), 0, &rv); NEW_OBJECT_CONSTRUCT(body, HttpMessage_Stream_ce, 0); INIT_ARRAY_PROPERTY(HttpMessage_Message_ce, "headers", rv); @@ -91,7 +91,7 @@ PHP_METHOD(Message, getProtocolVersion) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("protocolVersion"), 0, &rv); + value = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("protocolVersion"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -104,9 +104,9 @@ PHP_METHOD(Message, withProtocolVersion) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Message_ce, return_value, ZEND_STRL("protocolVersion"), value); + zend_update_property_str(HttpMessage_Message_ce, PROPERTY_ARG(return_value), ZEND_STRL("protocolVersion"), value); } @@ -116,7 +116,7 @@ PHP_METHOD(Message, getHeaders) { zval rv, *headers; - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); + headers = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("headers"), 0, &rv); RETURN_ZVAL(headers, 1, 0); } @@ -131,7 +131,7 @@ PHP_METHOD(Message, hasHeader) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); + headers = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("headers"), 0, &rv); exists = zend_hash_exists(Z_ARRVAL_P(headers), name); RETVAL_BOOL(exists); @@ -146,7 +146,7 @@ PHP_METHOD(Message, getHeader) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); + headers = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("headers"), 0, &rv); header_values = zend_hash_find(Z_ARRVAL_P(headers), name); if (header_values == NULL) { @@ -166,7 +166,7 @@ PHP_METHOD(Message, getHeaderLine) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); - headers = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("headers"), 0, &rv); + headers = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("headers"), 0, &rv); header_values = zend_hash_find(Z_ARRVAL_P(headers), name); if (header_values == NULL) { @@ -174,8 +174,11 @@ PHP_METHOD(Message, getHeaderLine) } glue = zend_string_init(ZEND_STRL(", "), 0); +#if PHP_VERSION_ID < 80000 php_implode(glue, header_values, return_value); - +#else + php_implode(glue, Z_ARRVAL_P(header_values), return_value); +#endif zend_string_free(glue); } @@ -188,7 +191,7 @@ PHP_METHOD(Message, withHeader) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); add_header(return_value, name, value, 0); } @@ -202,7 +205,7 @@ PHP_METHOD(Message, withAddedHeader) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); add_header(return_value, name, value, 1); } @@ -217,9 +220,9 @@ PHP_METHOD(Message, withoutHeader) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - headers_prop = zend_read_property(HttpMessage_Message_ce, return_value, ZEND_STRL("headers"), 0, &rv); + headers_prop = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(return_value), ZEND_STRL("headers"), 0, &rv); headers = zend_array_dup(Z_ARR_P(headers_prop)); zend_hash_del(headers, name); @@ -234,7 +237,7 @@ PHP_METHOD(Message, getBody) { zval rv, *value; - value = zend_read_property(HttpMessage_Message_ce, getThis(), ZEND_STRL("body"), 0, &rv); + value = zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(getThis()), ZEND_STRL("body"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -253,9 +256,9 @@ PHP_METHOD(Message, withBody) Z_PARAM_OBJECT_OF_CLASS(value, stream_interface) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property(HttpMessage_Message_ce, return_value, ZEND_STRL("body"), value); + zend_update_property(HttpMessage_Message_ce, PROPERTY_ARG(return_value), ZEND_STRL("body"), value); } diff --git a/request.c b/request.c index b6a8524..63e4af6 100644 --- a/request.c +++ b/request.c @@ -58,11 +58,11 @@ PHP_METHOD(Request, __construct) /* parent::__construct() */ zend_call_method_with_0_params( - getThis(), HttpMessage_Message_ce, &HttpMessage_Message_ce->constructor, "__construct", NULL + PROPERTY_ARG(getThis()), HttpMessage_Message_ce, &HttpMessage_Message_ce->constructor, "__construct", NULL ); /* $this->uri = new Uri() */ - uri = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); + uri = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(getThis()), ZEND_STRL("uri"), 0, &rv); NEW_OBJECT(uri, HttpMessage_Uri_ce); } @@ -74,15 +74,15 @@ PHP_METHOD(Request, getRequestTarget) zval rv, *value, *uri, path, query; smart_str buf = {0}; - value = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("requestTarget"), 0, &rv); + value = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(getThis()), ZEND_STRL("requestTarget"), 0, &rv); if (!ZVAL_IS_NULL(value)) { RETURN_ZVAL(value, 1, 0); } - uri = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); - zend_call_method_with_0_params(uri, NULL, NULL, "getPath", &path); - zend_call_method_with_0_params(uri, NULL, NULL, "getQuery", &query); + uri = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(getThis()), ZEND_STRL("uri"), 0, &rv); + zend_call_method_with_0_params(PROPERTY_ARG(uri), NULL, NULL, "getPath", &path); + zend_call_method_with_0_params(PROPERTY_ARG(uri), NULL, NULL, "getQuery", &query); if (UNEXPECTED(Z_TYPE(path) != IS_STRING) || Z_STRLEN(path) == 0) { RETURN_STRING("/"); @@ -108,12 +108,12 @@ PHP_METHOD(Request, withRequestTarget) Z_PARAM_STR_EX(value, 1, 0) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); if (EXPECTED(value != NULL)) { - zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget"), value); + zend_update_property_str(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("requestTarget"), value); } else { - zend_update_property_null(HttpMessage_Request_ce, return_value, ZEND_STRL("requestTarget")); + zend_update_property_null(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("requestTarget")); } } @@ -124,7 +124,7 @@ PHP_METHOD(Request, getMethod) { zval rv, *value; - value = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("method"), 0, &rv); + value = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(getThis()), ZEND_STRL("method"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -137,9 +137,9 @@ PHP_METHOD(Request, withMethod) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Request_ce, return_value, ZEND_STRL("method"), value); + zend_update_property_str(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("method"), value); } @@ -149,7 +149,7 @@ PHP_METHOD(Request, getUri) { zval rv, *value; - value = zend_read_property(HttpMessage_Request_ce, getThis(), ZEND_STRL("uri"), 0, &rv); + value = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(getThis()), ZEND_STRL("uri"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -168,9 +168,9 @@ PHP_METHOD(Request, withUri) Z_PARAM_OBJECT_OF_CLASS(value, uri_interface) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property(HttpMessage_Request_ce, return_value, ZEND_STRL("uri"), value); + zend_update_property(HttpMessage_Request_ce, PROPERTY_ARG(return_value), ZEND_STRL("uri"), value); } diff --git a/response.c b/response.c index ed226be..9787501 100644 --- a/response.c +++ b/response.c @@ -54,14 +54,14 @@ int response_set_status(zval *obj, zend_long code, zend_string *phrase) return FAILURE; } - zend_update_property_long(HttpMessage_Response_ce, obj, ZEND_STRL("statusCode"), code); + zend_update_property_long(HttpMessage_Response_ce, PROPERTY_ARG(obj), ZEND_STRL("statusCode"), code); if (phrase != NULL) { - zend_update_property_str(HttpMessage_Response_ce, obj, ZEND_STRL("reasonPhrase"), phrase); + zend_update_property_str(HttpMessage_Response_ce, PROPERTY_ARG(obj), ZEND_STRL("reasonPhrase"), phrase); } else { suggested_phrase = get_status_string((int)code); zend_update_property_stringl( - HttpMessage_Response_ce, obj, ZEND_STRL("reasonPhrase"), + HttpMessage_Response_ce, PROPERTY_ARG(obj), ZEND_STRL("reasonPhrase"), suggested_phrase, strlen(suggested_phrase) ); } @@ -101,7 +101,7 @@ PHP_METHOD(Response, getStatusCode) { zval rv, *value; - value = zend_read_property(HttpMessage_Response_ce, getThis(), ZEND_STRL("statusCode"), 0, &rv); + value = zend_read_property(HttpMessage_Response_ce, PROPERTY_ARG(getThis()), ZEND_STRL("statusCode"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -110,7 +110,7 @@ PHP_METHOD(Response, getReasonPhrase) { zval rv, *value; - value = zend_read_property(HttpMessage_Response_ce, getThis(), ZEND_STRL("reasonPhrase"), 0, &rv); + value = zend_read_property(HttpMessage_Response_ce, PROPERTY_ARG(getThis()), ZEND_STRL("reasonPhrase"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -126,7 +126,7 @@ PHP_METHOD(Response, withStatus) Z_PARAM_STR_EX(phrase, 1, 0) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); response_set_status(return_value, code, phrase); } diff --git a/server_request.c b/server_request.c index 9d9116f..5a99409 100644 --- a/server_request.c +++ b/server_request.c @@ -112,7 +112,7 @@ void init_headers_from_params(zval *object, HashTable *serverParams) zend_long index; zend_string *key; - headers = Z_ARR_P(zend_read_property(HttpMessage_Message_ce, object, ZEND_STRL("headers"), 0, &rv)); + headers = Z_ARR_P(zend_read_property(HttpMessage_Message_ce, PROPERTY_ARG(object), ZEND_STRL("headers"), 0, &rv)); ZEND_HASH_FOREACH_KEY_VAL(serverParams, index, key, val) { (void)index; /* NOOP, to avoid unused warning */ @@ -140,10 +140,10 @@ void init_uri_from_params(zval *object, HashTable *serverParams) zend_long port = -1, default_port = -1; zend_bool is_http; - uri = zend_read_property(HttpMessage_Request_ce, object, ZEND_STRL("uri"), 0, &rv); + uri = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(object), ZEND_STRL("uri"), 0, &rv); request_target = zend_hash_str_find(serverParams, ZEND_STRL("REQUEST_URI")); - zend_call_method(uri, HttpMessage_Uri_ce, &HttpMessage_Uri_ce->constructor, ZEND_STRL("__construct"), NULL, + zend_call_method(PROPERTY_ARG(uri), HttpMessage_Uri_ce, &HttpMessage_Uri_ce->constructor, ZEND_STRL("__construct"), NULL, request_target == NULL ? 0 : 1, request_target, NULL); COPY_PROPERTY_FROM_ARRAY(serverParams, "HTTP_HOST", uri, HttpMessage_Uri_ce, "host", IS_STRING, tmp); @@ -164,14 +164,14 @@ void init_uri_from_params(zval *object, HashTable *serverParams) // do nothing } else if (Z_STRCMP(https, "off", 0) == 0) { default_port = 80; - zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("scheme"), ZEND_STRL("http")); + zend_update_property_stringl(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("scheme"), ZEND_STRL("http")); } else { default_port = 443; - zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("scheme"), ZEND_STRL("https")); + zend_update_property_stringl(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("scheme"), ZEND_STRL("https")); } if (port != default_port && port > 0) { - zend_update_property_long(HttpMessage_Uri_ce, uri, ZEND_STRL("port"), port); + zend_update_property_long(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("port"), port); } user = zend_hash_str_find(serverParams, ZEND_STRL("PHP_AUTH_USER")); @@ -207,7 +207,7 @@ PHP_METHOD(ServerRequest, __construct) /* parent::__construct() */ zend_call_method_with_0_params( - getThis(), HttpMessage_Request_ce, &HttpMessage_Request_ce->constructor, "__construct", NULL + PROPERTY_ARG(getThis()), HttpMessage_Request_ce, &HttpMessage_Request_ce->constructor, "__construct", NULL ); SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "serverParams", serverParams, rv); @@ -215,14 +215,14 @@ PHP_METHOD(ServerRequest, __construct) SET_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "queryParams", queryParams, rv); if (files != NULL) { - uploadedFiles = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("uploadedFiles"), 0, &rv); + uploadedFiles = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("uploadedFiles"), 0, &rv); create_uploaded_files(uploadedFiles, Z_ARR_P(files)); } else { INIT_ARRAY_PROPERTY(HttpMessage_ServerRequest_ce, "uploadedFiles", rv); } if (post != NULL) { - zend_update_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("parsedBody"), post); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("parsedBody"), post); } if (serverParams != NULL) { @@ -242,7 +242,7 @@ PHP_METHOD(ServerRequest, getServerParams) { zval rv, *value; - value = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("serverParams"), 0, &rv); + value = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("serverParams"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -254,7 +254,7 @@ PHP_METHOD(ServerRequest, getCookieParams) { zval rv, *value; - value = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("cookieParams"), 0, &rv); + value = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("cookieParams"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -267,9 +267,9 @@ PHP_METHOD(ServerRequest, withCookieParams) Z_PARAM_ARRAY(value); ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("cookieParams"), value); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("cookieParams"), value); } @@ -279,7 +279,7 @@ PHP_METHOD(ServerRequest, getQueryParams) { zval rv, *value; - value = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("queryParams"), 0, &rv); + value = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("queryParams"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -292,9 +292,9 @@ PHP_METHOD(ServerRequest, withQueryParams) Z_PARAM_ARRAY(value); ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("queryParams"), value); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("queryParams"), value); } @@ -304,7 +304,7 @@ PHP_METHOD(ServerRequest, getUploadedFiles) { zval rv, *value; - value = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("uploadedFiles"), 0, &rv); + value = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("uploadedFiles"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -321,9 +321,9 @@ PHP_METHOD(ServerRequest, withUploadedFiles) return; } - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("uploadedFiles"), value); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("uploadedFiles"), value); } @@ -333,7 +333,7 @@ PHP_METHOD(ServerRequest, getParsedBody) { zval rv, *value; - value = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("parsedBody"), 0, &rv); + value = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("parsedBody"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -346,12 +346,12 @@ PHP_METHOD(ServerRequest, withParsedBody) Z_PARAM_ARRAY_OR_OBJECT_EX(value, 1, 0); ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); if (EXPECTED(value != NULL)) { - zend_update_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody"), value); + zend_update_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("parsedBody"), value); } else { - zend_update_property_null(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("parsedBody")); + zend_update_property_null(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("parsedBody")); } } @@ -362,7 +362,7 @@ PHP_METHOD(ServerRequest, getAttributes) { zval rv, *attributes; - attributes = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); + attributes = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("attributes"), 0, &rv); RETURN_ZVAL(attributes, 1, 0); } @@ -378,7 +378,7 @@ PHP_METHOD(ServerRequest, getAttribute) Z_PARAM_ZVAL(default_value) ZEND_PARSE_PARAMETERS_END(); - attributes = zend_read_property(HttpMessage_ServerRequest_ce, getThis(), ZEND_STRL("attributes"), 0, &rv); + attributes = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(getThis()), ZEND_STRL("attributes"), 0, &rv); value = zend_hash_find(Z_ARRVAL_P(attributes), name); @@ -403,9 +403,9 @@ PHP_METHOD(ServerRequest, withAttribute) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("attributes"), 0, &rv); attributes = zend_array_dup(Z_ARR_P(attributes_prop)); zend_symtable_update(attributes, name, value); @@ -422,9 +422,9 @@ PHP_METHOD(ServerRequest, withoutAttribute) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, return_value, ZEND_STRL("attributes"), 0, &rv); + attributes_prop = zend_read_property(HttpMessage_ServerRequest_ce, PROPERTY_ARG(return_value), ZEND_STRL("attributes"), 0, &rv); attributes = zend_array_dup(Z_ARR_P(attributes_prop)); zend_symtable_del(attributes, name); diff --git a/stream.c b/stream.c index 963a2e2..226558f 100644 --- a/stream.c +++ b/stream.c @@ -49,7 +49,7 @@ void stream_seek(zval *this, zend_long offset, zend_long whence, zval* return_va zval rv, *resource; php_stream *stream; - resource = zend_read_property(HttpMessage_Stream_ce, this, ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(this), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); @@ -115,7 +115,7 @@ PHP_METHOD(Stream, __construct) return; } - zend_update_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), &resource); + zend_update_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), &resource); } PHP_METHOD(Stream, __toString) @@ -124,7 +124,7 @@ PHP_METHOD(Stream, __toString) php_stream *stream; zend_string *contents; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_EMPTY_STRING(); } @@ -161,7 +161,7 @@ PHP_METHOD(Stream, close) zval rv, *resource; php_stream *stream; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (Z_TYPE_P(resource) != IS_RESOURCE) { return; } @@ -176,10 +176,10 @@ PHP_METHOD(Stream, detach) { zval rv, *resource; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); ZVAL_COPY(return_value, resource); - zend_update_property_null(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream")); + zend_update_property_null(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream")); } PHP_METHOD(Stream, getSize) @@ -188,7 +188,7 @@ PHP_METHOD(Stream, getSize) php_stream *stream; php_stream_statbuf ssb; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_NULL(); } @@ -205,7 +205,7 @@ PHP_METHOD(Stream, tell) php_stream *stream; size_t pos; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); @@ -224,7 +224,7 @@ PHP_METHOD(Stream, eof) php_stream *stream; zend_bool eof; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_TRUE; } @@ -241,7 +241,7 @@ PHP_METHOD(Stream, isSeekable) php_stream *stream; zend_bool seekable; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } @@ -275,7 +275,7 @@ PHP_METHOD(Stream, isWritable) zval rv, *resource; php_stream *stream; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } @@ -296,7 +296,7 @@ PHP_METHOD(Stream, write) Z_PARAM_STRING(input, len) ZEND_PARSE_PARAMETERS_END(); - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); @@ -322,7 +322,7 @@ PHP_METHOD(Stream, isReadable) zval rv, *resource; php_stream *stream; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { RETURN_FALSE; } @@ -348,7 +348,7 @@ PHP_METHOD(Stream, read) return; } - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); @@ -375,7 +375,7 @@ PHP_METHOD(Stream, getContents) php_stream *stream; zend_string *contents; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); if (!IS_STREAM_RESOURCE(resource)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Stream is %s", Z_TYPE_P(resource) == IS_RESOURCE ? "closed" : "detached"); @@ -401,7 +401,7 @@ PHP_METHOD(Stream, getMetadata) zval rv, fname, *resource, *zvalue; zend_string *key = NULL; - resource = zend_read_property(HttpMessage_Stream_ce, getThis(), ZEND_STRL("stream"), 0, &rv); + resource = zend_read_property(HttpMessage_Stream_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR(key) diff --git a/tests/Factory/createResponse_err01.phpt b/tests/Factory/createResponse_err01.phpt index 84cbda0..5c741ec 100644 --- a/tests/Factory/createResponse_err01.phpt +++ b/tests/Factory/createResponse_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Factory::createResponse() must be of the type int, string given -Argument 2 passed to HttpMessage\Factory::createResponse() must be of the type string, array given +--EXPECTF-- +%sttpMessage\Factory::createResponse()%sint, string given +%sttpMessage\Factory::createResponse()%sstring, array given diff --git a/tests/Factory/createServerRequest_err01.phpt b/tests/Factory/createServerRequest_err01.phpt index a36e8a7..f30c26b 100644 --- a/tests/Factory/createServerRequest_err01.phpt +++ b/tests/Factory/createServerRequest_err01.phpt @@ -29,8 +29,8 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 0 given HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 1 given HttpMessage\Factory::createServerRequest() expects parameter 1 to be a string or object that implements Psr\Http\Message\UriInterface, array given -Argument 3 passed to HttpMessage\Factory::createServerRequest() must be of the type array, string given +%sttpMessage\Factory::createServerRequest()%sarray, string given diff --git a/tests/Factory/createStreamFromFile_002.phpt b/tests/Factory/createStreamFromFile_002.phpt index 3fe8934..9feb45f 100644 --- a/tests/Factory/createStreamFromFile_002.phpt +++ b/tests/Factory/createStreamFromFile_002.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given -Argument 2 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given +--EXPECTF-- +%sttpMessage\Factory::createStreamFromFile()%sstring, array given +%sttpMessage\Factory::createStreamFromFile()%sstring, array given diff --git a/tests/Factory/createStreamFromFile_err01.phpt b/tests/Factory/createStreamFromFile_err01.phpt index d4099ad..0d8b8f1 100644 --- a/tests/Factory/createStreamFromFile_err01.phpt +++ b/tests/Factory/createStreamFromFile_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given -Argument 2 passed to HttpMessage\Factory::createStreamFromFile() must be of the type string, array given \ No newline at end of file +--EXPECTF-- +%sttpMessage\Factory::createStreamFromFile()%sstring, array given +%sttpMessage\Factory::createStreamFromFile()%sstring, array given diff --git a/tests/Factory/createStream_err01.phpt b/tests/Factory/createStream_err01.phpt index 4cff867..be23af2 100644 --- a/tests/Factory/createStream_err01.phpt +++ b/tests/Factory/createStream_err01.phpt @@ -11,5 +11,5 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Factory::createStream() must be of the type string, array given \ No newline at end of file +--EXPECTF-- +%sttpMessage\Factory::createStream()%sstring, array given diff --git a/tests/Factory/createUploadedFile_err01.phpt b/tests/Factory/createUploadedFile_err01.phpt index 73cced9..0bc72b9 100644 --- a/tests/Factory/createUploadedFile_err01.phpt +++ b/tests/Factory/createUploadedFile_err01.phpt @@ -42,10 +42,10 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Factory::createUploadedFile() must implement interface Psr\Http\Message\StreamInterface, string given -Argument 1 passed to HttpMessage\Factory::createUploadedFile() must implement interface Psr\Http\Message\StreamInterface, instance of stdClass given -Argument 2 passed to HttpMessage\Factory::createUploadedFile() must be of the type int or null, array given -Argument 3 passed to HttpMessage\Factory::createUploadedFile() must be of the type int, array given -Argument 4 passed to HttpMessage\Factory::createUploadedFile() must be of the type string or null, array given -Argument 5 passed to HttpMessage\Factory::createUploadedFile() must be of the type string or null, array given \ No newline at end of file +--EXPECTF-- +%sttpMessage\Factory::createUploadedFile()%s Psr\Http\Message\StreamInterface, string given +%sttpMessage\Factory::createUploadedFile()%s Psr\Http\Message\StreamInterface,%sstdClass given +%sttpMessage\Factory::createUploadedFile()%s, array given +%sttpMessage\Factory::createUploadedFile()%sint, array given +%sttpMessage\Factory::createUploadedFile()%s, array given +%sttpMessage\Factory::createUploadedFile()%s, array given diff --git a/tests/Message/body_err01.phpt b/tests/Message/body_err01.phpt index dd0c826..571fb38 100644 --- a/tests/Message/body_err01.phpt +++ b/tests/Message/body_err01.phpt @@ -18,6 +18,6 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Message::withBody() must implement interface Psr\Http\Message\StreamInterface, resource given +--EXPECTF-- +%sttpMessage\Message::withBody()%s Psr\Http\Message\StreamInterface, resource given HttpMessage\Message::withBody() expects exactly 1 parameter, 0 given diff --git a/tests/Message/headers_err01.phpt b/tests/Message/headers_err01.phpt index f1accf9..84332bc 100644 --- a/tests/Message/headers_err01.phpt +++ b/tests/Message/headers_err01.phpt @@ -23,7 +23,7 @@ try { } ?> ---EXPECT-- -HttpMessage\Message::withHeader() expects parameter 2 to be string, array given +--EXPECTF-- +HttpMessage\Message::withHeader()%sstring, array given HttpMessage\Message::withHeader() expects exactly 2 parameters, 1 given -HttpMessage\Message::withHeader() expects parameter 1 to be string, array given +HttpMessage\Message::withHeader()%sstring, array given diff --git a/tests/Message/headers_err02.phpt b/tests/Message/headers_err02.phpt index ed7a57a..607fa13 100644 --- a/tests/Message/headers_err02.phpt +++ b/tests/Message/headers_err02.phpt @@ -23,7 +23,7 @@ try { } ?> ---EXPECT-- -HttpMessage\Message::withAddedHeader() expects parameter 2 to be string, array given +--EXPECTF-- +HttpMessage\Message::withAddedHeader()%sstring, array given HttpMessage\Message::withAddedHeader() expects exactly 2 parameters, 1 given -HttpMessage\Message::withAddedHeader() expects parameter 1 to be string, array given +HttpMessage\Message::withAddedHeader()%sstring, array given diff --git a/tests/Message/headers_err03.phpt b/tests/Message/headers_err03.phpt index 604aae1..ed65c5a 100644 --- a/tests/Message/headers_err03.phpt +++ b/tests/Message/headers_err03.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -HttpMessage\Message::withoutHeader() expects parameter 1 to be string, array given -HttpMessage\Message::withoutHeader() expects exactly 1 parameter, 0 given \ No newline at end of file +--EXPECTF-- +HttpMessage\Message::withoutHeader()%sstring, array given +HttpMessage\Message::withoutHeader() expects exactly 1 parameter, 0 given diff --git a/tests/Message/headers_err04.phpt b/tests/Message/headers_err04.phpt index 85b1a6d..2be1ac0 100644 --- a/tests/Message/headers_err04.phpt +++ b/tests/Message/headers_err04.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -HttpMessage\Message::getHeader() expects parameter 1 to be string, array given -HttpMessage\Message::getHeader() expects exactly 1 parameter, 0 given \ No newline at end of file +--EXPECTF-- +HttpMessage\Message::getHeader()%sstring, array given +HttpMessage\Message::getHeader() expects exactly 1 parameter, 0 given diff --git a/tests/Message/headers_err05.phpt b/tests/Message/headers_err05.phpt index 62a28c9..ab2b43f 100644 --- a/tests/Message/headers_err05.phpt +++ b/tests/Message/headers_err05.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- -HttpMessage\Message::getHeaderLine() expects parameter 1 to be string, array given -HttpMessage\Message::getHeaderLine() expects exactly 1 parameter, 0 given \ No newline at end of file +--EXPECTF-- +HttpMessage\Message::getHeaderLine()%sstring, array given +HttpMessage\Message::getHeaderLine() expects exactly 1 parameter, 0 given diff --git a/tests/Message/protocolVersion_err01.phpt b/tests/Message/protocolVersion_err01.phpt index d22a35b..6401d49 100644 --- a/tests/Message/protocolVersion_err01.phpt +++ b/tests/Message/protocolVersion_err01.phpt @@ -16,6 +16,6 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Message::withProtocolVersion() expects exactly 1 parameter, 0 given -HttpMessage\Message::withProtocolVersion() expects parameter 1 to be string, array given \ No newline at end of file +HttpMessage\Message::withProtocolVersion()%sstring, array given diff --git a/tests/Request/method_err01.phpt b/tests/Request/method_err01.phpt index e532071..4396100 100644 --- a/tests/Request/method_err01.phpt +++ b/tests/Request/method_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Request::withMethod() expects exactly 1 parameter, 0 given -HttpMessage\Request::withMethod() expects parameter 1 to be string, array given +HttpMessage\Request::withMethod()%sstring, array given diff --git a/tests/Request/requestTarget_err01.phpt b/tests/Request/requestTarget_err01.phpt index ff11a06..2d93d63 100644 --- a/tests/Request/requestTarget_err01.phpt +++ b/tests/Request/requestTarget_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Request::withRequestTarget() expects exactly 1 parameter, 0 given -HttpMessage\Request::withRequestTarget() expects parameter 1 to be string, array given +HttpMessage\Request::withRequestTarget()%sstring, array given diff --git a/tests/Request/uri_err01.phpt b/tests/Request/uri_err01.phpt index f6ba3a7..697e754 100644 --- a/tests/Request/uri_err01.phpt +++ b/tests/Request/uri_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Request::withUri() expects exactly 1 parameter, 0 given -Argument 1 passed to HttpMessage\Request::withUri() must implement interface Psr\Http\Message\UriInterface, string given +%sttpMessage\Request::withUri()%sPsr\Http\Message\UriInterface, string given diff --git a/tests/Response/status_err01.phpt b/tests/Response/status_err01.phpt index 9c028ea..5111e7d 100644 --- a/tests/Response/status_err01.phpt +++ b/tests/Response/status_err01.phpt @@ -23,7 +23,7 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\Response::withStatus() expects at least 1 parameter, 0 given -HttpMessage\Response::withStatus() expects parameter 1 to be int, string given -HttpMessage\Response::withStatus() expects parameter 2 to be string, array given \ No newline at end of file +HttpMessage\Response::withStatus()%sint, string given +HttpMessage\Response::withStatus()%sstring, array given diff --git a/tests/ServerRequest/__construct_err01.phpt b/tests/ServerRequest/__construct_err01.phpt index 358d824..586d505 100644 --- a/tests/ServerRequest/__construct_err01.phpt +++ b/tests/ServerRequest/__construct_err01.phpt @@ -40,10 +40,10 @@ try { } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given -Argument 2 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given -Argument 3 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given -Argument 3 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given -Argument 4 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given -Argument 5 passed to HttpMessage\ServerRequest::__construct() must be of the type array, string given +--EXPECTF-- +%sttpMessage\ServerRequest::__construct()%sarray, string given +%sttpMessage\ServerRequest::__construct()%sarray, string given +%sttpMessage\ServerRequest::__construct()%sarray, string given +%sttpMessage\ServerRequest::__construct()%sarray, string given +%sttpMessage\ServerRequest::__construct()%sarray, string given +%sttpMessage\ServerRequest::__construct()%sarray, string given diff --git a/tests/ServerRequest/attributes_err01.phpt b/tests/ServerRequest/attributes_err01.phpt index 5299da3..b679674 100644 --- a/tests/ServerRequest/attributes_err01.phpt +++ b/tests/ServerRequest/attributes_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\ServerRequest::withAttribute() expects exactly 2 parameters, 1 given -HttpMessage\ServerRequest::withAttribute() expects parameter 1 to be string, array given \ No newline at end of file +HttpMessage\ServerRequest::withAttribute()%s string, array given diff --git a/tests/ServerRequest/cookieParams_err01.phpt b/tests/ServerRequest/cookieParams_err01.phpt index 55c1475..f1d4071 100644 --- a/tests/ServerRequest/cookieParams_err01.phpt +++ b/tests/ServerRequest/cookieParams_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\ServerRequest::withCookieParams() expects exactly 1 parameter, 0 given -Argument 1 passed to HttpMessage\ServerRequest::withCookieParams() must be of the type array, string given \ No newline at end of file +%sttpMessage\ServerRequest::withCookieParams()%s array, string given diff --git a/tests/ServerRequest/parsedBody_err01.phpt b/tests/ServerRequest/parsedBody_err01.phpt index b148260..ec2a019 100644 --- a/tests/ServerRequest/parsedBody_err01.phpt +++ b/tests/ServerRequest/parsedBody_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given -HttpMessage\ServerRequest::withParsedBody() expects parameter 1 to be array, string given \ No newline at end of file +HttpMessage\ServerRequest::withParsedBody()%sarray, string given diff --git a/tests/ServerRequest/queryParams_err01.phpt b/tests/ServerRequest/queryParams_err01.phpt index d66f8ca..593bdf7 100644 --- a/tests/ServerRequest/queryParams_err01.phpt +++ b/tests/ServerRequest/queryParams_err01.phpt @@ -17,6 +17,6 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given -Argument 1 passed to HttpMessage\ServerRequest::withQueryParams() must be of the type array, string given \ No newline at end of file +%sttpMessage\ServerRequest::withQueryParams()%s array, string given diff --git a/tests/Stream/read_err02.phpt b/tests/Stream/read_err02.phpt index 3088a37..3a32dee 100644 --- a/tests/Stream/read_err02.phpt +++ b/tests/Stream/read_err02.phpt @@ -18,5 +18,5 @@ try { } ?> --EXPECTF-- -HttpMessage\Stream::read() expects parameter 1 to be int, string given +HttpMessage\Stream::read()%s int, string given Length parameter must be equal or greater than 0 diff --git a/tests/Stream/seek_err02.phpt b/tests/Stream/seek_err02.phpt index 70f7de1..8ab5755 100644 --- a/tests/Stream/seek_err02.phpt +++ b/tests/Stream/seek_err02.phpt @@ -18,5 +18,5 @@ try { } ?> --EXPECTF-- -HttpMessage\Stream::seek() expects parameter 1 to be int, string given -HttpMessage\Stream::seek() expects parameter 2 to be int, string given +HttpMessage\Stream::seek()%s int, string given +HttpMessage\Stream::seek()%s int, string given diff --git a/tests/Stream/write_err02.phpt b/tests/Stream/write_err02.phpt index 49bca61..933b338 100644 --- a/tests/Stream/write_err02.phpt +++ b/tests/Stream/write_err02.phpt @@ -11,5 +11,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Stream::write() expects parameter 1 to be string, array given \ No newline at end of file +--EXPECTF-- +HttpMessage\Stream::write()%s string, array given diff --git a/tests/UploadedFile/__construct_err01.phpt b/tests/UploadedFile/__construct_err01.phpt index 6095895..51cf776 100644 --- a/tests/UploadedFile/__construct_err01.phpt +++ b/tests/UploadedFile/__construct_err01.phpt @@ -41,10 +41,10 @@ try { } ?> ---EXPECT-- +--EXPECTF-- HttpMessage\UploadedFile::__construct() expects parameter 1 to be a string or object that implements Psr\Http\Message\StreamInterface, array given -HttpMessage\UploadedFile::__construct() expects parameter 1 to be a string or object that implements Psr\Http\Message\StreamInterface, object given -Argument 2 passed to HttpMessage\UploadedFile::__construct() must be of the type int or null, array given -Argument 3 passed to HttpMessage\UploadedFile::__construct() must be of the type int, array given -Argument 4 passed to HttpMessage\UploadedFile::__construct() must be of the type string or null, array given -Argument 5 passed to HttpMessage\UploadedFile::__construct() must be of the type string or null, array given \ No newline at end of file +HttpMessage\UploadedFile::__construct() expects parameter 1 to be a string or object that implements Psr\Http\Message\StreamInterface, %s given +%sttpMessage\UploadedFile::__construct()%s, array given +%sttpMessage\UploadedFile::__construct()%s, array given +%sttpMessage\UploadedFile::__construct()%s, array given +%sttpMessage\UploadedFile::__construct()%s, array given diff --git a/tests/UploadedFile/moveTo_err03.phpt b/tests/UploadedFile/moveTo_err03.phpt index fb12acf..46d1ab7 100644 --- a/tests/UploadedFile/moveTo_err03.phpt +++ b/tests/UploadedFile/moveTo_err03.phpt @@ -20,5 +20,5 @@ if (file_exists(sys_get_temp_dir() . '/uploadedfile') { } ?> --EXPECTF-- -Warning: HttpMessage\UploadedFile::moveTo(%s/nosuchdir/movedfile): failed to open stream: No such file or directory in %smoveTo_err03.php on line %d -Failed to move uploaded file '%s/uploadedfile' to '%s/nosuchdir/movedfile' \ No newline at end of file +Warning: HttpMessage\UploadedFile::moveTo(%s/nosuchdir/movedfile): %sailed to open stream: No such file or directory in %smoveTo_err03.php on line %d +Failed to move uploaded file '%s/uploadedfile' to '%s/nosuchdir/movedfile' diff --git a/tests/UploadedFile/moveTo_err05.phpt b/tests/UploadedFile/moveTo_err05.phpt index 12ea517..f4d5807 100644 --- a/tests/UploadedFile/moveTo_err05.phpt +++ b/tests/UploadedFile/moveTo_err05.phpt @@ -18,5 +18,5 @@ if (file_exists(sys_get_temp_dir() . '/movedfile') { } ?> --EXPECTF-- -Warning: HttpMessage\UploadedFile::moveTo(%s): failed to open stream: No such file or directory in %s on line %d +Warning: HttpMessage\UploadedFile::moveTo(%s): %sailed to open stream: No such file or directory in %s on line %d Failed to move uploaded file '%s/UploadedFile/not/exist' to '%s/movedfile' diff --git a/tests/Uri/__construct_err01.phpt b/tests/Uri/__construct_err01.phpt index 240e680..0980baa 100644 --- a/tests/Uri/__construct_err01.phpt +++ b/tests/Uri/__construct_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -Argument 1 passed to HttpMessage\Uri::__construct() must be of the type string, array given +--EXPECTF-- +%sttpMessage\Uri::__construct()%s string, array given diff --git a/tests/Uri/fragment_err01.phpt b/tests/Uri/fragment_err01.phpt index d6f4503..a088cac 100644 --- a/tests/Uri/fragment_err01.phpt +++ b/tests/Uri/fragment_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withFragment() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withFragment()%s string, array given diff --git a/tests/Uri/host_error.phpt b/tests/Uri/host_error.phpt index b0f660d..d0e1ceb 100644 --- a/tests/Uri/host_error.phpt +++ b/tests/Uri/host_error.phpt @@ -14,6 +14,6 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withHost() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withHost()%s, array given HttpMessage\Uri::withHost() expects exactly 1 parameter, 0 given diff --git a/tests/Uri/path_err01.phpt b/tests/Uri/path_err01.phpt index a8c0c55..b44e75a 100644 --- a/tests/Uri/path_err01.phpt +++ b/tests/Uri/path_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withPath() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withPath()%s string, array given diff --git a/tests/Uri/port_err01.phpt b/tests/Uri/port_err01.phpt index 68aa908..1dd9dc0 100644 --- a/tests/Uri/port_err01.phpt +++ b/tests/Uri/port_err01.phpt @@ -9,4 +9,4 @@ try { } ?> --EXPECTF-- -HttpMessage\Uri::withPort() expects parameter 1 to be int, array given +HttpMessage\Uri::withPort()%sint, array given diff --git a/tests/Uri/query_err01.phpt b/tests/Uri/query_err01.phpt index b1e084d..dc6051e 100644 --- a/tests/Uri/query_err01.phpt +++ b/tests/Uri/query_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withQuery() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withQuery()%s string, array given diff --git a/tests/Uri/scheme_err01.phpt b/tests/Uri/scheme_err01.phpt index 8530982..2df465d 100644 --- a/tests/Uri/scheme_err01.phpt +++ b/tests/Uri/scheme_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withScheme() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withScheme()%s string, array given diff --git a/tests/Uri/userInfo_err01.phpt b/tests/Uri/userInfo_err01.phpt index ca4499c..6be1486 100644 --- a/tests/Uri/userInfo_err01.phpt +++ b/tests/Uri/userInfo_err01.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withUserInfo() expects parameter 1 to be string, array given +--EXPECTF-- +HttpMessage\Uri::withUserInfo()%s string, array given diff --git a/uploaded_file.c b/uploaded_file.c index 0b2b60b..0695c63 100644 --- a/uploaded_file.c +++ b/uploaded_file.c @@ -63,7 +63,7 @@ int assert_file_available(zval *file, zval *stream, zval *moved) } else { // Can be any StreamInterface object, doesn't need to be Stream from this lib. ZVAL_STRINGL(&arg1, "uri", 3); - zend_call_method_with_1_params(stream, NULL, NULL, "getMetadata", &stream_file, &arg1); + zend_call_method_with_1_params(PROPERTY_ARG(stream), NULL, NULL, "getMetadata", &stream_file, &arg1); filename = Z_STRVAL(stream_file); STR_CLOSE(filename, Z_STRLEN(stream_file)); } @@ -144,7 +144,7 @@ int move_uploaded_stream(zval *stream, char *new_path, size_t new_path_len) int ret; // Can be any StreamInterface object, doesn't need to be Stream from this lib. - zend_call_method_with_0_params(stream, NULL, NULL, "detach", &resource); + zend_call_method_with_0_params(PROPERTY_ARG(stream), NULL, NULL, "detach", &resource); source = (php_stream*)zend_fetch_resource2_ex(&resource, "stream", php_file_le_stream(), php_file_le_pstream()); STR_CLOSE(new_path, new_path_len); @@ -182,37 +182,37 @@ void construct_uploaded_file( if (error == 0 && stream != NULL) { // Must be verified it's a StreamInterface object before passing it to this function. // Can be any StreamInterface object, doesn't need to be Stream from this lib. - zend_call_method_with_0_params(stream, NULL, NULL, "isReadable", &zreadable); + zend_call_method_with_0_params(PROPERTY_ARG(stream), NULL, NULL, "isReadable", &zreadable); if (UNEXPECTED(Z_TYPE(zreadable) != IS_TRUE)) { zend_throw_exception( spl_ce_InvalidArgumentException, "Stream provided for uploaded file is not readable", 0 ); } - zend_update_property(HttpMessage_UploadedFile_ce, object, ZEND_STRL("stream"), stream); + zend_update_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("stream"), stream); } else if (error == 0 && file != NULL) { - zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("file"), file); + zend_update_property_str(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("file"), file); } if (clientFilename != NULL) { - zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientFilename"), clientFilename); + zend_update_property_str(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("clientFilename"), clientFilename); } if (clientMediaType != NULL) { - zend_update_property_str(HttpMessage_UploadedFile_ce, object, ZEND_STRL("clientMediaType"), clientMediaType); + zend_update_property_str(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("clientMediaType"), clientMediaType); } if (size > 0) { - zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("size"), size); + zend_update_property_long(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("size"), size); } if (error < 0 || error > 8) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Invalid error code %ld", error); } - zend_update_property_long(HttpMessage_UploadedFile_ce, object, ZEND_STRL("error"), error); + zend_update_property_long(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("error"), error); if (checkUploaded < 0) { checkUploaded = SG(rfc1867_uploaded_files) != NULL; } - zend_update_property_bool(HttpMessage_UploadedFile_ce, object, ZEND_STRL("checkUploaded"), checkUploaded); + zend_update_property_bool(HttpMessage_UploadedFile_ce, PROPERTY_ARG(object), ZEND_STRL("checkUploaded"), checkUploaded); } void create_uploaded_file(zval *uploaded_file, zval *tmp_name, zval *size, zval *error, zval *name, zval *type) @@ -360,9 +360,9 @@ PHP_METHOD(UploadedFile, getStream) { zval rv, *stream, *file, *moved, mode; - file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); - stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); + file = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("file"), 0, &rv); + stream = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); + moved = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("moved"), 0, &rv); if (assert_file_available(file, stream, moved) == FAILURE) { return; @@ -388,10 +388,10 @@ PHP_METHOD(UploadedFile, moveTo) Z_PARAM_PATH(new_path, new_path_len) ZEND_PARSE_PARAMETERS_END(); - file = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("file"), 0, &rv); - stream = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("stream"), 0, &rv); - moved = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("moved"), 0, &rv); - checkUploaded = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("checkUploaded"), 0, &rv); + file = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("file"), 0, &rv); + stream = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("stream"), 0, &rv); + moved = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("moved"), 0, &rv); + checkUploaded = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("checkUploaded"), 0, &rv); if ( assert_file_available(file, stream, moved) == FAILURE || @@ -413,7 +413,7 @@ PHP_METHOD(UploadedFile, getSize) { zval rv, *value; - value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("size"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("size"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -422,7 +422,7 @@ PHP_METHOD(UploadedFile, getError) { zval rv, *value; - value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("error"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("error"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -431,7 +431,7 @@ PHP_METHOD(UploadedFile, getClientFilename) { zval rv, *value; - value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("clientFilename"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("clientFilename"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -440,7 +440,7 @@ PHP_METHOD(UploadedFile, getClientMediaType) { zval rv, *value; - value = zend_read_property(HttpMessage_UploadedFile_ce, getThis(), ZEND_STRL("clientMediaType"), 0, &rv); + value = zend_read_property(HttpMessage_UploadedFile_ce, PROPERTY_ARG(getThis()), ZEND_STRL("clientMediaType"), 0, &rv); RETURN_ZVAL(value, 1, 0); } diff --git a/uri.c b/uri.c index a0ee490..1f5b4c6 100644 --- a/uri.c +++ b/uri.c @@ -53,7 +53,7 @@ void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t } if (pass_len == 0) { - zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("userInfo"), user, user_len); + zend_update_property_stringl(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("userInfo"), user, user_len); } else { userinfo = emalloc(user_len + pass_len + 2); if (UNEXPECTED(userinfo == NULL)) return; // Memory issue @@ -62,7 +62,7 @@ void uri_set_userinfo(zval *uri, char *user, size_t user_len, char *pass, size_t pass[pass_len] = '\0'; sprintf(userinfo, "%s:%s", user, pass); - zend_update_property_stringl(HttpMessage_Uri_ce, uri, ZEND_STRL("userInfo"), userinfo, user_len + pass_len + 1); + zend_update_property_stringl(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("userInfo"), userinfo, user_len + pass_len + 1); efree(userinfo); } @@ -100,7 +100,7 @@ PHP_METHOD(Uri, __construct) SET_URI_PROPERTY(HttpMessage_Uri_ce, "fragment", info->fragment); if (info->port > 0) { - zend_update_property_long(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), info->port); + zend_update_property_long(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("port"), info->port); } #if PHP_VERSION_ID < 70300 @@ -124,13 +124,13 @@ PHP_METHOD(Uri, __toString) char *path_ptr; size_t path_len = 0; - scheme = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("scheme"), 0, &rv); - userinfo = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); - host = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); - port = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); - path = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("path"), 0, &rv); - query = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("query"), 0, &rv); - fragment = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("fragment"), 0, &rv); + scheme = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("scheme"), 0, &rv); + userinfo = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("userInfo"), 0, &rv); + host = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("host"), 0, &rv); + port = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("port"), 0, &rv); + path = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("path"), 0, &rv); + query = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("query"), 0, &rv); + fragment = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("fragment"), 0, &rv); smart_str_alloc(&buf, 0, 0); @@ -194,7 +194,7 @@ PHP_METHOD(Uri, getScheme) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("scheme"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("scheme"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -207,9 +207,9 @@ PHP_METHOD(Uri, withScheme) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("scheme"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("scheme"), value); } @@ -220,9 +220,9 @@ PHP_METHOD(Uri, getAuthority) zval rv, *userinfo, *host, *port; smart_str buf = {0}; - userinfo = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); - host = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); - port = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); + userinfo = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("userInfo"), 0, &rv); + host = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("host"), 0, &rv); + port = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("port"), 0, &rv); if (Z_STRLEN_P(host) == 0) { RETURN_EMPTY_STRING(); @@ -251,7 +251,7 @@ PHP_METHOD(Uri, getUserInfo) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("userInfo"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("userInfo"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -264,9 +264,9 @@ PHP_METHOD(Uri, withUserInfo) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("userInfo"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("userInfo"), value); } @@ -276,7 +276,7 @@ PHP_METHOD(Uri, getHost) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("host"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("host"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -289,9 +289,9 @@ PHP_METHOD(Uri, withHost) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("host"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("host"), value); } @@ -301,7 +301,7 @@ PHP_METHOD(Uri, getPort) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("port"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("port"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -315,12 +315,12 @@ PHP_METHOD(Uri, withPort) Z_PARAM_LONG_EX(value, value_is_null,1, 0) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); if (!value_is_null) { - zend_update_property_long(HttpMessage_Uri_ce, return_value, ZEND_STRL("port"), value); + zend_update_property_long(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("port"), value); } else { - zend_update_property_null(HttpMessage_Uri_ce, return_value, ZEND_STRL("port")); + zend_update_property_null(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("port")); } } @@ -331,7 +331,7 @@ PHP_METHOD(Uri, getPath) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("path"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("path"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -344,9 +344,9 @@ PHP_METHOD(Uri, withPath) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("path"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("path"), value); } @@ -356,7 +356,7 @@ PHP_METHOD(Uri, getQuery) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("query"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("query"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -369,9 +369,9 @@ PHP_METHOD(Uri, withQuery) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("query"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("query"), value); } @@ -381,7 +381,7 @@ PHP_METHOD(Uri, getFragment) { zval rv, *value; - value = zend_read_property(HttpMessage_Uri_ce, getThis(), ZEND_STRL("fragment"), 0, &rv); + value = zend_read_property(HttpMessage_Uri_ce, PROPERTY_ARG(getThis()), ZEND_STRL("fragment"), 0, &rv); RETURN_ZVAL(value, 1, 0); } @@ -394,9 +394,9 @@ PHP_METHOD(Uri, withFragment) Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); - ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis())); + ZVAL_OBJ(return_value, zend_objects_clone_obj(PROPERTY_ARG(getThis()))); - zend_update_property_str(HttpMessage_Uri_ce, return_value, ZEND_STRL("fragment"), value); + zend_update_property_str(HttpMessage_Uri_ce, PROPERTY_ARG(return_value), ZEND_STRL("fragment"), value); } From 4a76fb6ec7760b24814ef62eed50a42586808d4a Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 1 Sep 2020 11:46:28 +0200 Subject: [PATCH 62/67] Fix for when $_SERVER['HTTPS'] property doesn't exist. --- README.md | 24 +++++++++++++++++++++--- server_request.c | 7 ++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8f3f9c4..77c7b27 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,21 @@ [![Build Status](https://travis-ci.org/improved-php-library/http-message.svg?branch=master)](https://travis-ci.org/improved-php-library/http-message) [![Build status](https://ci.appveyor.com/api/projects/status/7rof1vr8mv4kam17/branch/master?svg=true)](https://ci.appveyor.com/project/jasny/http-message/branch/master) -[PSR-7 HTTP Message](https://www.php-fig.org/psr/psr-7/) implementation as PHP extension written in C. +[PSR-7 HTTP Message](https://www.php-fig.org/psr/psr-7/) implementation as PHP extension written in C. Includes a +[PSR-17](https://www.php-fig.org/psr/psr-17/) compatilbe factory and an emitter. --- ## Requirements * PHP 7.2+ -* [psr extension 0.6+](https://github.com/jbboehr/php-psr) +* [psr extension](https://github.com/jbboehr/php-psr) ## Installation The extension is [available from pecl](https://pecl.php.net/package/http_message). - pecl install psr-beta + pecl install psr pecl install http_message-beta ### Manual build @@ -38,3 +39,20 @@ Add the following line to your `php.ini` To try out the extension, you can run the following command php -a -d extension=modules/http_message.so + +# Usage + +```php +use HttpMessage\Emitter; +use HttpMessage\Factory; +use HttpMessage\ServerRequest; + +$request = new ServerRequest($_SERVER, $_COOKIE, $_GET, $_POST, $_FILES); + +$handler = new App\Psr15Handler(); // Any PSR-15 handler. +$response = $handler->handle($request); + +$emitter = new Emitter(); +$emitter->emit($response); +``` + diff --git a/server_request.c b/server_request.c index 5a99409..daa9a51 100644 --- a/server_request.c +++ b/server_request.c @@ -138,7 +138,7 @@ void init_uri_from_params(zval *object, HashTable *serverParams) { zval rv, *uri, *tmp, *request_target, *protocol, *https, *user, *pass; zend_long port = -1, default_port = -1; - zend_bool is_http; + zend_bool is_http, is_https; uri = zend_read_property(HttpMessage_Request_ce, PROPERTY_ARG(object), ZEND_STRL("uri"), 0, &rv); @@ -156,13 +156,14 @@ void init_uri_from_params(zval *object, HashTable *serverParams) protocol = zend_hash_str_find(serverParams, ZEND_STRL("SERVER_PROTOCOL")); https = zend_hash_str_find(serverParams, ZEND_STRL("HTTPS")); + is_https = https != NULL && Z_STRCMP(https, "off", 0) != 0; is_http = protocol != NULL && Z_TYPE_P(protocol) == IS_STRING ? (strncmp("HTTP/", Z_STRVAL_P(protocol), 5) == 0) - : (port > 0 && port == (Z_STRCMP(https, "off", 0) == 0 ? 80 : 443)); + : (port > 0 && port == (is_https ? 443 : 80)); if (!is_http) { // do nothing - } else if (Z_STRCMP(https, "off", 0) == 0) { + } else if (!is_https) { default_port = 80; zend_update_property_stringl(HttpMessage_Uri_ce, PROPERTY_ARG(uri), ZEND_STRL("scheme"), ZEND_STRL("http")); } else { From 26c91577076827570ccfdb35fd88f06aa123dd09 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 30 Sep 2020 10:41:06 +0200 Subject: [PATCH 63/67] relax test for 8.0.0RC1 --- tests/Factory/createServerRequest_err01.phpt | 4 ++-- tests/Message/body_err01.phpt | 2 +- tests/Message/headers_err01.phpt | 2 +- tests/Message/headers_err02.phpt | 2 +- tests/Message/headers_err03.phpt | 2 +- tests/Message/headers_err04.phpt | 2 +- tests/Message/headers_err05.phpt | 2 +- tests/Message/protocolVersion_err01.phpt | 2 +- tests/Request/method_err01.phpt | 2 +- tests/Request/requestTarget_err01.phpt | 2 +- tests/Request/uri_err01.phpt | 2 +- tests/Response/status_err01.phpt | 2 +- tests/ServerRequest/attributes_err01.phpt | 2 +- tests/ServerRequest/cookieParams_err01.phpt | 2 +- tests/ServerRequest/parsedBody_err01.phpt | 2 +- tests/ServerRequest/queryParams_err01.phpt | 2 +- tests/Stream/read_err01.phpt | 4 ++-- tests/Stream/seek_err01.phpt | 4 ++-- tests/Stream/write_err01.phpt | 4 ++-- tests/Uri/fragment_err02.phpt | 4 ++-- tests/Uri/host_error.phpt | 2 +- tests/Uri/path_err02.phpt | 4 ++-- tests/Uri/port_err02.phpt | 4 ++-- tests/Uri/query_err02.phpt | 4 ++-- tests/Uri/scheme_err02.phpt | 4 ++-- tests/Uri/userInfo_err02.phpt | 4 ++-- 26 files changed, 36 insertions(+), 36 deletions(-) diff --git a/tests/Factory/createServerRequest_err01.phpt b/tests/Factory/createServerRequest_err01.phpt index f30c26b..004abc4 100644 --- a/tests/Factory/createServerRequest_err01.phpt +++ b/tests/Factory/createServerRequest_err01.phpt @@ -30,7 +30,7 @@ try { ?> --EXPECTF-- -HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 0 given -HttpMessage\Factory::createServerRequest() expects at least 2 parameters, 1 given +HttpMessage\Factory::createServerRequest() expects at least 2 %s, 0 given +HttpMessage\Factory::createServerRequest() expects at least 2 %s, 1 given HttpMessage\Factory::createServerRequest() expects parameter 1 to be a string or object that implements Psr\Http\Message\UriInterface, array given %sttpMessage\Factory::createServerRequest()%sarray, string given diff --git a/tests/Message/body_err01.phpt b/tests/Message/body_err01.phpt index 571fb38..720ff6a 100644 --- a/tests/Message/body_err01.phpt +++ b/tests/Message/body_err01.phpt @@ -20,4 +20,4 @@ try { ?> --EXPECTF-- %sttpMessage\Message::withBody()%s Psr\Http\Message\StreamInterface, resource given -HttpMessage\Message::withBody() expects exactly 1 parameter, 0 given +HttpMessage\Message::withBody() expects exactly 1 %s, 0 given diff --git a/tests/Message/headers_err01.phpt b/tests/Message/headers_err01.phpt index 84332bc..797aff0 100644 --- a/tests/Message/headers_err01.phpt +++ b/tests/Message/headers_err01.phpt @@ -25,5 +25,5 @@ try { ?> --EXPECTF-- HttpMessage\Message::withHeader()%sstring, array given -HttpMessage\Message::withHeader() expects exactly 2 parameters, 1 given +HttpMessage\Message::withHeader() expects exactly 2 %s, 1 given HttpMessage\Message::withHeader()%sstring, array given diff --git a/tests/Message/headers_err02.phpt b/tests/Message/headers_err02.phpt index 607fa13..a9e5c9c 100644 --- a/tests/Message/headers_err02.phpt +++ b/tests/Message/headers_err02.phpt @@ -25,5 +25,5 @@ try { ?> --EXPECTF-- HttpMessage\Message::withAddedHeader()%sstring, array given -HttpMessage\Message::withAddedHeader() expects exactly 2 parameters, 1 given +HttpMessage\Message::withAddedHeader() expects exactly 2 %s, 1 given HttpMessage\Message::withAddedHeader()%sstring, array given diff --git a/tests/Message/headers_err03.phpt b/tests/Message/headers_err03.phpt index ed65c5a..5888ab3 100644 --- a/tests/Message/headers_err03.phpt +++ b/tests/Message/headers_err03.phpt @@ -19,4 +19,4 @@ try { ?> --EXPECTF-- HttpMessage\Message::withoutHeader()%sstring, array given -HttpMessage\Message::withoutHeader() expects exactly 1 parameter, 0 given +HttpMessage\Message::withoutHeader() expects exactly 1 %s, 0 given diff --git a/tests/Message/headers_err04.phpt b/tests/Message/headers_err04.phpt index 2be1ac0..b6a6762 100644 --- a/tests/Message/headers_err04.phpt +++ b/tests/Message/headers_err04.phpt @@ -19,4 +19,4 @@ try { ?> --EXPECTF-- HttpMessage\Message::getHeader()%sstring, array given -HttpMessage\Message::getHeader() expects exactly 1 parameter, 0 given +HttpMessage\Message::getHeader() expects exactly 1 %s, 0 given diff --git a/tests/Message/headers_err05.phpt b/tests/Message/headers_err05.phpt index ab2b43f..c2f2a58 100644 --- a/tests/Message/headers_err05.phpt +++ b/tests/Message/headers_err05.phpt @@ -19,4 +19,4 @@ try { ?> --EXPECTF-- HttpMessage\Message::getHeaderLine()%sstring, array given -HttpMessage\Message::getHeaderLine() expects exactly 1 parameter, 0 given +HttpMessage\Message::getHeaderLine() expects exactly 1 %s, 0 given diff --git a/tests/Message/protocolVersion_err01.phpt b/tests/Message/protocolVersion_err01.phpt index 6401d49..0f40115 100644 --- a/tests/Message/protocolVersion_err01.phpt +++ b/tests/Message/protocolVersion_err01.phpt @@ -17,5 +17,5 @@ try { } ?> --EXPECTF-- -HttpMessage\Message::withProtocolVersion() expects exactly 1 parameter, 0 given +HttpMessage\Message::withProtocolVersion() expects exactly 1 %s, 0 given HttpMessage\Message::withProtocolVersion()%sstring, array given diff --git a/tests/Request/method_err01.phpt b/tests/Request/method_err01.phpt index 4396100..95c155f 100644 --- a/tests/Request/method_err01.phpt +++ b/tests/Request/method_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\Request::withMethod() expects exactly 1 parameter, 0 given +HttpMessage\Request::withMethod() expects exactly 1 %s, 0 given HttpMessage\Request::withMethod()%sstring, array given diff --git a/tests/Request/requestTarget_err01.phpt b/tests/Request/requestTarget_err01.phpt index 2d93d63..97f976e 100644 --- a/tests/Request/requestTarget_err01.phpt +++ b/tests/Request/requestTarget_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\Request::withRequestTarget() expects exactly 1 parameter, 0 given +HttpMessage\Request::withRequestTarget() expects exactly 1 %s, 0 given HttpMessage\Request::withRequestTarget()%sstring, array given diff --git a/tests/Request/uri_err01.phpt b/tests/Request/uri_err01.phpt index 697e754..8803d73 100644 --- a/tests/Request/uri_err01.phpt +++ b/tests/Request/uri_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\Request::withUri() expects exactly 1 parameter, 0 given +HttpMessage\Request::withUri() expects exactly 1 %s, 0 given %sttpMessage\Request::withUri()%sPsr\Http\Message\UriInterface, string given diff --git a/tests/Response/status_err01.phpt b/tests/Response/status_err01.phpt index 5111e7d..75c6a82 100644 --- a/tests/Response/status_err01.phpt +++ b/tests/Response/status_err01.phpt @@ -24,6 +24,6 @@ try { ?> --EXPECTF-- -HttpMessage\Response::withStatus() expects at least 1 parameter, 0 given +HttpMessage\Response::withStatus() expects at least 1 %s, 0 given HttpMessage\Response::withStatus()%sint, string given HttpMessage\Response::withStatus()%sstring, array given diff --git a/tests/ServerRequest/attributes_err01.phpt b/tests/ServerRequest/attributes_err01.phpt index b679674..c66373b 100644 --- a/tests/ServerRequest/attributes_err01.phpt +++ b/tests/ServerRequest/attributes_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\ServerRequest::withAttribute() expects exactly 2 parameters, 1 given +HttpMessage\ServerRequest::withAttribute() expects exactly 2 %s, 1 given HttpMessage\ServerRequest::withAttribute()%s string, array given diff --git a/tests/ServerRequest/cookieParams_err01.phpt b/tests/ServerRequest/cookieParams_err01.phpt index f1d4071..1dbe3e6 100644 --- a/tests/ServerRequest/cookieParams_err01.phpt +++ b/tests/ServerRequest/cookieParams_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\ServerRequest::withCookieParams() expects exactly 1 parameter, 0 given +HttpMessage\ServerRequest::withCookieParams() expects exactly 1 %s, 0 given %sttpMessage\ServerRequest::withCookieParams()%s array, string given diff --git a/tests/ServerRequest/parsedBody_err01.phpt b/tests/ServerRequest/parsedBody_err01.phpt index ec2a019..9f5b980 100644 --- a/tests/ServerRequest/parsedBody_err01.phpt +++ b/tests/ServerRequest/parsedBody_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given +HttpMessage\ServerRequest::withQueryParams() expects exactly 1 %s, 0 given HttpMessage\ServerRequest::withParsedBody()%sarray, string given diff --git a/tests/ServerRequest/queryParams_err01.phpt b/tests/ServerRequest/queryParams_err01.phpt index 593bdf7..a7dd760 100644 --- a/tests/ServerRequest/queryParams_err01.phpt +++ b/tests/ServerRequest/queryParams_err01.phpt @@ -18,5 +18,5 @@ try { ?> --EXPECTF-- -HttpMessage\ServerRequest::withQueryParams() expects exactly 1 parameter, 0 given +HttpMessage\ServerRequest::withQueryParams() expects exactly 1 %s, 0 given %sttpMessage\ServerRequest::withQueryParams()%s array, string given diff --git a/tests/Stream/read_err01.phpt b/tests/Stream/read_err01.phpt index e774f51..d2076ff 100644 --- a/tests/Stream/read_err01.phpt +++ b/tests/Stream/read_err01.phpt @@ -11,5 +11,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Stream::read() expects exactly 1 parameter, 0 given \ No newline at end of file +--EXPECTF-- +HttpMessage\Stream::read() expects exactly 1 %s, 0 given diff --git a/tests/Stream/seek_err01.phpt b/tests/Stream/seek_err01.phpt index 098e9bb..724eac5 100644 --- a/tests/Stream/seek_err01.phpt +++ b/tests/Stream/seek_err01.phpt @@ -11,5 +11,5 @@ try { echo $e->getMessage(); } ?> ---EXPECT-- -HttpMessage\Stream::seek() expects at least 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Stream::seek() expects at least 1 %s, 0 given diff --git a/tests/Stream/write_err01.phpt b/tests/Stream/write_err01.phpt index c6f9d10..4a3a775 100644 --- a/tests/Stream/write_err01.phpt +++ b/tests/Stream/write_err01.phpt @@ -11,5 +11,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Stream::write() expects exactly 1 parameter, 0 given \ No newline at end of file +--EXPECTF-- +HttpMessage\Stream::write() expects exactly 1 %s, 0 given diff --git a/tests/Uri/fragment_err02.phpt b/tests/Uri/fragment_err02.phpt index 8e52621..b706a6a 100644 --- a/tests/Uri/fragment_err02.phpt +++ b/tests/Uri/fragment_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withFragment() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withFragment() expects exactly 1 %s, 0 given diff --git a/tests/Uri/host_error.phpt b/tests/Uri/host_error.phpt index d0e1ceb..5f00ee0 100644 --- a/tests/Uri/host_error.phpt +++ b/tests/Uri/host_error.phpt @@ -16,4 +16,4 @@ try { ?> --EXPECTF-- HttpMessage\Uri::withHost()%s, array given -HttpMessage\Uri::withHost() expects exactly 1 parameter, 0 given +HttpMessage\Uri::withHost() expects exactly 1 %s, 0 given diff --git a/tests/Uri/path_err02.phpt b/tests/Uri/path_err02.phpt index c588d02..35d6fdc 100644 --- a/tests/Uri/path_err02.phpt +++ b/tests/Uri/path_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withPath() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withPath() expects exactly 1 %s, 0 given diff --git a/tests/Uri/port_err02.phpt b/tests/Uri/port_err02.phpt index f50945c..a24b02c 100644 --- a/tests/Uri/port_err02.phpt +++ b/tests/Uri/port_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withPort() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withPort() expects exactly 1 %s, 0 given diff --git a/tests/Uri/query_err02.phpt b/tests/Uri/query_err02.phpt index c0fb791..220c2bc 100644 --- a/tests/Uri/query_err02.phpt +++ b/tests/Uri/query_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withQuery() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withQuery() expects exactly 1 %s, 0 given diff --git a/tests/Uri/scheme_err02.phpt b/tests/Uri/scheme_err02.phpt index 71f1c24..82ccc21 100644 --- a/tests/Uri/scheme_err02.phpt +++ b/tests/Uri/scheme_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withScheme() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withScheme() expects exactly 1 %s, 0 given diff --git a/tests/Uri/userInfo_err02.phpt b/tests/Uri/userInfo_err02.phpt index 93409dd..c637e0e 100644 --- a/tests/Uri/userInfo_err02.phpt +++ b/tests/Uri/userInfo_err02.phpt @@ -8,5 +8,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -HttpMessage\Uri::withUserInfo() expects exactly 1 parameter, 0 given +--EXPECTF-- +HttpMessage\Uri::withUserInfo() expects exactly 1 %s, 0 given From c1f7d14266ec23bb9006d89d630fd23e872cc439 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sat, 26 Dec 2020 22:40:53 +0100 Subject: [PATCH 64/67] Add missing autoconf files from package.xml --- build-packagexml.php | 6 +++++- package.xml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build-packagexml.php b/build-packagexml.php index 6164ed3..0784030 100644 --- a/build-packagexml.php +++ b/build-packagexml.php @@ -311,7 +311,7 @@ class PackageXMLElement extends SimpleXMLElement - PHP License + MIT License @@ -320,6 +320,10 @@ class PackageXMLElement extends SimpleXMLElement + + + + diff --git a/package.xml b/package.xml index 97de2f8..bc34da4 100644 --- a/package.xml +++ b/package.xml @@ -48,6 +48,7 @@ Fixed HttpMessage\Factory::createUri() + From ed8a773314aea639e094da19d235292cc3d83972 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 27 Dec 2020 00:43:04 +0100 Subject: [PATCH 65/67] Build for PHP 8 on AppVeyor and Travis. --- .appveyor.yml | 35 ++++++++++++++++++++++++++++------- .ci/appveyor.psm1 | 22 +++++++++++++--------- .ci/php-appveyor.psm1 | 16 ++++++++-------- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f35c73f..f193742 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,32 +5,53 @@ branches: - master - appveyor - w32 + - /^v\d+\.\d+\.\d+$/ environment: EXTNAME: http_message matrix: - PHP_VERSION: 7.2 - VC_VERSION: 15 BUILD_TYPE: Win32 + VC_VERSION: vc15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_VERSION: 7.2 - VC_VERSION: 15 BUILD_TYPE: nts-Win32 + VC_VERSION: vc15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_VERSION: 7.3 - VC_VERSION: 15 BUILD_TYPE: Win32 + VC_VERSION: vc15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_VERSION: 7.3 - VC_VERSION: 15 BUILD_TYPE: nts-Win32 + VC_VERSION: vc15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_SDK_VERSION: 2.1.9 + - PHP_VERSION: 7.4 + BUILD_TYPE: Win32 + VC_VERSION: vc15 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - PHP_VERSION: 7.4 + BUILD_TYPE: nts-Win32 + VC_VERSION: vc15 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - PHP_VERSION: 8.0 + BUILD_TYPE: Win32 + VC_VERSION: vs16 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + + - PHP_VERSION: 8.0 + BUILD_TYPE: nts-Win32 + VC_VERSION: vs16 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + + PHP_SDK_VERSION: 2.2.0 PHP_AVM: https://raw.githubusercontent.com/sergeyklay/php-appveyor/master/php-appveyor.psm1 TEST_PHP_EXECUTABLE: C:\php\php.exe @@ -77,8 +98,8 @@ install: build_script: - ps: Import-Module .\.ci\appveyor.psm1 - ps: InitializeBuildVars - - cmd: '"%VSCOMNTOOLS%\VsDevCmd" -arch=%PLATFORM%' - - cmd: '"%VCVARSALL_FILE%" %ARCH%' + - cmd: '"%VSDEVCMD%" -arch=%PLATFORM%' + - cmd: '"%VCVARSALL%" %ARCH%' - cmd: C:\php-sdk\bin\phpsdk_setvars - cmd: C:\php-devpack\phpize - cmd: configure.bat --with-prefix=C:\php --with-php-build=C:\php-devpack --disable-all --enable-http-message diff --git a/.ci/appveyor.psm1 b/.ci/appveyor.psm1 index 9ba4a39..e22786b 100644 --- a/.ci/appveyor.psm1 +++ b/.ci/appveyor.psm1 @@ -1,23 +1,27 @@ Function InitializeBuildVars { switch ($Env:VC_VERSION) { - '14' { + 'vc14' { If (-not (Test-Path $Env:VS120COMNTOOLS)) { Throw'The VS120COMNTOOLS environment variable is not set. Check your VS installation' } - $Env:VSCOMNTOOLS = $Env:VS120COMNTOOLS -replace '\\$', '' + $Env:VSDEVCMD = ($Env:VS120COMNTOOLS -replace '\\$', '') + '\VsDevCmd.bat' Break } - '15' { + 'vc15' { If (-not (Test-Path $Env:VS140COMNTOOLS)) { Throw'The VS140COMNTOOLS environment variable is not set. Check your VS installation' } - $Env:VSCOMNTOOLS = $Env:VS140COMNTOOLS -replace '\\$', '' + $Env:VSDEVCMD = ($Env:VS140COMNTOOLS -replace '\\$', '') + '\VsDevCmd.bat' Break } default { - Throw 'This script is designed to run with VS 14/15. Check your VS installation' + $Env:VSDEVCMD = Get-ChildItem -Path "${Env:ProgramFiles(x86)}" -Filter "VsDevCmd.bat" -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } + + If ("$Env:VSDEVCMD" -eq "") { + Throw 'Unable to find VsDevCmd. Check your VS installation' + } } } @@ -27,10 +31,10 @@ Function InitializeBuildVars { $Env:ARCH = 'x86' } - $SearchFilter = 'vcvarsall.bat' - $SearchInFolder = "${Env:VSCOMNTOOLS}\..\..\" + $Env:ENABLE_EXT = "--enable-{0}" -f ("${Env:EXTNAME}" -replace "_","-") - $Env:VCVARSALL_FILE = Get-ChildItem -Path $SearchInFolder -Filter $SearchFilter -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } + $SearchInFolder = (Get-Item $Env:VSDEVCMD).Directory.Parent.Parent.FullName + $Env:VCVARSALL = Get-ChildItem -Path "$SearchInFolder" -Filter "vcvarsall.bat" -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } } Function InitializeReleaseVars { @@ -49,5 +53,5 @@ Function InitializeReleaseVars { } $Env:RELEASE_FOLDER = "${Env:APPVEYOR_BUILD_FOLDER}\${Env:RELEASE_SUBFOLDER}" - $Env:RELEASE_ZIPBALL = "${Env:EXTNAME}_${Env:PLATFORM}_vc${Env:VC_VERSION}_php${Env:PHP_VERSION}_${Env:APPVEYOR_BUILD_VERSION}" + $Env:RELEASE_ZIPBALL = "${Env:EXTNAME}_${Env:PLATFORM}_${Env:VC_VERSION}_php${Env:PHP_VERSION}_${Env:APPVEYOR_BUILD_VERSION}" } diff --git a/.ci/php-appveyor.psm1 b/.ci/php-appveyor.psm1 index 2ac57ca..de0c921 100644 --- a/.ci/php-appveyor.psm1 +++ b/.ci/php-appveyor.psm1 @@ -37,7 +37,7 @@ function InstallPhpSdk { EnsureRequiredDirectoriesPresent ` -Directories bin,lib,include ` - -Prefix "${InstallPath}\phpdev\vc${VC}\${Platform}" + -Prefix "${InstallPath}\phpdev\${VC}\${Platform}" } function InstallPhp { @@ -59,10 +59,10 @@ function InstallPhp { $ReleasesPart = "releases/archives" } - $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-%7B1%7D-%7B2%7D-vc%7B3%7D-%7B4%7D.zip" -f + $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-%7B1%7D-%7B2%7D-%7B3%7D-%7B4%7D.zip" -f $ReleasesPart, $FullVersion, $BuildType, $VC, $Platform - $Archive = "C:\Downloads\php-${FullVersion}-${BuildType}-VC${VC}-${Platform}.zip" + $Archive = "C:\Downloads\php-${FullVersion}-${BuildType}-${VC}-${Platform}.zip" if (-not (Test-Path "${InstallPath}\php.exe")) { if (-not (Test-Path $Archive)) { @@ -96,17 +96,17 @@ function InstallPhpDevPack { $ReleasesPart = "releases/archives" } - $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-devel-pack-%7B1%7D-%7B2%7D-vc%7B3%7D-%7B4%7D.zip" -f + $RemoteUrl = "http://windows.php.net/downloads/%7B0%7D/php-devel-pack-%7B1%7D-%7B2%7D-%7B3%7D-%7B4%7D.zip" -f $ReleasesPart, $Version, $BuildType, $VC, $Platform - $Archive = "C:\Downloads\php-devel-pack-${Version}-${BuildType}-VC${VC}-${Platform}.zip" + $Archive = "C:\Downloads\php-devel-pack-${Version}-${BuildType}-${VC}-${Platform}.zip" if (-not (Test-Path "${InstallPath}\phpize.bat")) { if (-not (Test-Path $Archive)) { DownloadFile $RemoteUrl $Archive } - $UnzipPath = "${Env:Temp}\php-${Version}-devel-VC${VC}-${Platform}" + $UnzipPath = "${Env:Temp}\php-${Version}-devel-${VC}-${Platform}" if (-not (Test-Path "${UnzipPath}\phpize.bat")) { Expand-Item7zip $Archive $Env:Temp } @@ -143,8 +143,8 @@ function InstallPeclExtension { $TS = "ts" } - $RemoteUrl = "${BaseUri}/${LocalPart}-${TS}-vc${VC}-${Platform}.zip" - $DestinationPath = "C:\Downloads\${LocalPart}-${TS}-vc${VC}-${Platform}.zip" + $RemoteUrl = "${BaseUri}/${LocalPart}-${TS}-${VC}-${Platform}.zip" + $DestinationPath = "C:\Downloads\${LocalPart}-${TS}-${VC}-${Platform}.zip" if (-not (Test-Path "${InstallPath}\php_${Name}.dll")) { if (-not (Test-Path $DestinationPath)) { From c8954197ca7b58d32278575ca7b4ab43aa2810e0 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 27 Dec 2020 01:31:12 +0100 Subject: [PATCH 66/67] Build with pecl psr v1.0.1. Can't build for PHP8 on AppVeyor because pecl psr doesn't support it. --- .appveyor.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f193742..0a5b5a1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -41,16 +41,6 @@ environment: VC_VERSION: vc15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - PHP_VERSION: 8.0 - BUILD_TYPE: Win32 - VC_VERSION: vs16 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - - PHP_VERSION: 8.0 - BUILD_TYPE: nts-Win32 - VC_VERSION: vs16 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PHP_SDK_VERSION: 2.2.0 PHP_AVM: https://raw.githubusercontent.com/sergeyklay/php-appveyor/master/php-appveyor.psm1 @@ -87,7 +77,7 @@ install: - ps: >- InstallPeclExtension ` -Name psr ` - -Version 0.6.1 ` + -Version 1.0.1 ` -PhpVersion $Env:PHP_VERSION ` -BuildType $Env:BUILD_TYPE ` -VC $Env:VC_VERSION ` From 047857e2f8266688722be932f3650ce1d3837ed4 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Sun, 27 Dec 2020 02:00:07 +0100 Subject: [PATCH 67/67] Release as v1.0.0 --- .appveyor.yml | 2 +- .travis.yml | 2 +- package.xml | 28 ++++++++++++++++++++++------ php_http_message.h | 2 +- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0a5b5a1..9ac6bd8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -140,7 +140,7 @@ deploy: secure: 9kSFTreufYy0WOpd+eYAFa+2IjSxe1idbVAzehcTS/womadyGxVG6qTKpJnXDmTh artifact: '$(RELEASE_ZIPBALL).zip' draft: false - prerelease: true + prerelease: false force_update: true on: branch: master diff --git a/.travis.yml b/.travis.yml index a7bdaa6..960f0a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,6 +52,6 @@ deploy: file: "$RELEASE_PACKAGE" skip_cleanup: true name: "$TRAVIS_TAG" - prerelease: true + prerelease: false on: tags: true diff --git a/package.xml b/package.xml index bc34da4..b6c89f2 100644 --- a/package.xml +++ b/package.xml @@ -10,18 +10,18 @@ jasny@php.net yes - 2020-08-25 + 2020-12-27 - 0.2.2 - 0.2.0 + 1.0.0 + 1.0.0 - beta - beta + stable + stable MIT License -Fixed HttpMessage\Factory::createUri() +Release as v1.0.0 @@ -285,6 +285,22 @@ Fixed HttpMessage\Factory::createUri() http_message + + 2020-12-27 + + + 1.0.0 + 1.0.0 + + + stable + stable + + MIT License + +Release as v1.0.0 + + 2020-08-25 diff --git a/php_http_message.h b/php_http_message.h index 7df8474..0e6ea6e 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -31,7 +31,7 @@ #ifndef PHP_HTTP_MESSAGE_H #define PHP_HTTP_MESSAGE_H 1 -#define PHP_HTTP_MESSAGE_VERSION "0.2.2" +#define PHP_HTTP_MESSAGE_VERSION "1.0.0" #define PHP_HTTP_MESSAGE_EXTNAME "http_message" #ifdef PHP_WIN32