Index: cpp/bindings/swig_php_typemaps.i
===================================================================
--- cpp/bindings/swig_php_typemaps.i	(revision 0)
+++ cpp/bindings/swig_php_typemaps.i	(revision 0)
@@ -0,0 +1,450 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%wrapper %{
+    #include <limits>
+    #include <sstream>
+    #include <qpid/types/Variant.h>
+
+    /*
+     * Functions for converting from PHP values to Qpid Variants.
+     */
+
+    void listToZval(zval * const output, const qpid::types::Variant::List * const list TSRMLS_DC);
+    void mapToZval (zval * const output, const qpid::types::Variant::Map  * const map  TSRMLS_DC);
+
+    /*
+     * This macro is used to simplify the variantToZval function below by
+     * selecting the right PHP array-add function.
+     */
+    #define ADD_TO_ARRAY(type, ...) {                                      \
+        if (key == NULL)                                                   \
+            add_next_index_##type(output , ##__VA_ARGS__);                 \
+        else if (keyLength == (uint)-1)                                    \
+            add_assoc_##type(output, key , ##__VA_ARGS__);                 \
+        else                                                               \
+            add_assoc_##type##_ex(output, key, keyLength , ##__VA_ARGS__); \
+    }
+
+    /*
+     * This macro is used to simplify the variantToZval function below, by
+     * abstracting away the choice between setting a PHP value directly, or
+     * adding the value to an existing PHP array instead.
+     */
+    #define SET_OR_ADD(TYPE, type, ...)          \
+        if (add) {                               \
+            ADD_TO_ARRAY(type, ##__VA_ARGS__);   \
+        } else {                                 \
+            ZVAL_##TYPE(output , ##__VA_ARGS__); \
+        }
+
+    // Convert a Qpid Variant to a PHP value.
+    void variantToZval(
+        zval * const output,
+        const qpid::types::Variant * const variant
+        TSRMLS_DC,                      // Zend thread-safety arguments.
+        const bool add = false,         // Is output an array we should add to?
+        const char *key = NULL,         // If non-NULL, the associative array key.
+        const uint keyLength = (uint)-1 // If non-default, the length of key.
+    ) {
+        switch (variant->getType()) {
+            case qpid::types::VAR_VOID:
+                SET_OR_ADD(NULL, null);
+                break;
+            case qpid::types::VAR_BOOL:
+                SET_OR_ADD(BOOL, bool, variant->asBool());
+                break;
+            case qpid::types::VAR_UINT8:
+            case qpid::types::VAR_UINT16:
+            case qpid::types::VAR_UINT32:
+            case qpid::types::VAR_UINT64: {
+                    const uint64_t value = variant->asUint64();
+                    if (value > LONG_MAX) {
+                        SWIG_exception(SWIG_OverflowError, "unsigned integer too large for PHP");
+                        return;
+                    }
+                    SET_OR_ADD(LONG, long, (long)value);
+                }
+                break;
+            case qpid::types::VAR_INT8:
+            case qpid::types::VAR_INT16:
+            case qpid::types::VAR_INT32:
+            case qpid::types::VAR_INT64: {
+                    const int64_t value = variant->asInt64();
+                    if ((value < LONG_MIN) || (value > LONG_MAX)) {
+                        SWIG_exception(SWIG_OverflowError, "integer too large for PHP");
+                        return;
+                    }
+                    SET_OR_ADD(LONG, long, (long)value);
+                }
+                break;
+            case qpid::types::VAR_FLOAT:
+            case qpid::types::VAR_DOUBLE:
+                SET_OR_ADD(DOUBLE, double, variant->asDouble());
+                break;
+            case qpid::types::VAR_STRING: {
+                    std::string value = variant->asString();
+                    SET_OR_ADD(STRINGL, stringl, const_cast<char *>(value.c_str()), value.size(), 1);
+                }
+                break;
+            case qpid::types::VAR_LIST: {
+                    qpid::types::Variant::List list = variant->asList();
+                    if (add) {
+                        zval *array;
+                        ALLOC_INIT_ZVAL(array);
+                        listToZval(array, &list TSRMLS_CC);
+                        ADD_TO_ARRAY(zval, array);
+                    } else {
+                        listToZval(output, &list TSRMLS_CC);
+                    }
+                }
+                break;
+            case qpid::types::VAR_MAP: {
+                    qpid::types::Variant::Map map = variant->asMap();
+                    if (add) {
+                        zval *array;
+                        ALLOC_INIT_ZVAL(array);
+                        mapToZval(array, &map TSRMLS_CC);
+                        ADD_TO_ARRAY(zval, array);
+                    } else {
+                        mapToZval(output, &map TSRMLS_CC);
+                    }
+                }
+                break;
+            case qpid::types::VAR_UUID: {
+                    std::string value = variant->asUuid().str();
+                    SET_OR_ADD(STRINGL, stringl, const_cast<char *>(value.c_str()), value.size(), 1);
+                }
+                break;
+            default: // Should never happen.
+                SWIG_exception(SWIG_TypeError, "invalid variant type");
+        }
+    }
+
+    // Convert a Qpid Variant::List to a PHP value.
+    void listToZval(zval * const output, const qpid::types::Variant::List * const list TSRMLS_DC) {
+        array_init(output);
+        for (qpid::types::Variant::List::const_iterator iter = list->begin(); iter != list->end(); iter++) {
+            variantToZval(output, &*iter TSRMLS_CC, true);
+        }
+    }
+
+    // Convert a Qpid Variant::Map to a PHP value.
+    void mapToZval(zval * const output, const qpid::types::Variant::Map * const map TSRMLS_DC) {
+        array_init(output);
+        for (qpid::types::Variant::Map::const_iterator iter = map->begin(); iter != map->end(); iter++) {
+            variantToZval(output, &iter->second TSRMLS_CC, true, iter->first.c_str(), iter->first.size()+1);
+        }
+    }
+
+    /*
+     * Functions for converting from Qpid Variants to PHP variables.
+     */
+
+    qpid::types::Variant zvalToVariant(zval ** const input TSRMLS_DC);
+
+    // Convert a PHP array value to a Qpid Variant::List.
+    qpid::types::Variant::List zvalToList(zval ** const input TSRMLS_DC) {
+        qpid::types::Variant::List list;
+        HashTable *hashTable = Z_ARRVAL_PP(input);
+        HashPosition hashPosition;
+        zval **data;
+        for (zend_hash_internal_pointer_reset_ex(hashTable, &hashPosition);
+             zend_hash_get_current_data_ex(hashTable, (void**)&data, &hashPosition) == SUCCESS;
+             zend_hash_move_forward_ex(hashTable, &hashPosition))
+        {
+            list.push_back(zvalToVariant(data TSRMLS_CC));
+        }
+        return list;
+    }
+
+    // Convert a PHP hash table key to a std::string.
+    std::string zvalArrayKey(HashTable *hashTable, HashPosition *hashPosition TSRMLS_DC) {
+        char *key = NULL;
+        uint keyLength = 0;
+        ulong index;
+        const int type = zend_hash_get_current_key_ex(hashTable, &key, &keyLength, &index, 0, hashPosition);
+        switch (type) {
+            case HASH_KEY_IS_STRING:
+                return std::string(key, keyLength-1);
+            case HASH_KEY_IS_LONG: {
+                    std::stringstream stream;
+                    stream << index;
+                    return stream.str();
+                }
+            case HASH_KEY_NON_EXISTANT:
+                SWIG_exception(SWIG_TypeError, "non-existant hash key");
+                return std::string();
+            default: // Should never happen.
+                SWIG_exception(SWIG_TypeError, "unknown hash key type");
+                return std::string();
+        }
+    }
+
+    // Convert a PHP hash table to a Qpid Variant::Map.
+    qpid::types::Variant::Map zvalToMap(HashTable * const hashTable TSRMLS_DC) {
+        qpid::types::Variant::Map map;
+        HashPosition hashPosition;
+        zval **data;
+        for (zend_hash_internal_pointer_reset_ex(hashTable, &hashPosition);
+             zend_hash_get_current_data_ex(hashTable, (void**)&data, &hashPosition) == SUCCESS;
+             zend_hash_move_forward_ex(hashTable, &hashPosition))
+        {
+            const std::string key = zvalArrayKey(hashTable, &hashPosition TSRMLS_CC);
+            map[key] = zvalToVariant(data TSRMLS_CC);
+        }
+        return map;
+    }
+
+    // Convert a PHP array value to a Qpid Variant::Map.
+    qpid::types::Variant::Map zvalToMap(zval ** const input TSRMLS_DC) {
+        HashTable *hashTable = Z_ARRVAL_PP(input);
+        return zvalToMap(hashTable TSRMLS_CC);
+    }
+
+   /*
+    * Determine if a PHP array should be converted to a Qpid Variant::List
+    * in preference to converting to a Qpid Variant::Map instead.
+    *
+    * We consider a PHP array to be a "list" if the following are both true:
+    *   1. the array has no string keys.
+    *   2. all indexes are contiguous, and begin at 0.
+    *
+    * If either of these conditions are not met, then conversion to a List
+    * (which is still possible, and supported), would result in array key
+    * data loss, making List conversion non-preferable (ie conversion to Map
+    * would be better).
+    */
+   bool isZvalList(zval ** const input) {
+        // Make sure input is a PHP array.
+        if ((Z_TYPE_PP(input) != IS_ARRAY) && (Z_TYPE_PP(input) != IS_CONSTANT_ARRAY))
+            return false; // input is not a "map".
+
+        // Make sure all of the array elements have a valid key.
+        HashTable *hashTable = Z_ARRVAL_PP(input);
+        HashPosition hashPosition;
+        zval **data;
+        ulong count;
+        for (zend_hash_internal_pointer_reset_ex(hashTable, &hashPosition), count = 0;
+             zend_hash_get_current_data_ex(hashTable, (void**)&data, &hashPosition) == SUCCESS;
+             zend_hash_move_forward_ex(hashTable, &hashPosition), count++)
+        {
+            char *key = NULL;
+            uint keyLength = 0;
+            ulong index;
+            if (zend_hash_get_current_key_ex(hashTable, &key, &keyLength, &index, 0, &hashPosition) != HASH_KEY_IS_LONG)
+                return false; // The current element has a key string (or is invalid), so it's not a "list".
+            else if (index != count)
+                return false; // input has non-contiguous indexes.
+        }
+        return true;
+    }
+
+    // Convert a PHP value to a Qpid Variant.
+    qpid::types::Variant zvalToVariant(zval ** const input TSRMLS_DC) {
+        switch (Z_TYPE_PP(input)) {
+            case IS_ARRAY:
+            case IS_CONSTANT_ARRAY:
+                if (isZvalList(input)) {
+                    return zvalToList(input TSRMLS_CC);
+                } else {
+                    return zvalToMap(input TSRMLS_CC);
+                }
+            case IS_BOOL:
+                return Z_BVAL_PP(input) ? true : false;
+            case IS_DOUBLE:
+                return Z_DVAL_PP(input);
+            case IS_LONG: {
+                    const int64_t value = Z_LVAL_PP(input);
+                    if (value < 0) {
+                        if (value >= std::numeric_limits<int8_t>::min())
+                            return (int8_t)value;
+                        if (value >= std::numeric_limits<int8_t>::min())
+                            return (int16_t)value;
+                        if (value >= std::numeric_limits<int8_t>::min())
+                            return (int32_t)value;
+                        return (int64_t)value;
+                    } else {
+                        if (value <= std::numeric_limits<uint8_t>::min())
+                            return (uint8_t)value;
+                        if (value <= std::numeric_limits<uint8_t>::min())
+                            return (uint16_t)value;
+                        if (value <= std::numeric_limits<uint8_t>::min())
+                            return (uint32_t)value;
+                        return (uint64_t)value;
+                    }
+                }
+            case IS_NULL:
+                return NULL;
+            case IS_OBJECT: {
+                    // Mimic var_dump's object serialisation.
+                    char *className;
+                    zend_uint classNameLength;
+                    const int copyNeeded = zend_get_object_classname(*input, &className, &classNameLength TSRMLS_CC);
+                    const std::string key = "object(" + std::string(className, classNameLength) + ')';
+                    if (!copyNeeded) {
+                        efree(className);
+                    }
+                    qpid::types::Variant::Map map;
+                    map[key] = zvalToMap(Z_OBJPROP_PP(input) TSRMLS_CC);
+                    return map;
+                }
+            case IS_RESOURCE: {
+                    // Mimic var_dump's resource display; eg  "resource (10) of type (stream)".
+                    char * const type = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(input) TSRMLS_CC);
+                    std::stringstream stream;
+                    stream << "resource(" << Z_LVAL_PP(input) << ") of type (" << type << ')';
+                    return stream.str();
+                }
+            case IS_STRING:
+            case IS_CONSTANT:
+                return std::string(Z_STRVAL_PP(input), Z_STRLEN_PP(input));
+            default:
+                SWIG_exception(SWIG_TypeError, "unknown PHP type");
+        }
+    }
+
+%}
+
+/*
+ * Apply SWIG's existing integer typemaps to our explicit width types.
+ */
+
+%apply int                {   int8_t,  int16_t,  int32_t };
+%apply unsigned int       {  uint8_t, uint16_t, uint32_t };
+%apply long long          {                      int64_t };
+%apply unsigned long long {                     uint64_t };
+
+/*
+ * Map Qpid Variants to PHP values.
+ */
+
+%typemap(out) qpid::types::Variant::Map {
+    mapToZval($result, $1 TSRMLS_CC);
+}
+
+%typemap(out) qpid::types::Variant::Map& {
+    mapToZval($result, $1 TSRMLS_CC);
+}
+
+%typemap(out) qpid::types::Variant::List {
+    listToZval($result, $1 TSRMLS_CC);
+}
+
+%typemap(out) qpid::types::Variant::List& {
+    listToZval(return_value, $1 TSRMLS_CC);
+}
+
+%typemap(out) qpid::types::Variant {
+    variantToZval($result, $1 TSRMLS_CC);
+}
+
+%typemap(out) qpid::types::Variant& {
+    variantToZval($result, $1 TSRMLS_CC);
+}
+
+/*
+ * Map PHP values to Qpid Variants.
+ */
+
+%typemap(in) qpid::types::Variant &,
+             const qpid::types::Variant const &
+{
+    $1 = new qpid::types::Variant(zvalToVariant($input TSRMLS_CC));
+}
+
+%typemap(in) qpid::types::Variant::List &,
+             const qpid::types::Variant::List const &
+{
+    $1 = new qpid::types::Variant::List(zvalToList($input TSRMLS_CC));
+}
+
+%typemap(in) qpid::types::Variant::Map &,
+             const qpid::types::Variant::Map const &
+{
+    $1 = new qpid::types::Variant::Map(zvalToMap($input TSRMLS_CC));
+}
+
+%typemap(freearg) qpid::types::Variant & {
+    delete $1;
+}
+
+%typemap(freearg) qpid::types::Variant::Map & {
+    delete $1;
+}
+
+%typemap(freearg) qpid::types::Variant::List & {
+    delete $1;
+}
+
+/*
+ * Integer typechecks.
+ */
+
+%define %php_typecheck_range(_type,_prec)
+%typemap(typecheck,precedence=_prec) _type, const _type &
+"    $1 = ((Z_TYPE_PP($input) == IS_LONG) &&
+           (Z_LVAL_PP($input) >= std::numeric_limits<_type>::min()) &&
+           (Z_LVAL_PP($input) <= std::numeric_limits<_type>::max())
+          ) ? 0 : 1;"
+%enddef
+
+%php_typecheck_range(  int8_t,SWIG_TYPECHECK_INT8  );
+%php_typecheck_range( int16_t,SWIG_TYPECHECK_INT16 );
+%php_typecheck_range( int32_t,SWIG_TYPECHECK_INT32 );
+%php_typecheck_range( int64_t,SWIG_TYPECHECK_INT64 );
+%php_typecheck_range( uint8_t,SWIG_TYPECHECK_UINT8 );
+%php_typecheck_range(uint16_t,SWIG_TYPECHECK_UINT16);
+%php_typecheck_range(uint32_t,SWIG_TYPECHECK_UINT32);
+%php_typecheck_range(uint64_t,SWIG_TYPECHECK_UINT64);
+
+/*
+ * Variant typechecks.
+ */
+
+%typecheck(SWIG_TYPECHECK_LIST) qpid::types::Variant::List &,
+                                const qpid::types::Variant::List const &
+{
+    $1 = (isZvalList($input)) ? 1 : 0;
+}
+
+%typecheck(SWIG_TYPECHECK_MAP) qpid::types::Variant::Map &,
+                               const qpid::types::Variant::Map const &
+{
+    $1 = ((Z_TYPE_PP($input) == IS_ARRAY) ||
+          (Z_TYPE_PP($input) == IS_CONSTANT_ARRAY)) ? 1 : 0;
+}
+
+%typecheck(3000) qpid::types::Variant &,
+                 const qpid::types::Variant const &
+{
+    $1 = ((Z_TYPE_PP($input) == IS_NULL)     ||
+          (Z_TYPE_PP($input) == IS_LONG)     ||
+          (Z_TYPE_PP($input) == IS_DOUBLE)   ||
+          (Z_TYPE_PP($input) == IS_BOOL)     ||
+          (Z_TYPE_PP($input) == IS_ARRAY)    ||
+        //(Z_TYPE_PP($input) == IS_OBJECT)   ||
+          (Z_TYPE_PP($input) == IS_STRING)   ||
+        //(Z_TYPE_PP($input) == IS_RESOURCE) ||
+          (Z_TYPE_PP($input) == IS_CONSTANT) ||
+          (Z_TYPE_PP($input) == IS_CONSTANT_ARRAY)
+         ) ? 1 : 0;
+}
+
+// End of swig_php_typemaps.i

Property changes on: cpp/bindings/qpid/php
___________________________________________________________________
Added: svn:ignore
   + .deps
cqpid.cpp
cqpid.ini
cqpid.php
Makefile.in
php_cqpid.h


Index: cpp/bindings/qpid/php/Makefile.am
===================================================================
--- cpp/bindings/qpid/php/Makefile.am	(revision 0)
+++ cpp/bindings/qpid/php/Makefile.am	(revision 0)
@@ -0,0 +1,71 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if HAVE_PHP_DEVEL
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include
+
+PHP_INI_FILE = cqpid.ini
+EXTRA_DIST = php.i phpinfo.i cqpid.php $(PHP_INI_FILE)
+SWIG_OUTPUT = cqpid.cpp cqpid.php php_cqpid.h
+SWIG_FLAGS = -w401
+PHP_QPID_VERSION = -DPHP_QPID_VERSION='"$(VERSION)"'
+
+$(SWIG_OUTPUT): $(srcdir)/php.i $(srcdir)/phpinfo.i $(srcdir)/../qpid.i $(srcdir)/../../swig_php_typemaps.i
+	$(SWIG) -c++ -php $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -o cqpid.cpp $(srcdir)/php.i
+	$(SED) -i -e 's/\(qpid_messaging_\w*\)_qpid_messaging/\1/g' \
+	          -e 's/zend_error_noreturn/zend_error/g' cqpid.cpp
+	$(SED) -i -e 's/\(qpid_messaging_\w*\)_qpid_messaging/\1/g' \
+	          -e 's/\(class\|function\|new\) qpid_messaging_/\1 /g' \
+	          -e 's/\(static function \(FOREVER\|IMMEDIATE\|SECOND\|MINUTE\)()\)/const \2 = QPID_MESSAGING_DURATION_\2; \1/' \
+		cqpid.php
+	if test $(PHP_VERSION) -ge 50300; then \
+		$(SED) -i -e 's/^<?php/<?php namespace qpid\\messaging;/' cqpid.php; \
+	fi
+
+$(PHP_INI_FILE): cqpid.la
+	echo '; configuration for PHP Qpid module' > $(PHP_INI_FILE)
+	echo "extension=$(PHP_EXTENSION_DIR)/"`$(SED) -ne "s/^dlname='\(.*\)'/\1/p" cqpid.la` >> $(PHP_INI_FILE)
+
+if HAVE_PHP_DYNAMIC_INSTALL
+phplibarchdir = $(PHP_EXTENSION_DIR)
+phplibarch_LTLIBRARIES = cqpid.la
+cqpid_la_LDFLAGS = -avoid-version -module -shared
+cqpid_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \
+	$(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la
+cqpid_la_CXXFLAGS = -fpic $(INCLUDES) $(PHP_DEV_INCLUDES) $(PHP_QPID_VERSION)
+nodist_cqpid_la_SOURCES = cqpid.cpp
+cqpid_confdir = $(PHP_CONFIG_DIR)
+cqpid_conf_DATA = $(PHP_INI_FILE)
+endif
+
+if HAVE_PHP_STATIC_INSTALL
+cqpid_staticdir = $(PHP_INCLUDE_DIR)
+cqpid_static_DATA = cqpid.cpp
+cqpid_static_HEADERS = php_cqpid.h
+endif
+
+if HAVE_PHP_WRAPPER_INSTALL
+cqpid_wrapperdir = $(PHP_WRAPPER_DIR)
+cqpid_wrapper_DATA = cqpid.php
+endif
+
+CLEANFILES = $(SWIG_OUTPUT) $(PHP_INI_FILE)
+
+endif # HAVE_PHP_DEVEL
Index: cpp/bindings/qpid/php/phpinfo.i
===================================================================
--- cpp/bindings/qpid/php/phpinfo.i	(revision 0)
+++ cpp/bindings/qpid/php/phpinfo.i	(revision 0)
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* Expose the SWIG_VERSION macro to C/C++ code */
+%header {
+    static const size_t __SWIG_VERSION__ = SWIG_VERSION;
+}
+
+/* Define our phpinfo print function */
+%pragma(php) phpinfo = %{
+    php_info_print_table_start();
+
+    // Qpid Information.
+#ifdef PHP_QPID_VERSION
+    php_info_print_table_row(2, "Qpid Version", PHP_QPID_VERSION);
+#endif
+
+    // SWIG Information.
+    size_t swigVersions[3] = {
+        __SWIG_VERSION__ >> 16,
+        __SWIG_VERSION__ >> 8 & 0xFF,
+        __SWIG_VERSION__ & 0xFF
+    };
+    std::stringstream swigVersion;
+    swigVersion << swigVersions[0] << '.' << swigVersions[1] << '.' << swigVersions[2];
+    php_info_print_table_row(2, "SWIG Version", swigVersion.str().c_str());
+
+    // PHP Information.
+    size_t phpVersions[3] = {
+        PHP_VERSION_ID / 100 / 100,
+        PHP_VERSION_ID / 100 % 100,
+        PHP_VERSION_ID % 100
+    };
+    std::stringstream phpVersion;
+    phpVersion << phpVersions[0] << '.' << phpVersions[1] << '.' << phpVersions[2]
+               << " (" << PHP_VERSION << ')';
+    php_info_print_table_row(2, "Targeted PHP Version", phpVersion.str().c_str());
+#ifdef ZTS
+    php_info_print_table_row(2, "PHP Thread Safety", "enabled");
+#else
+    php_info_print_table_row(2, "PHP Thread Safety", "disabled");
+#endif
+
+    // Compiler Information.
+#ifdef __GNUC__
+    std::stringstream gccVersion;
+    gccVersion << "gcc " << __GNUC__;
+#ifdef __GNUC_MINOR__
+    gccVersion << '.' << __GNUC_MINOR__;
+#ifdef __GNUC_PATCHLEVEL__
+    gccVersion << '.' << __GNUC_PATCHLEVEL__;
+#endif
+#endif
+    php_info_print_table_row(2, "Compiler Version", gccVersion.str().c_str());
+#endif
+    // TODO: Add other compiler types.
+
+    // Other build information.
+    php_info_print_table_row(2, "Build Date", __DATE__" "__TIME__);
+
+    php_info_print_table_end();
+%}
+
+// End of phpinfo.i
Index: cpp/bindings/qpid/php/php.i
===================================================================
--- cpp/bindings/qpid/php/php.i	(revision 0)
+++ cpp/bindings/qpid/php/php.i	(revision 0)
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+%module cqpid
+
+%include "std_string.i"
+
+/* Include the PHP-specific SWIG typemaps */
+%include "../../swig_php_typemaps.i"
+
+/* Include our phpinfo support */
+%include "phpinfo.i"
+
+/* Define the general-purpose exception handling */
+%exception {
+    try {
+        $action
+    } catch (const qpid::messaging::MessagingException &ex) {
+        SWIG_exception(SWIG_RuntimeError, ex.what());
+    }
+}
+
+/*
+ * Apply a custom prefix to all SWIG-generated global functions.  This is not
+ * only good practice, but is necessary for this module since without doing so
+ * the Session::commit method would be exposed as session_commit which clashes
+ * with the PHP built-in session_commit function preventing the PHP
+ * interpreter from loading.
+ *
+ * See https://sourceforge.net/tracker/?func=detail&aid=3168551&group_id=1645&atid=351645
+ * for more details.
+ */
+%rename("qpid_messaging_%s") "";
+/*
+ * Unfortunately the %rename directive above will result in the wrapper
+ * classes also being prefixed, so for example the Connection class will become
+ * qpid_messaging_Connection.  Thus we strip the prefix from wrapper class
+ * names later in the build system.
+ *
+ * Alternatively, we could perform a narrow %rename of just functions, not
+ * classes, such as: %rename("qpid_messagins_%s", %$isfunction) "";  However,
+ * that will still result in some non-prefixed global functions, such as
+ * new_Session and Session_copy, which can still cause conflicts with other
+ * modules, causing PHP to fail to start.
+ */
+
+/*
+ * Ignore some overloaded member functions for SWIG versions earlier than
+ * SWIG 2.0.2 (or else SWIG would seg-fault). See SWIG artifact 3168531.
+ */
+#if SWIG_VERSION < 0x020002 // SWIG version < 2.0.2
+%ignore qpid::messaging::Receiver::fetch       (Message&);
+%ignore qpid::messaging::Receiver::fetch       (Message&,Duration);
+%ignore qpid::messaging::Receiver::get         (Message&);
+%ignore qpid::messaging::Receiver::get         (Message&,Duration);
+%ignore qpid::messaging::Session ::nextReceiver(Receiver&);
+%ignore qpid::messaging::Session ::nextReceiver(Receiver&,Duration);
+#endif
+
+/* Rename some operators that would otherwise not be accessible to PHP */
+%rename(copy)     operator=(const Address&);
+%rename(copy)     operator=(const Message&);
+%rename(copy)     operator=(const Receiver&);
+%rename(copy)     operator=(const Sender&);
+%rename(copy)     operator=(const Session&);
+%rename(copy)     operator=(const Connection&);
+%rename(isValid)  operator bool() const;
+%rename(isNull)   operator!() const;
+%rename(multiply) operator*(const Duration& duration, uint64_t multiplier);
+%rename(multiply) operator*(uint64_t multiplier,const Duration& duration);
+
+/*
+ * PHP has no concept of constant-variables, so the following methods will
+ * never be used by SWIG/PHP (there are non-const versions which SWIG will
+ * use instead).  Ignore them, just to avoid benign SWIG warnings.
+ */
+%ignore qpid::messaging::Address::getOptions()    const;
+%ignore qpid::messaging::Message::getProperties() const;
+
+/*
+ * Define some global constants to make Duration a little easier to use (since
+ * PHP does not support operator*).  We'll modify the generated cqpid.php
+ * wrapper file to expose these as Duration class member constants too.
+ */
+%init {
+    SWIG_LONG_CONSTANT(QPID_MESSAGING_DURATION_FOREVER,   qpid::messaging::Duration::FOREVER.getMilliseconds());
+    SWIG_LONG_CONSTANT(QPID_MESSAGING_DURATION_IMMEDIATE, qpid::messaging::Duration::IMMEDIATE.getMilliseconds());
+    SWIG_LONG_CONSTANT(QPID_MESSAGING_DURATION_SECOND,    qpid::messaging::Duration::SECOND.getMilliseconds());
+    SWIG_LONG_CONSTANT(QPID_MESSAGING_DURATION_MINUTE,    qpid::messaging::Duration::MINUTE.getMilliseconds());
+}
+
+/* Include the common Qpid SWIG interface file */
+%include </home/paul/src/qpidc-0.8/bindings/qpid/qpid.i>
+
+/* Define type-agnostic codec wrapper functions */
+%pragma(php) code = %{
+
+function encode($content, $message = null) {
+    if ($message === null) {
+        $message = new Message();
+    }
+    qpid_messaging_encode($content, $message);
+    return $message;
+}
+
+function decode($message) {
+    if ($message->getContentType() == "amqp/list") {
+        return qpid_messaging_decodeList($message);
+    } else {
+        return qpid_messaging_decodeMap($message);
+    }
+}
+
+%}
+
+// End of php.i
Index: cpp/bindings/qpid/examples/php/cli/hello_world.php
===================================================================
--- cpp/bindings/qpid/examples/php/cli/hello_world.php	(revision 0)
+++ cpp/bindings/qpid/examples/php/cli/hello_world.php	(revision 0)
@@ -0,0 +1,52 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qpid\messaging;
+
+require('cqpid.php');
+
+$broker = $argc > 1 ? $argv[1] : 'localhost:5672';
+$address = $argc > 2 ? $argv[2] : 'amq.topic';
+$connectionOptions = $argc > 3 ? $argv[3] : '';
+
+try {
+    $connection = new Connection($broker, $connectionOptions);
+    $connection->open();
+    $session = $connection->createSession();
+
+    $receiver = $session->createReceiver($address);
+    $sender = $session->createSender($address);
+
+    $sender->send(new Message('Hello world!'));
+
+    $message = $receiver->fetch(new Duration(Duration::SECOND * 1));
+    print $message->getContent() . "\n";
+    $session->acknowledge();
+
+    $connection->close();
+    exit(0);
+} catch(\Exception $error) {
+    print $error->getMessage() . "\n";
+    if (isset($connection)) {
+        $connection->close();
+    }
+    exit(1);
+}
+?>
Index: cpp/bindings/qpid/examples/php/cli/map_sender.php
===================================================================
--- cpp/bindings/qpid/examples/php/cli/map_sender.php	(revision 0)
+++ cpp/bindings/qpid/examples/php/cli/map_sender.php	(revision 0)
@@ -0,0 +1,57 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qpid\messaging;
+
+require('cqpid.php');
+
+$url = $argc>1 ? $argv[1] : 'amqp:tcp:127.0.0.1:5672';
+$address = $argc>2 ? $argv[2] : 'message_queue; {create: always}';
+$connectionOptions = $argc > 3 ? $argv[3] : '';
+
+try {
+    $connection = new Connection($url, $connectionOptions);
+    $connection->open();
+    $session = $connection->createSession();
+    $sender = $session->createSender($address);
+
+    $message = new Message;
+    $content = array(
+        'id'      => 987654321,
+        'name'    => 'Widget',
+        'percent' => 0.99
+    );
+    $colours = array('red', 'green', 'white');
+    $content['colours'] = $colours;
+    $content['uuid'] = '773bb118-286c-435e-8948-71e57f9e2f97';
+    encode($content, $message);
+
+    $sender->send($message, true);
+
+    $connection->close();
+    exit(0);
+} catch(\Exception $error) {
+    print $error->getMessage() . "\n";
+    if (isset($connection)) {
+        $connection->close();
+    }
+}
+exit(1);
+?>
Index: cpp/bindings/qpid/examples/php/cli/client.php
===================================================================
--- cpp/bindings/qpid/examples/php/cli/client.php	(revision 0)
+++ cpp/bindings/qpid/examples/php/cli/client.php	(revision 0)
@@ -0,0 +1,64 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qpid\messaging;
+
+require('cqpid.php');
+
+$url = $argc>1 ? $argv[1] : 'amqp:tcp:127.0.0.1:5672';
+$connectionOptions = $argc > 2 ? $argv[2] : '';
+
+try {
+    $connection = new Connection($url, $connectionOptions);
+    $connection->open();
+    $session = $connection->createSession();
+
+    $sender = $session->createSender('service_queue');
+
+    //create temp queue & receiver...
+    $responseQueue = new Address('#response-queue; {create:always, delete:always}');
+    $receiver = $session->createReceiver($responseQueue);
+
+    // Now send some messages ...
+    $s = array(
+        'Twas brillig, and the slithy toves',
+        'Did gire and gymble in the wabe.',
+        'All mimsy were the borogroves,',
+        'And the mome raths outgrabe.'
+    );
+
+    $request = new Message();
+    $request->setReplyTo($responseQueue);
+    foreach ($s as $content) {
+       $request->setContent($content);
+       $sender->send($request);
+       $response = $receiver->fetch();
+       print $request->getContent() . ' -> ' . $response->getContent() . "\n";
+    }
+    $connection->close();
+    exit(0);
+} catch(\Exception $error) {
+    print $error->getMessage() . "\n";
+    if (isset($connection)) {
+        $connection->close();
+    }
+}
+exit(1);
+?>
Index: cpp/bindings/qpid/examples/php/cli/map_receiver.php
===================================================================
--- cpp/bindings/qpid/examples/php/cli/map_receiver.php	(revision 0)
+++ cpp/bindings/qpid/examples/php/cli/map_receiver.php	(revision 0)
@@ -0,0 +1,47 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qpid\messaging;
+
+require('cqpid.php');
+
+$url = $argc>1 ? $argv[1] : 'amqp:tcp:127.0.0.1:5672';
+$address = $argc>2 ? $argv[2] : 'message_queue; {create: always}';
+$connectionOptions = $argc > 3 ? $argv[3] : '';
+
+try {
+    $connection = new Connection($url, $connectionOptions);
+    $connection->open();
+    $session = $connection->createSession();
+    $receiver = $session->createReceiver($address);
+    $content = decode($receiver->fetch());
+    print_r($content);
+    $session->acknowledge();
+    $receiver->close();
+    $connection->close();
+    exit(0);
+} catch(\Exception $error) {
+    print $error->getMessage() . "\n";
+    if (isset($connection)) {
+        $connection->close();
+    }
+}
+exit(1);
+?>
Index: cpp/bindings/qpid/examples/php/cli/server.php
===================================================================
--- cpp/bindings/qpid/examples/php/cli/server.php	(revision 0)
+++ cpp/bindings/qpid/examples/php/cli/server.php	(revision 0)
@@ -0,0 +1,61 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace qpid\messaging;
+
+require('cqpid.php');
+
+$url = $argc>1 ? $argv[1] : 'amqp:tcp:127.0.0.1:5672';
+$connectionOptions = $argc > 3 ? $argv[3] : '';
+
+try {
+    $connection = new Connection($url, $connectionOptions);
+    $connection->open();
+    $session = $connection->createSession();
+    $receiver = $session->createReceiver('service_queue; {create: always}');
+
+    while (true) {
+        $request = $receiver->fetch();
+        $address = $request->getReplyTo();
+        if ($address->isValid()) {
+            $sender = $session->createSender($address);
+            $s = strtoupper($request->getContent());
+            $response = new Message($s);
+            $sender->send($response);
+            print 'Processed request: ' .
+                  $request->getContent() .
+                  ' -> ' .
+                  $response->getContent() . "\n";
+            $session->acknowledge();
+        } else {
+            print 'Error: no reply address specified for request: ' . $request->getContent() . "\n";
+            $session->reject($request);
+        }
+    }
+    $connection->close();
+    exit(0);
+} catch(\Exception $error) {
+    print $error->getMessage() . "\n";
+    if (isset($connection)) {
+        $connection->close();
+    }
+}
+exit(1);
+?>
Index: cpp/configure.ac
===================================================================
--- cpp/configure.ac	(revision 1075699)
+++ cpp/configure.ac	(working copy)
@@ -228,7 +228,74 @@
 fi
 AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test -f $PYTHON_INC/Python.h && test -n "$SWIG"])
 
+# PHP bindings.
 
+AC_ARG_VAR(PHP_VERSION, [PHP version number])
+AC_ARG_VAR(PHP_DEV_INCLUDES, [List of PHP development includes])
+AC_ARG_VAR(PHP_EXTENSION_DIR, [Directory to install loadable PHP extension to])
+AC_ARG_VAR(PHP_INCLUDE_DIR, [Directory to install static PHP extension header to])
+AC_ARG_VAR(PHP_WRAPPER_DIR, [Directory to install PHP class wrapper to])
+AC_ARG_VAR(PHP_CONFIG_DIR,  [Directory to install PHP ini file to])
+
+AC_CHECK_PROG([PHP], [php], [php])
+AC_CHECK_PROG([PHP_CONFIG], [php-config], [php-config])
+
+# Get details from $(PHP_CONFIG), falling back to $(PHP) if possible.
+if test -n "$PHP_CONFIG" ; then
+    if test -z "$PHP_VERSION" ; then
+        AC_MSG_CHECKING([for PHP version number])
+        PHP_VERSION=`"$PHP_CONFIG" --vernum`
+        AC_SUBST(PHP_VERSION)
+        AC_MSG_RESULT([$PHP_VERSION])
+    fi
+
+    if test -z "$PHP_DEV_INCLUDES" ; then
+        AC_MSG_CHECKING([for PHP development includes])
+        PHP_DEV_INCLUDES=`"$PHP_CONFIG" --includes`
+        AC_SUBST(PHP_DEV_INCLUDES)
+        AC_MSG_RESULT([$PHP_DEV_INCLUDES])
+    fi
+
+    if test -z "$PHP_EXTENSION_DIR" ; then
+        AC_MSG_CHECKING([for directory to install loadable PHP extension to])
+        PHP_EXTENSION_DIR=`$PHP_CONFIG --extension-dir`
+        if test -z "$PHP_EXTENSION_DIR" && test -n "$PHP" ; then
+            PHP_EXTENSION_DIR=`"$PHP" -r 'phpinfo();' | "$SED" -ne 's/^extension_dir\s\+=>\s\+\(.*\)\s\+=>.*$/\1/p'`
+        fi
+        AC_SUBST(PHP_EXTENSION_DIR)
+        AC_MSG_RESULT([$PHP_EXTENSION_DIR])
+    fi
+
+    if test -z "$PHP_INCLUDE_DIR" ; then
+        AC_MSG_CHECKING([for directory to install static PHP extension header to])
+        PHP_INCLUDE_DIR=`"$PHP_CONFIG" --include-dir`/ext/cqpid
+        AC_SUBST(PHP_INCLUE_DIR)
+        AC_MSG_RESULT([$PHP_INCLUDE_DIR])
+    fi
+
+    if test -z "$PHP_CONFIG_DIR" ; then
+        AC_MSG_CHECKING([for directory to install PHP ini file to])
+        PHP_CONFIG_DIR=`"$PHP_CONFIG" --configure-options | "$SED" -ne 's/^.*--with-config-file-scan-dir=\([[^ ]]*\).*/\1/p'`
+        AC_SUBST(PHP_INCLUE_DIR)
+        AC_MSG_RESULT([$PHP_INCLUDE_DIR])
+    fi
+fi
+
+# Get details only available from $(PHP), and not $(PHP_CONFIG).
+if test -n "$PHP" ; then
+    if test -z "$PHP_WRAPPER_DIR" ; then
+        AC_MSG_CHECKING([for directory to install PHP class wrapper to])
+        PHP_WRAPPER_DIR=`"$PHP" -r 'print get_include_path();' | "$SED" -ne 's/\(\.:\)\?\(\/[[^:]]*\).*/\2/p'`
+        AC_SUBST(PHP_WRAPPER_DIR)
+        AC_MSG_RESULT([$PHP_WRAPPER_DIR])
+    fi
+fi
+
+AM_CONDITIONAL([HAVE_PHP_DEVEL], [test -n "$PHP_DEV_INCLUDES" && test -n "$SWIG"])
+AM_CONDITIONAL([HAVE_PHP_DYNAMIC_INSTALL], [test -n "$PHP_EXTENSION_DIR" && test -n "$PHP_CONFIG_DIR"])
+AM_CONDITIONAL([HAVE_PHP_STATIC_INSTALL],  [test -n "$PHP_INCLUDE_DIR"])
+AM_CONDITIONAL([HAVE_PHP_WRAPPER_INSTALL], [test -n "$PHP_WRAPPER_DIR"])
+
 # Perl bindings:
 
 AC_CHECK_PROG([PERL], [perl], [perl])
@@ -537,6 +604,7 @@
   bindings/qpid/Makefile
   bindings/qpid/ruby/Makefile
   bindings/qpid/python/Makefile
+  bindings/qpid/php/Makefile
   bindings/qpid/perl/Makefile
   bindings/qpid/dotnet/Makefile
   bindings/qmf/Makefile
