Skip to content
Browse files

initial commit

  • Loading branch information...
0 parents commit d5501aa0a4408f4f1af2cef3ac7c62a91ecfffa4 @mweibel mweibel committed Aug 11, 2011
2 .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+.svn
7 LICENSE
@@ -0,0 +1,7 @@
+Copyright (c) 2011 Amiado Group AG
+
+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.
46 README.md
@@ -0,0 +1,46 @@
+XMPP Prebind for PHP
+====================
+
+This class is for (prebinding)[http://metajack.im/2009/12/14/fastest-xmpp-sessions-with-http-prebinding/] a XMPP Session with PHP.
+
+Usage
+=====
+1. Clone the repo
+2. In your file where you want to do the prebinding:
+
+`
+/**
+ * Comment here for explanation of the options.
+ *
+ * Create a new XMPP Object with the required params
+ *
+ * @param string $jabberHost Jabber Server Host
+ * @param string $boshUri Full URI to the http-bind
+ * @param string $resource Resource identifier
+ * @param bool $useSsl Use SSL (not working yet, TODO)
+ * @param bool $debug Enable debug
+ */
+$xmppPrebind = new XmppPrebind('your-jabber-host.tld', 'http://your-jabber-host/http-bind/', 'Your XMPP Clients resource name', false, false);
+$xmppPrebind->connect($username, $password);
+$sessionInfo = $xmppPrebind->getSessionInfo(); // array containing sid, rid and jid
+`
+
+3. If you use (Candy)[http://amiadogroup.github.com/candy], change the `Candy.Core.Connect()` line to the following:
+
+`Candy.Core.attach('<?php echo $sessionInfo['jid'] ?>', '<?php echo $sessionInfo['sid'] ?>', '<?php echo $sessionInfo['rid'] ?>');`
+
+4. You should now have a working prebinding with PHP
+
+Debugging
+=========
+If something doesn't work, you can enable Debug. Debug output is logged to (FirePHP)[http://www.firephp.org/], so you have to install that first.
+
+Other Languages
+===============
+There exist other projects for other languages to support a prebind. Go googling :)
+
+Be aware
+========
+This class is in no way feature complete. There may also be bugs. I'd appreciate it if you contribute or submit bug reports.
+
+Thanks.
103 lib/Auth/SASL.php
@@ -0,0 +1,103 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Client implementation of various SASL mechanisms
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.1
+* @package Auth_SASL
+*/
+require_once(dirname(__FILE__) . '/SASL/Exception.php');
+
+class Auth_SASL
+{
+ /**
+ * Factory class. Returns an object of the request
+ * type.
+ *
+ * @param string $type One of: Anonymous
+ * Plain
+ * CramMD5
+ * DigestMD5
+ * Types are not case sensitive
+ */
+ public static function factory($type)
+ {
+ switch (strtolower($type)) {
+ case 'anonymous':
+ $filename = 'SASL/Anonymous.php';
+ $classname = 'Auth_SASL_Anonymous';
+ break;
+
+ case 'login':
+ $filename = 'SASL/Login.php';
+ $classname = 'Auth_SASL_Login';
+ break;
+
+ case 'plain':
+ $filename = 'SASL/Plain.php';
+ $classname = 'Auth_SASL_Plain';
+ break;
+
+ case 'external':
+ $filename = 'SASL/External.php';
+ $classname = 'Auth_SASL_External';
+ break;
+
+ case 'cram-md5':
+ $filename = 'SASL/CramMD5.php';
+ $classname = 'Auth_SASL_CramMD5';
+ break;
+
+ case 'digest-md5':
+ $filename = 'SASL/DigestMD5.php';
+ $classname = 'Auth_SASL_DigestMD5';
+ break;
+
+ default:
+ throw new Auth_SASL_Exception('Invalid SASL mechanism type ("' . $type .'")');
+ break;
+ }
+
+ require_once(dirname(__FILE__) . '/' . $filename);
+ $obj = new $classname();
+ return $obj;
+ }
+}
+
+?>
71 lib/Auth/SASL/Anonymous.php
@@ -0,0 +1,71 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Implmentation of ANONYMOUS SASL mechanism
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.1
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_Anonymous extends Auth_SASL_Common
+{
+ /**
+ * Not much to do here except return the token supplied.
+ * No encoding, hashing or encryption takes place for this
+ * mechanism, simply one of:
+ * o An email address
+ * o An opaque string not containing "@" that can be interpreted
+ * by the sysadmin
+ * o Nothing
+ *
+ * We could have some logic here for the second option, but this
+ * would by no means create something interpretable.
+ *
+ * @param string $token Optional email address or string to provide
+ * as trace information.
+ * @return string The unaltered input token
+ */
+ public function getResponse($token = '')
+ {
+ return $token;
+ }
+}
+?>
76 lib/Auth/SASL/Common.php
@@ -0,0 +1,76 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Common functionality to SASL mechanisms
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.1
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Exception.php');
+
+class Auth_SASL_Common
+{
+ /**
+ * Function which implements HMAC MD5 digest
+ *
+ * @param string $key The secret key
+ * @param string $data The data to protect
+ * @return string The HMAC MD5 digest
+ */
+ protected function HMAC_MD5($key, $data)
+ {
+ if (strlen($key) > 64) {
+ $key = pack('H32', md5($key));
+ }
+
+ if (strlen($key) < 64) {
+ $key = str_pad($key, 64, chr(0));
+ }
+
+ $k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
+ $k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
+
+ $inner = pack('H32', md5($k_ipad . $data));
+ $digest = md5($k_opad . $inner);
+
+ return $digest;
+ }
+}
+?>
68 lib/Auth/SASL/CramMD5.php
@@ -0,0 +1,68 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Implmentation of CRAM-MD5 SASL mechanism
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.1
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_CramMD5 extends Auth_SASL_Common
+{
+ /**
+ * Implements the CRAM-MD5 SASL mechanism
+ * This DOES NOT base64 encode the return value,
+ * you will need to do that yourself.
+ *
+ * @param string $user Username
+ * @param string $pass Password
+ * @param string $challenge The challenge supplied by the server.
+ * this should be already base64_decoded.
+ *
+ * @return string The string to pass back to the server, of the form
+ * "<user> <digest>". This is NOT base64_encoded.
+ */
+ public function getResponse($user, $pass, $challenge)
+ {
+ return $user . ' ' . $this->HMAC_MD5($pass, $challenge);
+ }
+}
+?>
197 lib/Auth/SASL/DigestMD5.php
@@ -0,0 +1,197 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Implmentation of DIGEST-MD5 SASL mechanism
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.1
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_DigestMD5 extends Auth_SASL_Common
+{
+ /**
+ * Provides the (main) client response for DIGEST-MD5
+ * requires a few extra parameters than the other
+ * mechanisms, which are unavoidable.
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $challenge The digest challenge sent by the server
+ * @param string $hostname The hostname of the machine you're connecting to
+ * @param string $service The servicename (eg. imap, pop, acap etc)
+ * @param string $authzid Authorization id (username to proxy as)
+ * @return string The digest response (NOT base64 encoded)
+ * @access public
+ */
+ public function getResponse($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
+ {
+ $challenge = $this->parseChallenge($challenge);
+ $authzid_string = '';
+ if ($authzid != '') {
+ $authzid_string = ',authzid="' . $authzid . '"';
+ }
+
+ if (!empty($challenge)) {
+ $cnonce = $this->getCnonce();
+ $digest_uri = sprintf('%s/%s', $service, $hostname);
+ $response_value = $this->getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
+
+ if ($challenge['realm']) {
+ return sprintf('username="%s",realm="%s"' . $authzid_string .
+',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
+ } else {
+ return sprintf('username="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
+ }
+ } else {
+ throw new Auth_SASL_Exception('Invalid digest challenge');
+ }
+ }
+
+ /**
+ * Parses and verifies the digest challenge*
+ *
+ * @param string $challenge The digest challenge
+ * @return array The parsed challenge as an assoc
+ * array in the form "directive => value".
+ * @access private
+ */
+ private function parseChallenge($challenge)
+ {
+ $tokens = array();
+ while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) {
+
+ // Ignore these as per rfc2831
+ if ($matches[1] == 'opaque' OR $matches[1] == 'domain') {
+ $challenge = substr($challenge, strlen($matches[0]) + 1);
+ continue;
+ }
+
+ // Allowed multiple "realm" and "auth-param"
+ if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) {
+ if (is_array($tokens[$matches[1]])) {
+ $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
+ } else {
+ $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
+ }
+
+ // Any other multiple instance = failure
+ } elseif (!empty($tokens[$matches[1]])) {
+ $tokens = array();
+ break;
+
+ } else {
+ $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
+ }
+
+ // Remove the just parsed directive from the challenge
+ $challenge = substr($challenge, strlen($matches[0]) + 1);
+ }
+
+ /**
+ * Defaults and required directives
+ */
+ // Realm
+ if (empty($tokens['realm'])) {
+ $tokens['realm'] = "";
+ }
+
+ // Maxbuf
+ if (empty($tokens['maxbuf'])) {
+ $tokens['maxbuf'] = 65536;
+ }
+
+ // Required: nonce, algorithm
+ if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) {
+ return array();
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Creates the response= part of the digest response
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $realm Realm as provided by the server
+ * @param string $nonce Nonce as provided by the server
+ * @param string $cnonce Client nonce
+ * @param string $digest_uri The digest-uri= value part of the response
+ * @param string $authzid Authorization id
+ * @return string The response= part of the digest response
+ * @access private
+ */
+ private function getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '')
+ {
+ if ($authzid == '') {
+ $A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce);
+ } else {
+ $A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid);
+ }
+ $A2 = 'AUTHENTICATE:' . $digest_uri;
+ return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2)));
+ }
+
+ /**
+ * Creates the client nonce for the response
+ *
+ * @return string The cnonce value
+ * @access private
+ */
+ private function getCnonce()
+ {
+ if (file_exists('/dev/urandom') && $fd = fopen('/dev/urandom', 'r')) {
+ return base64_encode(fread($fd, 32));
+
+ } elseif (file_exists('/dev/random') && $fd = fopen('/dev/random', 'r')) {
+ return base64_encode(fread($fd, 32));
+
+ } else {
+ $str = '';
+ for ($i=0; $i<32; $i++) {
+ $str .= chr(mt_rand(0, 255));
+ }
+
+ return base64_encode($str);
+ }
+ }
+}
+?>
37 lib/Auth/SASL/Exception.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @author Michael Weibel <michael.weibel@amiadogroup.com>
+ */
+
+/**
+ * Auth SASL Exception
+ *
+ * @author Michael Weibel <michael.weibel@amiadogroup.com>
+ * @package Auth_SASL
+ */
+class Auth_SASL_Exception extends Exception {}
63 lib/Auth/SASL/External.php
@@ -0,0 +1,63 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2008 Christoph Schulz |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Christoph Schulz <develop@kristov.de> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Implmentation of EXTERNAL SASL mechanism
+*
+* @author Christoph Schulz <develop@kristov.de>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0.4
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_External extends Auth_SASL_Common
+{
+ /**
+ * Returns EXTERNAL response
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $authzid Autorization id
+ * @return string EXTERNAL Response
+ */
+ public function getResponse($authcid, $pass, $authzid = '')
+ {
+ return $authzid;
+ }
+}
+?>
65 lib/Auth/SASL/Login.php
@@ -0,0 +1,65 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* This is technically not a SASL mechanism, however
+* it's used by Net_Sieve, Net_Cyrus and potentially
+* other protocols , so here is a good place to abstract
+* it.
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_Login extends Auth_SASL_Common
+{
+ /**
+ * Pseudo SASL LOGIN mechanism
+ *
+ * @param string $user Username
+ * @param string $pass Password
+ * @return string LOGIN string
+ */
+ public function getResponse($user, $pass)
+ {
+ return sprintf('LOGIN %s %s', $user, $pass);
+ }
+}
+?>
63 lib/Auth/SASL/Plain.php
@@ -0,0 +1,63 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003 Richard Heyes |
+// | All rights reserved. |
+// | |
+// | Redistribution and use in source and binary forms, with or without |
+// | modification, are permitted provided that the following conditions |
+// | are met: |
+// | |
+// | o Redistributions of source code must retain the above copyright |
+// | notice, this list of conditions and the following disclaimer. |
+// | o Redistributions in binary form must reproduce the above copyright |
+// | notice, this list of conditions and the following disclaimer in the |
+// | documentation and/or other materials provided with the distribution.|
+// | o The names of the authors may not be used to endorse or promote |
+// | products derived from this software without specific prior written |
+// | permission. |
+// | |
+// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// | |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard@php.net> |
+// +-----------------------------------------------------------------------+
+//
+
+/**
+* Implmentation of PLAIN SASL mechanism
+*
+* @author Richard Heyes <richard@php.net>
+* @author Michael Weibel <michael.weibel@amiadogroup.com> (made it work for PHP5)
+* @access public
+* @version 1.0
+* @package Auth_SASL
+*/
+
+require_once(dirname(__FILE__) . '/Common.php');
+
+class Auth_SASL_Plain extends Auth_SASL_Common
+{
+ /**
+ * Returns PLAIN response
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $authzid Autorization id
+ * @return string PLAIN Response
+ */
+ public function getResponse($authcid, $pass, $authzid = '')
+ {
+ return $authzid . chr(0) . $authcid . chr(0) . $pass;
+ }
+}
+?>
1,784 lib/FirePHP/FirePHP.class.php
@@ -0,0 +1,1784 @@
+<?php
+/**
+ * *** BEGIN LICENSE BLOCK *****
+ *
+ * This file is part of FirePHP (http://www.firephp.org/).
+ *
+ * Software License Agreement (New BSD License)
+ *
+ * Copyright (c) 2006-2010, Christoph Dorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Christoph Dorn nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK *****
+ *
+ * @copyright Copyright (C) 2007-2009 Christoph Dorn
+ * @author Christoph Dorn <christoph@christophdorn.com>
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @package FirePHPCore
+ */
+
+/**
+ * @see http://code.google.com/p/firephp/issues/detail?id=112
+ */
+if (!defined('E_STRICT')) {
+ define('E_STRICT', 2048);
+}
+if (!defined('E_RECOVERABLE_ERROR')) {
+ define('E_RECOVERABLE_ERROR', 4096);
+}
+if (!defined('E_DEPRECATED')) {
+ define('E_DEPRECATED', 8192);
+}
+if (!defined('E_USER_DEPRECATED')) {
+ define('E_USER_DEPRECATED', 16384);
+}
+
+/**
+ * Sends the given data to the FirePHP Firefox Extension.
+ * The data can be displayed in the Firebug Console or in the
+ * "Server" request tab.
+ *
+ * For more information see: http://www.firephp.org/
+ *
+ * @copyright Copyright (C) 2007-2009 Christoph Dorn
+ * @author Christoph Dorn <christoph@christophdorn.com>
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @package FirePHPCore
+ */
+class FirePHP {
+
+ /**
+ * FirePHP version
+ *
+ * @var string
+ */
+ const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%'
+
+ /**
+ * Firebug LOG level
+ *
+ * Logs a message to firebug console.
+ *
+ * @var string
+ */
+ const LOG = 'LOG';
+
+ /**
+ * Firebug INFO level
+ *
+ * Logs a message to firebug console and displays an info icon before the message.
+ *
+ * @var string
+ */
+ const INFO = 'INFO';
+
+ /**
+ * Firebug WARN level
+ *
+ * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
+ *
+ * @var string
+ */
+ const WARN = 'WARN';
+
+ /**
+ * Firebug ERROR level
+ *
+ * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
+ *
+ * @var string
+ */
+ const ERROR = 'ERROR';
+
+ /**
+ * Dumps a variable to firebug's server panel
+ *
+ * @var string
+ */
+ const DUMP = 'DUMP';
+
+ /**
+ * Displays a stack trace in firebug console
+ *
+ * @var string
+ */
+ const TRACE = 'TRACE';
+
+ /**
+ * Displays an exception in firebug console
+ *
+ * Increments the firebug error count.
+ *
+ * @var string
+ */
+ const EXCEPTION = 'EXCEPTION';
+
+ /**
+ * Displays an table in firebug console
+ *
+ * @var string
+ */
+ const TABLE = 'TABLE';
+
+ /**
+ * Starts a group in firebug console
+ *
+ * @var string
+ */
+ const GROUP_START = 'GROUP_START';
+
+ /**
+ * Ends a group in firebug console
+ *
+ * @var string
+ */
+ const GROUP_END = 'GROUP_END';
+
+ /**
+ * Singleton instance of FirePHP
+ *
+ * @var FirePHP
+ */
+ protected static $instance = null;
+
+ /**
+ * Flag whether we are logging from within the exception handler
+ *
+ * @var boolean
+ */
+ protected $inExceptionHandler = false;
+
+ /**
+ * Flag whether to throw PHP errors that have been converted to ErrorExceptions
+ *
+ * @var boolean
+ */
+ protected $throwErrorExceptions = true;
+
+ /**
+ * Flag whether to convert PHP assertion errors to Exceptions
+ *
+ * @var boolean
+ */
+ protected $convertAssertionErrorsToExceptions = true;
+
+ /**
+ * Flag whether to throw PHP assertion errors that have been converted to Exceptions
+ *
+ * @var boolean
+ */
+ protected $throwAssertionExceptions = false;
+
+ /**
+ * Wildfire protocol message index
+ *
+ * @var int
+ */
+ protected $messageIndex = 1;
+
+ /**
+ * Options for the library
+ *
+ * @var array
+ */
+ protected $options = array('maxDepth' => 10,
+ 'maxObjectDepth' => 5,
+ 'maxArrayDepth' => 5,
+ 'useNativeJsonEncode' => true,
+ 'includeLineNumbers' => true);
+
+ /**
+ * Filters used to exclude object members when encoding
+ *
+ * @var array
+ */
+ protected $objectFilters = array(
+ 'firephp' => array('objectStack', 'instance', 'json_objectStack'),
+ 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack')
+ );
+
+ /**
+ * A stack of objects used to detect recursion during object encoding
+ *
+ * @var object
+ */
+ protected $objectStack = array();
+
+ /**
+ * Flag to enable/disable logging
+ *
+ * @var boolean
+ */
+ protected $enabled = true;
+
+ /**
+ * The insight console to log to if applicable
+ *
+ * @var object
+ */
+ protected $logToInsightConsole = null;
+
+ /**
+ * When the object gets serialized only include specific object members.
+ *
+ * @return array
+ */
+ public function __sleep()
+ {
+ return array('options','objectFilters','enabled');
+ }
+
+ /**
+ * Gets singleton instance of FirePHP
+ *
+ * @param boolean $AutoCreate
+ * @return FirePHP
+ */
+ public static function getInstance($AutoCreate = false)
+ {
+ if ($AutoCreate===true && !self::$instance) {
+ self::init();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Creates FirePHP object and stores it for singleton access
+ *
+ * @return FirePHP
+ */
+ public static function init()
+ {
+ return self::setInstance(new self());
+ }
+
+ /**
+ * Set the instance of the FirePHP singleton
+ *
+ * @param FirePHP $instance The FirePHP object instance
+ * @return FirePHP
+ */
+ public static function setInstance($instance)
+ {
+ return self::$instance = $instance;
+ }
+
+ /**
+ * Set an Insight console to direct all logging calls to
+ *
+ * @param object $console The console object to log to
+ * @return void
+ */
+ public function setLogToInsightConsole($console)
+ {
+ if(is_string($console)) {
+ if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) {
+ throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!');
+ }
+ $this->logToInsightConsole = $this->to('request')->console($console);
+ } else {
+ $this->logToInsightConsole = $console;
+ }
+ }
+
+ /**
+ * Enable and disable logging to Firebug
+ *
+ * @param boolean $Enabled TRUE to enable, FALSE to disable
+ * @return void
+ */
+ public function setEnabled($Enabled)
+ {
+ $this->enabled = $Enabled;
+ }
+
+ /**
+ * Check if logging is enabled
+ *
+ * @return boolean TRUE if enabled
+ */
+ public function getEnabled()
+ {
+ return $this->enabled;
+ }
+
+ /**
+ * Specify a filter to be used when encoding an object
+ *
+ * Filters are used to exclude object members.
+ *
+ * @param string $Class The class name of the object
+ * @param array $Filter An array of members to exclude
+ * @return void
+ */
+ public function setObjectFilter($Class, $Filter)
+ {
+ $this->objectFilters[strtolower($Class)] = $Filter;
+ }
+
+ /**
+ * Set some options for the library
+ *
+ * Options:
+ * - maxDepth: The maximum depth to traverse (default: 10)
+ * - maxObjectDepth: The maximum depth to traverse objects (default: 5)
+ * - maxArrayDepth: The maximum depth to traverse arrays (default: 5)
+ * - useNativeJsonEncode: If true will use json_encode() (default: true)
+ * - includeLineNumbers: If true will include line numbers and filenames (default: true)
+ *
+ * @param array $Options The options to be set
+ * @return void
+ */
+ public function setOptions($Options)
+ {
+ $this->options = array_merge($this->options,$Options);
+ }
+
+ /**
+ * Get options from the library
+ *
+ * @return array The currently set options
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Set an option for the library
+ *
+ * @param string $Name
+ * @param mixed $Value
+ * @throws Exception
+ * @return void
+ */
+ public function setOption($Name, $Value)
+ {
+ if (!isset($this->options[$Name])) {
+ throw $this->newException('Unknown option: ' . $Name);
+ }
+ $this->options[$Name] = $Value;
+ }
+
+ /**
+ * Get an option from the library
+ *
+ * @param string $Name
+ * @throws Exception
+ * @return mixed
+ */
+ public function getOption($Name)
+ {
+ if (!isset($this->options[$Name])) {
+ throw $this->newException('Unknown option: ' . $Name);
+ }
+ return $this->options[$Name];
+ }
+
+ /**
+ * Register FirePHP as your error handler
+ *
+ * Will throw exceptions for each php error.
+ *
+ * @return mixed Returns a string containing the previously defined error handler (if any)
+ */
+ public function registerErrorHandler($throwErrorExceptions = false)
+ {
+ //NOTE: The following errors will not be caught by this error handler:
+ // E_ERROR, E_PARSE, E_CORE_ERROR,
+ // E_CORE_WARNING, E_COMPILE_ERROR,
+ // E_COMPILE_WARNING, E_STRICT
+
+ $this->throwErrorExceptions = $throwErrorExceptions;
+
+ return set_error_handler(array($this,'errorHandler'));
+ }
+
+ /**
+ * FirePHP's error handler
+ *
+ * Throws exception for each php error that will occur.
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $errcontext
+ */
+ public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
+ {
+ // Don't throw exception if error reporting is switched off
+ if (error_reporting() == 0) {
+ return;
+ }
+ // Only throw exceptions for errors we are asking for
+ if (error_reporting() & $errno) {
+
+ $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
+ if ($this->throwErrorExceptions) {
+ throw $exception;
+ } else {
+ $this->fb($exception);
+ }
+ }
+ }
+
+ /**
+ * Register FirePHP as your exception handler
+ *
+ * @return mixed Returns the name of the previously defined exception handler,
+ * or NULL on error.
+ * If no previous handler was defined, NULL is also returned.
+ */
+ public function registerExceptionHandler()
+ {
+ return set_exception_handler(array($this,'exceptionHandler'));
+ }
+
+ /**
+ * FirePHP's exception handler
+ *
+ * Logs all exceptions to your firebug console and then stops the script.
+ *
+ * @param Exception $Exception
+ * @throws Exception
+ */
+ function exceptionHandler($Exception)
+ {
+
+ $this->inExceptionHandler = true;
+
+ header('HTTP/1.1 500 Internal Server Error');
+
+ try {
+ $this->fb($Exception);
+ } catch (Exception $e) {
+ echo 'We had an exception: ' . $e;
+ }
+ $this->inExceptionHandler = false;
+ }
+
+ /**
+ * Register FirePHP driver as your assert callback
+ *
+ * @param boolean $convertAssertionErrorsToExceptions
+ * @param boolean $throwAssertionExceptions
+ * @return mixed Returns the original setting or FALSE on errors
+ */
+ public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false)
+ {
+ $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions;
+ $this->throwAssertionExceptions = $throwAssertionExceptions;
+
+ if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) {
+ throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!');
+ }
+
+ return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
+ }
+
+ /**
+ * FirePHP's assertion handler
+ *
+ * Logs all assertions to your firebug console and then stops the script.
+ *
+ * @param string $file File source of assertion
+ * @param int $line Line source of assertion
+ * @param mixed $code Assertion code
+ */
+ public function assertionHandler($file, $line, $code)
+ {
+ if ($this->convertAssertionErrorsToExceptions) {
+
+ $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line);
+
+ if ($this->throwAssertionExceptions) {
+ throw $exception;
+ } else {
+ $this->fb($exception);
+ }
+
+ } else {
+ $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line));
+ }
+ }
+
+ /**
+ * Start a group for following messages.
+ *
+ * Options:
+ * Collapsed: [true|false]
+ * Color: [#RRGGBB|ColorName]
+ *
+ * @param string $Name
+ * @param array $Options OPTIONAL Instructions on how to log the group
+ * @return true
+ * @throws Exception
+ */
+ public function group($Name, $Options = null)
+ {
+
+ if (!$Name) {
+ throw $this->newException('You must specify a label for the group!');
+ }
+
+ if ($Options) {
+ if (!is_array($Options)) {
+ throw $this->newException('Options must be defined as an array!');
+ }
+ if (array_key_exists('Collapsed', $Options)) {
+ $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false';
+ }
+ }
+
+ return $this->fb(null, $Name, FirePHP::GROUP_START, $Options);
+ }
+
+ /**
+ * Ends a group you have started before
+ *
+ * @return true
+ * @throws Exception
+ */
+ public function groupEnd()
+ {
+ return $this->fb(null, null, FirePHP::GROUP_END);
+ }
+
+ /**
+ * Log object with label to firebug console
+ *
+ * @see FirePHP::LOG
+ * @param mixes $Object
+ * @param string $Label
+ * @return true
+ * @throws Exception
+ */
+ public function log($Object, $Label = null, $Options = array())
+ {
+ return $this->fb($Object, $Label, FirePHP::LOG, $Options);
+ }
+
+ /**
+ * Log object with label to firebug console
+ *
+ * @see FirePHP::INFO
+ * @param mixes $Object
+ * @param string $Label
+ * @return true
+ * @throws Exception
+ */
+ public function info($Object, $Label = null, $Options = array())
+ {
+ return $this->fb($Object, $Label, FirePHP::INFO, $Options);
+ }
+
+ /**
+ * Log object with label to firebug console
+ *
+ * @see FirePHP::WARN
+ * @param mixes $Object
+ * @param string $Label
+ * @return true
+ * @throws Exception
+ */
+ public function warn($Object, $Label = null, $Options = array())
+ {
+ return $this->fb($Object, $Label, FirePHP::WARN, $Options);
+ }
+
+ /**
+ * Log object with label to firebug console
+ *
+ * @see FirePHP::ERROR
+ * @param mixes $Object
+ * @param string $Label
+ * @return true
+ * @throws Exception
+ */
+ public function error($Object, $Label = null, $Options = array())
+ {
+ return $this->fb($Object, $Label, FirePHP::ERROR, $Options);
+ }
+
+ /**
+ * Dumps key and variable to firebug server panel
+ *
+ * @see FirePHP::DUMP
+ * @param string $Key
+ * @param mixed $Variable
+ * @return true
+ * @throws Exception
+ */
+ public function dump($Key, $Variable, $Options = array())
+ {
+ if (!is_string($Key)) {
+ throw $this->newException('Key passed to dump() is not a string');
+ }
+ if (strlen($Key)>100) {
+ throw $this->newException('Key passed to dump() is longer than 100 characters');
+ }
+ if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) {
+ throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]');
+ }
+ return $this->fb($Variable, $Key, FirePHP::DUMP, $Options);
+ }
+
+ /**
+ * Log a trace in the firebug console
+ *
+ * @see FirePHP::TRACE
+ * @param string $Label
+ * @return true
+ * @throws Exception
+ */
+ public function trace($Label)
+ {
+ return $this->fb($Label, FirePHP::TRACE);
+ }
+
+ /**
+ * Log a table in the firebug console
+ *
+ * @see FirePHP::TABLE
+ * @param string $Label
+ * @param string $Table
+ * @return true
+ * @throws Exception
+ */
+ public function table($Label, $Table, $Options = array())
+ {
+ return $this->fb($Table, $Label, FirePHP::TABLE, $Options);
+ }
+
+ /**
+ * Insight API wrapper
+ *
+ * @see Insight_Helper::to()
+ */
+ public static function to()
+ {
+ $instance = self::getInstance();
+ if (!method_exists($instance, "_to")) {
+ throw new Exception("FirePHP::to() implementation not loaded");
+ }
+ $args = func_get_args();
+ return call_user_func_array(array($instance, '_to'), $args);
+ }
+
+ /**
+ * Insight API wrapper
+ *
+ * @see Insight_Helper::plugin()
+ */
+ public static function plugin()
+ {
+ $instance = self::getInstance();
+ if (!method_exists($instance, "_plugin")) {
+ throw new Exception("FirePHP::plugin() implementation not loaded");
+ }
+ $args = func_get_args();
+ return call_user_func_array(array($instance, '_plugin'), $args);
+ }
+
+ /**
+ * Check if FirePHP is installed on client
+ *
+ * @return boolean
+ */
+ public function detectClientExtension()
+ {
+ // Check if FirePHP is installed on client via User-Agent header
+ if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) &&
+ version_compare($m[1][0],'0.0.6','>=')) {
+ return true;
+ } else
+ // Check if FirePHP is installed on client via X-FirePHP-Version header
+ if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) &&
+ version_compare($m[1][0],'0.0.6','>=')) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Log varible to Firebug
+ *
+ * @see http://www.firephp.org/Wiki/Reference/Fb
+ * @param mixed $Object The variable to be logged
+ * @return true Return TRUE if message was added to headers, FALSE otherwise
+ * @throws Exception
+ */
+ public function fb($Object)
+ {
+ if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) {
+ if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message
+ $this->_logUpgradeClientMessage();
+ }
+ }
+
+ static $insightGroupStack = array();
+
+ if (!$this->getEnabled()) {
+ return false;
+ }
+
+ if ($this->headersSent($filename, $linenum)) {
+ // If we are logging from within the exception handler we cannot throw another exception
+ if ($this->inExceptionHandler) {
+ // Simply echo the error out to the page
+ echo '<div style="border: 2px solid red; font-family: Arial; font-size: 12px; background-color: lightgray; padding: 5px;"><span style="color: red; font-weight: bold;">FirePHP ERROR:</span> Headers already sent in <b>'.$filename.'</b> on line <b>'.$linenum.'</b>. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.</div>';
+ } else {
+ throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.');
+ }
+ }
+
+ $Type = null;
+ $Label = null;
+ $Options = array();
+
+ if (func_num_args()==1) {
+ } else
+ if (func_num_args()==2) {
+ switch(func_get_arg(1)) {
+ case self::LOG:
+ case self::INFO:
+ case self::WARN:
+ case self::ERROR:
+ case self::DUMP:
+ case self::TRACE:
+ case self::EXCEPTION:
+ case self::TABLE:
+ case self::GROUP_START:
+ case self::GROUP_END:
+ $Type = func_get_arg(1);
+ break;
+ default:
+ $Label = func_get_arg(1);
+ break;
+ }
+ } else
+ if (func_num_args()==3) {
+ $Type = func_get_arg(2);
+ $Label = func_get_arg(1);
+ } else
+ if (func_num_args()==4) {
+ $Type = func_get_arg(2);
+ $Label = func_get_arg(1);
+ $Options = func_get_arg(3);
+ } else {
+ throw $this->newException('Wrong number of arguments to fb() function!');
+ }
+
+ if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) {
+ $msg = $this->logToInsightConsole;
+ if ($Object instanceof Exception) {
+ $Type = self::EXCEPTION;
+ }
+ if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) {
+ $msg = $msg->label($Label);
+ }
+ switch($Type) {
+ case self::DUMP:
+ case self::LOG:
+ return $msg->log($Object);
+ case self::INFO:
+ return $msg->info($Object);
+ case self::WARN:
+ return $msg->warn($Object);
+ case self::ERROR:
+ return $msg->error($Object);
+ case self::TRACE:
+ return $msg->trace($Object);
+ case self::EXCEPTION:
+ return $this->plugin('engine')->handleException($Object, $msg);
+ case self::TABLE:
+ if (isset($Object[0]) && !is_string($Object[0]) && $Label) {
+ $Object = array($Label, $Object);
+ }
+ return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]);
+ case self::GROUP_START:
+ $insightGroupStack[] = $msg->group(md5($Label))->open();
+ return $msg->log($Label);
+ case self::GROUP_END:
+ if(count($insightGroupStack)==0) {
+ throw new Error('Too many groupEnd() as opposed to group() calls!');
+ }
+ $group = array_pop($insightGroupStack);
+ return $group->close();
+ default:
+ return $msg->log($Object);
+ }
+ }
+
+ if (!$this->detectClientExtension()) {
+ return false;
+ }
+
+ $meta = array();
+ $skipFinalObjectEncode = false;
+
+ if ($Object instanceof Exception) {
+
+ $meta['file'] = $this->_escapeTraceFile($Object->getFile());
+ $meta['line'] = $Object->getLine();
+
+ $trace = $Object->getTrace();
+ if ($Object instanceof ErrorException
+ && isset($trace[0]['function'])
+ && $trace[0]['function']=='errorHandler'
+ && isset($trace[0]['class'])
+ && $trace[0]['class']=='FirePHP') {
+
+ $severity = false;
+ switch($Object->getSeverity()) {
+ case E_WARNING: $severity = 'E_WARNING'; break;
+ case E_NOTICE: $severity = 'E_NOTICE'; break;
+ case E_USER_ERROR: $severity = 'E_USER_ERROR'; break;
+ case E_USER_WARNING: $severity = 'E_USER_WARNING'; break;
+ case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break;
+ case E_STRICT: $severity = 'E_STRICT'; break;
+ case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break;
+ case E_DEPRECATED: $severity = 'E_DEPRECATED'; break;
+ case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break;
+ }
+
+ $Object = array('Class'=>get_class($Object),
+ 'Message'=>$severity.': '.$Object->getMessage(),
+ 'File'=>$this->_escapeTraceFile($Object->getFile()),
+ 'Line'=>$Object->getLine(),
+ 'Type'=>'trigger',
+ 'Trace'=>$this->_escapeTrace(array_splice($trace,2)));
+ $skipFinalObjectEncode = true;
+ } else {
+ $Object = array('Class'=>get_class($Object),
+ 'Message'=>$Object->getMessage(),
+ 'File'=>$this->_escapeTraceFile($Object->getFile()),
+ 'Line'=>$Object->getLine(),
+ 'Type'=>'throw',
+ 'Trace'=>$this->_escapeTrace($trace));
+ $skipFinalObjectEncode = true;
+ }
+ $Type = self::EXCEPTION;
+
+ } else
+ if ($Type==self::TRACE) {
+
+ $trace = debug_backtrace();
+ if (!$trace) return false;
+ for( $i=0 ; $i<sizeof($trace) ; $i++ ) {
+
+ if (isset($trace[$i]['class'])
+ && isset($trace[$i]['file'])
+ && ($trace[$i]['class']=='FirePHP'
+ || $trace[$i]['class']=='FB')
+ && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+ || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+ /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+ } else
+ if (isset($trace[$i]['class'])
+ && isset($trace[$i+1]['file'])
+ && $trace[$i]['class']=='FirePHP'
+ && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+ /* Skip fb() */
+ } else
+ if ($trace[$i]['function']=='fb'
+ || $trace[$i]['function']=='trace'
+ || $trace[$i]['function']=='send') {
+
+ $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'',
+ 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'',
+ 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'',
+ 'Message'=>$trace[$i]['args'][0],
+ 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'',
+ 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'',
+ 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'',
+ 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1)));
+
+ $skipFinalObjectEncode = true;
+ $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+ $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+ break;
+ }
+ }
+
+ } else
+ if ($Type==self::TABLE) {
+
+ if (isset($Object[0]) && is_string($Object[0])) {
+ $Object[1] = $this->encodeTable($Object[1]);
+ } else {
+ $Object = $this->encodeTable($Object);
+ }
+
+ $skipFinalObjectEncode = true;
+
+ } else
+ if ($Type==self::GROUP_START) {
+
+ if (!$Label) {
+ throw $this->newException('You must specify a label for the group!');
+ }
+
+ } else {
+ if ($Type===null) {
+ $Type = self::LOG;
+ }
+ }
+
+ if ($this->options['includeLineNumbers']) {
+ if (!isset($meta['file']) || !isset($meta['line'])) {
+
+ $trace = debug_backtrace();
+ for( $i=0 ; $trace && $i<sizeof($trace) ; $i++ ) {
+
+ if (isset($trace[$i]['class'])
+ && isset($trace[$i]['file'])
+ && ($trace[$i]['class']=='FirePHP'
+ || $trace[$i]['class']=='FB')
+ && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+ || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+ /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+ } else
+ if (isset($trace[$i]['class'])
+ && isset($trace[$i+1]['file'])
+ && $trace[$i]['class']=='FirePHP'
+ && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+ /* Skip fb() */
+ } else
+ if (isset($trace[$i]['file'])
+ && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') {
+ /* Skip FB::fb() */
+ } else {
+ $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+ $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+ break;
+ }
+ }
+ }
+ } else {
+ unset($meta['file']);
+ unset($meta['line']);
+ }
+
+ $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
+ $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION);
+
+ $structure_index = 1;
+ if ($Type==self::DUMP) {
+ $structure_index = 2;
+ $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
+ } else {
+ $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
+ }
+
+ if ($Type==self::DUMP) {
+ $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}';
+ } else {
+ $msg_meta = $Options;
+ $msg_meta['Type'] = $Type;
+ if ($Label!==null) {
+ $msg_meta['Label'] = $Label;
+ }
+ if (isset($meta['file']) && !isset($msg_meta['File'])) {
+ $msg_meta['File'] = $meta['file'];
+ }
+ if (isset($meta['line']) && !isset($msg_meta['Line'])) {
+ $msg_meta['Line'] = $meta['line'];
+ }
+ $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']';
+ }
+
+ $parts = explode("\n",chunk_split($msg, 5000, "\n"));
+
+ for( $i=0 ; $i<count($parts) ; $i++) {
+
+ $part = $parts[$i];
+ if ($part) {
+
+ if (count($parts)>2) {
+ // Message needs to be split into multiple parts
+ $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+ (($i==0)?strlen($msg):'')
+ . '|' . $part . '|'
+ . (($i<count($parts)-2)?'\\':''));
+ } else {
+ $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+ strlen($part) . '|' . $part . '|');
+ }
+
+ $this->messageIndex++;
+
+ if ($this->messageIndex > 99999) {
+ throw $this->newException('Maximum number (99,999) of messages reached!');
+ }
+ }
+ }
+
+ $this->setHeader('X-Wf-1-Index',$this->messageIndex-1);
+
+ return true;
+ }
+
+ /**
+ * Standardizes path for windows systems.
+ *
+ * @param string $Path
+ * @return string
+ */
+ protected function _standardizePath($Path)
+ {
+ return preg_replace('/\\\\+/','/',$Path);
+ }
+
+ /**
+ * Escape trace path for windows systems
+ *
+ * @param array $Trace
+ * @return array
+ */
+ protected function _escapeTrace($Trace)
+ {
+ if (!$Trace) return $Trace;
+ for( $i=0 ; $i<sizeof($Trace) ; $i++ ) {
+ if (isset($Trace[$i]['file'])) {
+ $Trace[$i]['file'] = $this->_escapeTraceFile($Trace[$i]['file']);
+ }
+ if (isset($Trace[$i]['args'])) {
+ $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']);
+ }
+ }
+ return $Trace;
+ }
+
+ /**
+ * Escape file information of trace for windows systems
+ *
+ * @param string $File
+ * @return string
+ */
+ protected function _escapeTraceFile($File)
+ {
+ /* Check if we have a windows filepath */
+ if (strpos($File,'\\')) {
+ /* First strip down to single \ */
+
+ $file = preg_replace('/\\\\+/','\\',$File);
+
+ return $file;
+ }
+ return $File;
+ }
+
+ /**
+ * Check if headers have already been sent
+ *
+ * @param string $Filename
+ * @param integer $Linenum
+ */
+ protected function headersSent(&$Filename, &$Linenum)
+ {
+ return headers_sent($Filename, $Linenum);
+ }
+
+ /**
+ * Send header
+ *
+ * @param string $Name
+ * @param string $Value
+ */
+ protected function setHeader($Name, $Value)
+ {
+ return header($Name.': '.$Value);
+ }
+
+ /**
+ * Get user agent
+ *
+ * @return string|false
+ */
+ protected function getUserAgent()
+ {
+ if (!isset($_SERVER['HTTP_USER_AGENT'])) return false;
+ return $_SERVER['HTTP_USER_AGENT'];
+ }
+
+ /**
+ * Get all request headers
+ *
+ * @return array
+ */
+ public static function getAllRequestHeaders() {
+ static $_cached_headers = false;
+ if($_cached_headers!==false) {
+ return $_cached_headers;
+ }
+ $headers = array();
+ if(function_exists('getallheaders')) {
+ foreach( getallheaders() as $name => $value ) {
+ $headers[strtolower($name)] = $value;
+ }
+ } else {
+ foreach($_SERVER as $name => $value) {
+ if(substr($name, 0, 5) == 'HTTP_') {
+ $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value;
+ }
+ }
+ }
+ return $_cached_headers = $headers;
+ }
+
+ /**
+ * Get a request header
+ *
+ * @return string|false
+ */
+ protected function getRequestHeader($Name)
+ {
+ $headers = self::getAllRequestHeaders();
+ if (isset($headers[strtolower($Name)])) {
+ return $headers[strtolower($Name)];
+ }
+ return false;
+ }
+
+ /**
+ * Returns a new exception
+ *
+ * @param string $Message
+ * @return Exception
+ */
+ protected function newException($Message)
+ {
+ return new Exception($Message);
+ }
+
+ /**
+ * Encode an object into a JSON string
+ *
+ * Uses PHP's jeson_encode() if available
+ *
+ * @param object $Object The object to be encoded
+ * @return string The JSON string
+ */
+ public function jsonEncode($Object, $skipObjectEncode = false)
+ {
+ if (!$skipObjectEncode) {
+ $Object = $this->encodeObject($Object);
+ }
+
+ if (function_exists('json_encode')
+ && $this->options['useNativeJsonEncode']!=false) {
+
+ return json_encode($Object);
+ } else {
+ return $this->json_encode($Object);
+ }
+ }
+
+ /**
+ * Encodes a table by encoding each row and column with encodeObject()
+ *
+ * @param array $Table The table to be encoded
+ * @return array
+ */
+ protected function encodeTable($Table)
+ {
+
+ if (!$Table) return $Table;
+
+ $new_table = array();
+ foreach($Table as $row) {
+
+ if (is_array($row)) {
+ $new_row = array();
+
+ foreach($row as $item) {
+ $new_row[] = $this->encodeObject($item);
+ }
+
+ $new_table[] = $new_row;
+ }
+ }
+
+ return $new_table;
+ }
+
+ /**
+ * Encodes an object including members with
+ * protected and private visibility
+ *
+ * @param Object $Object The object to be encoded
+ * @param int $Depth The current traversal depth
+ * @return array All members of the object
+ */
+ protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1)
+ {
+ if ($MaxDepth > $this->options['maxDepth']) {
+ return '** Max Depth ('.$this->options['maxDepth'].') **';
+ }
+
+ $return = array();
+
+ if (is_resource($Object)) {
+
+ return '** '.(string)$Object.' **';
+
+ } else
+ if (is_object($Object)) {
+
+ if ($ObjectDepth > $this->options['maxObjectDepth']) {
+ return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **';
+ }
+
+ foreach ($this->objectStack as $refVal) {
+ if ($refVal === $Object) {
+ return '** Recursion ('.get_class($Object).') **';
+ }
+ }
+ array_push($this->objectStack, $Object);
+
+ $return['__className'] = $class = get_class($Object);
+ $class_lower = strtolower($class);
+
+ $reflectionClass = new ReflectionClass($class);
+ $properties = array();
+ foreach( $reflectionClass->getProperties() as $property) {
+ $properties[$property->getName()] = $property;
+ }
+
+ $members = (array)$Object;
+
+ foreach( $properties as $plain_name => $property ) {
+
+ $name = $raw_name = $plain_name;
+ if ($property->isStatic()) {
+ $name = 'static:'.$name;
+ }
+ if ($property->isPublic()) {
+ $name = 'public:'.$name;
+ } else
+ if ($property->isPrivate()) {
+ $name = 'private:'.$name;
+ $raw_name = "\0".$class."\0".$raw_name;
+ } else
+ if ($property->isProtected()) {
+ $name = 'protected:'.$name;
+ $raw_name = "\0".'*'."\0".$raw_name;
+ }
+
+ if (!(isset($this->objectFilters[$class_lower])
+ && is_array($this->objectFilters[$class_lower])
+ && in_array($plain_name,$this->objectFilters[$class_lower]))) {
+
+ if (array_key_exists($raw_name,$members)
+ && !$property->isStatic()) {
+
+ $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1);
+
+ } else {
+ if (method_exists($property,'setAccessible')) {
+ $property->setAccessible(true);
+ $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1);
+ } else
+ if ($property->isPublic()) {
+ $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1);
+ } else {
+ $return[$name] = '** Need PHP 5.3 to get value **';
+ }
+ }
+ } else {
+ $return[$name] = '** Excluded by Filter **';
+ }
+ }
+
+ // Include all members that are not defined in the class
+ // but exist in the object
+ foreach( $members as $raw_name => $value ) {
+
+ $name = $raw_name;
+
+ if ($name{0} == "\0") {
+ $parts = explode("\0", $name);
+ $name = $parts[2];
+ }
+
+ $plain_name = $name;
+
+ if (!isset($properties[$name])) {
+ $name = 'undeclared:'.$name;
+
+ if (!(isset($this->objectFilters[$class_lower])
+ && is_array($this->objectFilters[$class_lower])
+ && in_array($plain_name,$this->objectFilters[$class_lower]))) {
+
+ $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1);
+ } else {
+ $return[$name] = '** Excluded by Filter **';
+ }
+ }