Probably the biggest problem is that it requires C++.
We mentioned to you that C++ was something we avoided in PHP because
it tends to create more problems than it's worth, particularly so in
something that is part of the core distribution.

Can you write it in C instead?

--Wez.

On 5/12/06, Brandon Fosdick <[EMAIL PROTECTED]> wrote:
I'm not finished yet, but I'm at a decent check point, so I thought I'd send 
out what I've done so far with the hope of getting some feedback.

The attached files contain the patches and new files (wrt 5.1.4) for 
implementing import and export of PEM strings for both public and private keys 
using an OO interface. BTW, I know the code doesn't conform to the CS very 
well, I plan to run everything through astyle at the very end.

One of my initial goals was to avoid modifying existing code as much as 
possible to avoid introducing new breakage. In hindsight that might have been 
more trouble than it was worth because I ended up doing a lot more than I had 
originally planned. But it was a good learning experience. I decided on an OO 
interface because it seemed like it could be most easily accomplished w/o 
touching existing code.

At present the new interface adds two classes, described below. I wasn't sure 
what to name them, so feel free to offer suggestions.

class PrivateKey
  constructor( [string pem [, string passphrase]] )
  constructor( [array configargs]] )
  string pem( [ string passphrase [, encrypt_key]] )
  PublicKey public()

class PublicKey
  constructor(string pem)
  string pem()

I'm not sure about the second constructor for PrivateKey, since it really only 
needs two of the configarg values. I'm thinking about having it take just those 
two as separate arguments.

Most of the changes are in the new files. In openssl.c I added a call to 
init_object() in the MINIT function and moved struct php_x509_request to 
openssl.h so I could use it elsewhere. I also made a few functions non-static 
so they could be called from the other files.

From here I think I might as well add an object for certificates (X509, 
X509Certificate, Certificate...?) and then I'll add PKCS12 support.

Thoughts, suggestions? Problems?


--- config0.m4.orig     Sat Jan  1 06:32:58 2005
+++ config.m4   Wed May 10 15:14:22 2006
@@ -9,8 +9,10 @@
 [  --with-kerberos[=DIR]     OPENSSL: Include Kerberos support], no, no)

 if test "$PHP_OPENSSL" != "no"; then
-  PHP_NEW_EXTENSION(openssl, openssl.c xp_ssl.c, $ext_shared)
+  PHP_REQUIRE_CXX()
+  PHP_NEW_EXTENSION(openssl, openssl.c xp_ssl.c init_oo.cc pubkey.cc 
privkey.cc, $ext_shared)
   PHP_SUBST(OPENSSL_SHARED_LIBADD)
+  PHP_ADD_LIBRARY(stdc++, 1, OPENSSL_SHARED_LIBADD)

   if test "$PHP_KERBEROS" != "no"; then
     PHP_SETUP_KERBEROS(OPENSSL_SHARED_LIBADD)


/*      Filename:       init_oo.cc
        Object oriented OpenSSL interface for PHP5

        200600505       Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include "privkey.h"
#include "pubkey.h"

//Make storage for static members of ObjectBase
//      These are the members that don't need type-specific defaults
template<typename T> zend_class_entry* php::ObjectBase<T>::class_entry = NULL;
template<typename T> zend_object_handlers php::ObjectBase<T>::handlers;
template<typename T> zend_internal_function 
php::ObjectBase<T>::constructor_function;

namespace php
{
        namespace openssl
        {
                extern "C" void init_objects(TSRMLS_D)
                {
                        PrivateKey::register_class(TSRMLS_C);
                        PublicKey::register_class(TSRMLS_C);
                }
        }
}


/*      Filename:       objbase.h
        Base class for wrapping PHP5 Object Oriented interface

        20060501        Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

extern "C"
{
#include "php.h"
}

#ifndef OBJBASE_H
#define OBJBASE_H

namespace php
{
        template<typename T>
        class ObjectBase : public zend_object
        {
                typedef T       obj_t;

        protected:
                static const char *const name;
                static zend_class_entry*        class_entry;    //A Class Entry 
for every derived type
                static zend_object_handlers     handlers;       //Handlers for 
every derived type
                static zend_internal_function   constructor_function;   
//Function entry for the new-handler
                static zend_function_entry methods[];           //Handlers for 
derived type userland-methods

        public:
                //Base constructor
                ObjectBase(zend_class_entry *zce)
                {
                        ce = zce;
                        ALLOC_HASHTABLE(properties);
                        zend_hash_init(properties, 0, NULL, ZVAL_PTR_DTOR, 0);

                        guards = NULL;  //Init unused pointer

                        zval *tmp;
                        zend_hash_copy(properties, &zce->default_properties, 
(copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval*));
                }

                ~ObjectBase()
                {
                        //Explicitly destroy the zend_object base (it doesn't 
have its own destructor)
                        zend_object_std_dtor(static_cast<zend_object*>(this) 
TSRMLS_CC);
                }
                void*   operator new(size_t s)  {       return emalloc(s);      
}
                void    operator delete(void* p, size_t)        {       
efree(p);       }

                //Register the class
                static void register_class(TSRMLS_D)
                {
                        zend_class_entry ce;

                        memset(&ce, NULL, sizeof(ce));
                        INIT_CLASS_ENTRY(ce, name, methods);
                        ce.name_length = strlen(name);          //Work-a-round for 
"feature" in INIT_CLASS_ENTRY
                        ce.create_object = &construct;          
//psuedo-constructor
                        class_entry = zend_register_internal_class(&ce 
TSRMLS_CC);
                        if( class_entry != NULL )
                                class_entry->ce_flags |= ZEND_ACC_FINAL_CLASS;

                        handlers = *zend_get_std_object_handlers();
                        handlers.clone_obj = NULL;      //No cloning
                        handlers.get_constructor = &get_constructor;
                }

                //Construct and register a new unitialized object in a zval
                //      Used by handlers that need to return a new object
                //      Uses the static zend_class_entry object, so 
register_class() must be called first
                //      ***     This is a bare-minimum psuedo-contructor that 
calls the simplest constructor
                //                              possible, and may leave the 
class mostly uninitialized. The class probably
                //                              still needs to be initialized 
in the new()-handler.
                static obj_t* construct(zval *z TSRMLS_DC)
                {
                        if(class_entry == NULL)                                 
        //Ignore calls prior to register_class()
                                return NULL;
                        obj_t* obj = new obj_t(class_entry);    //New object 
with registered zend_class_entry
                        z->type = IS_OBJECT;
                        z->value.obj = obj->store(TSRMLS_C);
                return obj;
                }

        private:
                //Construct and then put on the object store
                //      This is function passed to the ZE by get_constructor()
                //      ***     This is a bare-minimum psuedo-contructor that 
calls the simplest constructor
                //                              possible, and may leave the 
class mostly uninitialized. The class probably
                //                              still needs to be initialized 
in the new()-handler.
                static zend_object_value construct(zend_class_entry *zce 
TSRMLS_DC)
                {
                return (new obj_t(zce))->store(TSRMLS_C);
                }

                //A destructor for every derived type
                static void     destroy(void* object TSRMLS_DC)
                {
                        delete 
static_cast<obj_t*>(static_cast<zend_object*>(object));
                }

                //Make a zend_function for the derived class' constructor 
handler
                static zend_function* get_constructor(zval* object TSRMLS_DC)
                {
                        zend_object* obj = zend_objects_get_address(object 
TSRMLS_CC);

                        if(obj == NULL)
                                return NULL;

                        memset(&constructor_function, NULL, 
sizeof(constructor_function));
                        constructor_function.type = ZEND_INTERNAL_FUNCTION;
                        constructor_function.function_name = obj->ce->name;
                        constructor_function.scope = obj->ce;
                        constructor_function.handler = 
&obj_t::ZEND_FN(construct);

                        return 
reinterpret_cast<zend_function*>(&constructor_function);
                }

                //Register the object with the ZE object store
                //      This function is private to help prevent being called 
more than once per object
                zend_object_value store(TSRMLS_D)
                {
                zend_object_value r;
                        //Downcast to a zend_object* to appease the standard 
object handlers
                        r.handle = zend_objects_store_put((zend_object*)this, NULL, 
&destroy, NULL TSRMLS_CC);
                        r.handlers = &handlers;
                        return r;
                }

        };

        template<typename T>
        inline T* get_object(zval* z TSRMLS_DC)
        {
                return 
static_cast<T*>(static_cast<zend_object*>(zend_object_store_get_object(z 
TSRMLS_CC)));
        }

        inline zend_object* get_object(zval* z TSRMLS_DC)
        {
                return static_cast<zend_object*>(zend_object_store_get_object(z 
TSRMLS_CC));
        }

}       //namespace php

#endif  //OBJBASE_H


--- openssl.c.orig      Sun Apr 30 16:43:40 2006
+++ openssl.c   Fri May 12 15:53:46 2006
@@ -41,7 +41,8 @@
 #include <openssl/err.h>
 #include <openssl/conf.h>
 #include <openssl/rand.h>
-#include <openssl/ssl.h>
+
+#include "openssl.h"

 #define DEFAULT_KEY_LENGTH     512
 #define MIN_KEY_LENGTH         384
@@ -202,32 +203,13 @@
 /* true global; readonly after module startup */
 static char default_ssl_conf_filename[MAXPATHLEN];

-struct php_x509_request {
-       LHASH * global_config;  /* Global SSL config */
-       LHASH * req_config;             /* SSL config for this request */
-       const EVP_MD * md_alg;
-       const EVP_MD * digest;
-       char    * section_name,
-                       * config_filename,
-                       * digest_name,
-                       * extensions_section,
-                       * request_extensions_section;
-       int priv_key_bits;
-       int priv_key_type;
-
-       int priv_key_encrypt;
-
-       EVP_PKEY * priv_key;
-};
-
-
 static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * 
resourceval TSRMLS_DC);
 static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char 
* passphrase, int makeresource, long * resourceval TSRMLS_DC);
 static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);
 static X509_STORE     * setup_verify(zval * calist TSRMLS_DC);
 static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
 static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, 
long * resourceval TSRMLS_DC);
-static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * 
req TSRMLS_DC);
+EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req 
TSRMLS_DC);


 static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int 
shortname TSRMLS_DC)
@@ -427,7 +409,7 @@



-static int php_openssl_parse_config(
+int php_openssl_parse_config(
                struct php_x509_request * req,
                zval * optional_args
                TSRMLS_DC
@@ -589,6 +571,8 @@
        le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL 
X.509", module_number);
        le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL 
X.509 CSR", module_number);

+       init_objects(TSRMLS_C); /*      Initialize the OO interface     */
+
        SSL_library_init();
        OpenSSL_add_all_ciphers();
        OpenSSL_add_all_digests();
@@ -1873,7 +1857,7 @@
 /* }}} */

 /* {{{ php_openssl_generate_private_key */
-static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * 
req TSRMLS_DC)
+EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req 
TSRMLS_DC)
 {
        char * randfile = NULL;
        int egdsocket, seeded;


/*      Filename:       openssl.h
        Most of this was moved from openssl.c

        20060510 Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include <openssl/conf.h>
#include <openssl/ssl.h>

#ifndef OPENSSL_H
#define OPENSSL_H

struct php_x509_request {
        LHASH * global_config;  /* Global SSL config */
        LHASH * req_config;             /* SSL config for this request */
        const EVP_MD * md_alg;
        const EVP_MD * digest;
        char    * section_name,
                        * config_filename,
                        * digest_name,
                        * extensions_section,
                        * request_extensions_section;
        int priv_key_bits;
        int priv_key_type;

        int priv_key_encrypt;

        EVP_PKEY * priv_key;
};

#ifdef __cplusplus
extern "C"
{
#endif
int php_openssl_parse_config(struct php_x509_request*, zval* TSRMLS_DC);
EVP_PKEY* php_openssl_generate_private_key(struct php_x509_request* TSRMLS_DC);
#ifdef __cplusplus
}

namespace php
{
        namespace openssl
        {
                class X509Request : public php_x509_request
                {
                public:
                        X509Request()
                        {
                                global_config = NULL;
                                req_config = NULL;
                                md_alg = NULL;
                                digest = NULL;;
                                section_name = NULL;
                                config_filename = NULL;
                                digest_name = NULL;
                                extensions_section = NULL;
                                request_extensions_section = NULL;
                                priv_key_bits = 0;
                                priv_key_type = 0;
                                priv_key_encrypt = 0;
                                EVP_PKEY * priv_key = NULL;
                        }
                        //This doesn't call php_openssl_dispose_config() 
because there's no way to pass
                        //      TSRMLS_* to a destructor
                        //      ***     This assumes that the EVP_PKEY is 
managed elsewhere
                        ~X509Request()
                        {
                                if( global_config != NULL )
                                {
                                        CONF_free(global_config);
                                        global_config = NULL;
                                }
                                if( req_config != NULL )
                                {
                                        CONF_free(req_config);
                                        req_config = NULL;
                                }
                        }
                        bool parse_config(zval* z)
                        {
                                return php_openssl_parse_config(&base(), z 
TSRMLS_CC) == SUCCESS;
                        }
                        EVP_PKEY* generate_private_key(TSRMLS_D)
                        {
                                return php_openssl_generate_private_key(&base() 
TSRMLS_CC);
                        }
                        php_x509_request& base()        {       return *this;   
}
                };
        }
}

#endif  //__cplusplus

#endif  //OPENSSL_H


/*      Filename:       privkey.cc
        Private key interface class for PHP5

        20060429        Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include "privkey.h"

#include "openssl.h"

namespace php
{
        namespace openssl
        {
                template<>
                const char *const ObjectBase<PrivateKey>::name = "PrivateKey";  
//Set the class's userland name

                //Do the actual construction in response to a userland call to 
'new PrivateKey()'
                //      The first argument can be a config_args array
                //      It could also be a PEM string, in which case the 2nd 
arg is an optional passphrase
                //      The passphrase could be a zero-length string, which 
isn't considered to be a passphrase
                PHP_NAMED_FUNCTION(PrivateKey::ZEND_FN(construct))
                {
                        zval    *z = NULL;
                        unsigned char*  pass = NULL;
                        int     pass_len = 0;

                        if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!s", 
&z, &pass, &pass_len) == FAILURE )
                        {
                                RETURN_FALSE;
                        }

                        //Get the mostly-unitialized object off the object store
                        PrivateKey* key = get_object<PrivateKey>(getThis() 
TSRMLS_CC);
                        if( key == NULL )
                        {
                                RETURN_FALSE;
                        }

                        //Now behave like a constructor
                        if( (z != NULL) && (Z_TYPE_P(z) == IS_STRING) ) 
//Create the key from a PEM string
                        {
                                BIO *in = BIO_new_mem_buf(Z_STRVAL_P(z), 
Z_STRLEN_P(z));
                                if(in == NULL)
                                {
                                        RETURN_FALSE;
                                }

                                pass = (pass_len==0)?NULL:pass; //Ignore 
zero-length passphrases
                                key->key = PEM_read_bio_PrivateKey(in, NULL, 
NULL, pass);
                                BIO_free(in);
                        }
                        else    //Generate a new key
                        {
                                X509Request req;
                                req.parse_config(z);
                                key->numBits = req.priv_key_bits;       //Save 
the number of key bits
                                key->key = req.generate_private_key(TSRMLS_C);
                        }
                }

                namespace privatekey
                {
                        //Return the private key as PEM formatted text
                        PHP_FUNCTION(pem)
                        {
                                unsigned char*  pass = NULL;
                                int     pass_len = 0;
                                zend_bool       encrypt = false;

                                RETVAL_FALSE;   //Default retval to false 
(speedup)

                                if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 
"|s!b", &pass, &pass_len, &encrypt) == FAILURE)
                                {
                                        return;
                                }

                                PrivateKey* key = 
get_object<PrivateKey>(getThis() TSRMLS_CC);
                                if( key == NULL )
                                {
                                        return;
                                }

                                key->pem(return_value, pass, pass_len, encrypt);
                        }

                        //Return a PublicKey object for this private key
                        PHP_FUNCTION(public)
                        {
                                PrivateKey* key = 
get_object<PrivateKey>(getThis() TSRMLS_CC);

                                if( key == NULL )
                                {
                                        RETURN_FALSE;
                                }

                                key->get_public(return_value);
//                              RETURN_STRING("this is public()\n", 1);
                        }
                }       //namespace privatekey

        #define PRIVKEY_ME(func_name, handler_name)     ZEND_FENTRY(func_name, 
&openssl::privatekey:: PHP_FN(handler_name), NULL, 0)
                template<> zend_function_entry 
ObjectBase<PrivateKey>::methods[] =
                {
//                      PRIVKEY_ME(csr, csr)                            
//Return a CSR object
                        PRIVKEY_ME(pem, pem)                            
//Return the private key as PEM formatted text
                        PRIVKEY_ME(public,      public)         //Return a 
PublicKey object for this private key
                        {NULL, NULL, NULL}
                };
        }       //namespace openssl
}       //namespace php


/*      Filename:       privkey.h
        Private key interface class for PHP5

        20060501        Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include <string>

#include <openssl/ssl.h>

#include "objbase.h"
#include "pubkey.h"

#ifndef PRIVKEY_H
#define PRIVKEY_H

namespace php
{
        namespace openssl
        {
                class PrivateKey : public ObjectBase<PrivateKey>
                {
                        EVP_PKEY*       key;
                        unsigned                numBits;

                        PrivateKey(const PrivateKey&);  //No copying
                public:
                        //Bare-minimum constructor
                        PrivateKey(zend_class_entry *zce) : key(NULL), numBits(0), 
ObjectBase<PrivateKey>(zce) {}
                        ~PrivateKey()
                        {
                                if( key != NULL )
                                {
                                        EVP_PKEY_free(key);
                                }
                        }

                        static PHP_FUNCTION(construct); //Handle userland new()

                        bool pem(zval *const out, unsigned char *const pass, 
size_t len, const bool encrypt)
                        {
                                const EVP_CIPHER* cipher = (pass && encrypt && 
(len!=0)) ? EVP_des_ede3_cbc() : NULL;
                                BIO* bio_out = BIO_new(BIO_s_mem());
                                if( PEM_write_bio_PrivateKey(bio_out, key, 
cipher, pass, len, NULL, NULL) )
                                {
                                        char*   bio_mem_ptr;
                                        long    bio_mem_len = 
BIO_get_mem_data(bio_out, &bio_mem_ptr);
                                        ZVAL_STRINGL(out, bio_mem_ptr, 
bio_mem_len, 1);
                                }

                                if( bio_out )
                                {
                                        BIO_free(bio_out);
                                }
                                return true;
                        }

                        void get_public(zval* z)
                        {
                                PublicKey* pub = PublicKey::construct(z, key);
                                if( pub == NULL )
                                        return;
                                ++key->references;      //Inc the ref count to 
prevent early deletion
                        }
                };
        }       //namespace openssl
}       //namespace php

#endif  //PRIVKEY_H


/*      Filename:       pubkey.cc
        Public key interface class for PHP5

        20060429        Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include "pubkey.h"

#define RSA_PUBLIC_HEADER       "-----BEGIN RSA PUBLIC KEY-----"

namespace php
{
        namespace openssl
        {
                template<> const char *const ObjectBase<PublicKey>::name = 
"PublicKey"; //Set the class's userland name

                PHP_NAMED_FUNCTION(PublicKey::ZEND_FN(construct))
                {
                        zval    *z;
                        unsigned char*  pem = NULL;
                        int     pem_len = 0;

                        if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", 
&pem, &pem_len) == FAILURE )
                        {
                                RETURN_FALSE;
                        }

                        //Get the mostly-unitialized object off the object store
                        PublicKey* key = get_object<PublicKey>(getThis() 
TSRMLS_CC);
                        if( key == NULL )
                        {
                                RETURN_FALSE;
                        }

                        //Now behave like a constructor
                        if( (pem != NULL) && (pem_len != 0) )   //Create the 
key from a PEM string
                        {
                                BIO *in = BIO_new_mem_buf(pem, pem_len);        
//Init the input buffer
                                if( in == NULL)
                                {
                                        RETURN_FALSE;
                                }
                                key->key = PEM_read_bio_PUBKEY(in, NULL, NULL, 
NULL);
                                BIO_free(in);
                        }
                }

                namespace publickey
                {
                        //Return the public key as PEM formatted text
                        PHP_FUNCTION(pem)
                        {
                                PublicKey* key = 
get_object<PublicKey>(getThis() TSRMLS_CC);
                                if( key == NULL )
                                {
                                        RETURN_FALSE;
                                }

                                key->pem(return_value);
                        }
                }       //namespace publickey

        #define PUBKEY_ME(func_name, handler_name)      ZEND_FENTRY(func_name, 
&openssl::publickey:: ZEND_FN(handler_name), NULL, 0)
                template<> zend_function_entry ObjectBase<PublicKey>::methods[] 
=
                {
                        PUBKEY_ME(pem,  pem)                            
//Return the public key as PEM formatted text
        //              PUBKEY_ME(spawn,        spawn,  NULL)
                        {NULL, NULL, NULL}
                };
        }       //namespace openssl
}       //namespace php


/*      Filename:       pubkey.h
        Public key interface class for PHP5

        20060501        Created by Brandon Fosdick <[EMAIL PROTECTED]>
*/

#include <openssl/ssl.h>

#include "objbase.h"

#ifndef PUBKEY_H
#define PUBKEY_H

namespace php
{
        namespace openssl
        {
                class PublicKey : public ObjectBase<PublicKey>
                {
                        EVP_PKEY*       key;

                        PublicKey(const PublicKey&);    //No copying
                public:
                        //Bare-minimum constructor
                        PublicKey(zend_class_entry *zce) : key(NULL), 
ObjectBase<PublicKey>(zce) {}
                        ~PublicKey()
                        {
                                if( key != NULL )
                                {
                                        EVP_PKEY_free(key);
                                }
                        }

                        bool init(EVP_PKEY* k)
                        {
                                if(key == NULL)
                                {
                                        key = k;
                                        return true;
                                }
                                return false;
                        }

                        static PHP_FUNCTION(construct); //Handle userland new()

                        //Construct and register a new unitialized object in a 
zval given an existing key
                        //      Used by handlers that need to return a new 
object
                        //      Uses the static zend_class_entry object, so 
register_class() must be called first
                        static PublicKey* construct(zval *z, EVP_PKEY* new_key 
TSRMLS_DC)
                        {
                                PublicKey* obj = 
ObjectBase<PublicKey>::construct(z);
                                if( obj == NULL )
                                        return NULL;
                                obj->init(new_key);
                        return obj;
                        }

                        bool pem(zval *const out)
                        {
                                if( (key->type != EVP_PKEY_RSA) && (key->type 
!= EVP_PKEY_RSA2) )
                                        return false;

                                BIO* bio_out = BIO_new(BIO_s_mem());
                                if( PEM_write_bio_RSA_PUBKEY(bio_out, 
key->pkey.rsa) )
                                {
                                        char*   bio_mem_ptr;
                                        long    bio_mem_len = 
BIO_get_mem_data(bio_out, &bio_mem_ptr);
                                        ZVAL_STRINGL(out, bio_mem_ptr, 
bio_mem_len, 1);
                                }

                                if( bio_out )
                                {
                                        BIO_free(bio_out);
                                }
                                return true;
                        }
                };
        }       //namespace openssl
}       //namespace php

#endif  //PUBKEY_H



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to