diff --git a/classes/API/AYAH.php b/classes/API/AYAH.php new file mode 100644 index 0000000..cd84dc5 --- /dev/null +++ b/classes/API/AYAH.php @@ -0,0 +1,34 @@ +api['ayah']) + { + throw new Exception('Missing API configuration.'); + } + + $ayah = new AYAH($config->api['ayah']); + + return $ayah->getPublisherHTML(); + } + + public static function isHuman() + { + $config = Config::getInstance(); + + if (!$config->api['ayah']) + { + throw new Exception('Missing API configuration.'); + } + + $ayah = new AYAH($config->api['ayah']); + + return $ayah->scoreResult(); + } +} + +?> diff --git a/pickles.php b/pickles.php index a66b70e..f3f03fc 100644 --- a/pickles.php +++ b/pickles.php @@ -27,8 +27,9 @@ define('PICKLES_START_TIME', microtime(true)); // Establishes our PICKLES paths -define('PICKLES_PATH', dirname(__FILE__) . '/'); -define('PICKLES_CLASS_PATH', PICKLES_PATH . 'classes/'); +define('PICKLES_PATH', dirname(__FILE__) . '/'); +define('PICKLES_CLASS_PATH', PICKLES_PATH . 'classes/'); +define('PICKLES_VENDOR_PATH', PICKLES_PATH . 'vendors/'); // Establishes our site paths define('SITE_PATH', getcwd() . '/../'); @@ -127,38 +128,43 @@ if (!isset($_REQUEST['request'])) * Magic function to automatically load classes * * Attempts to load a core PICKLES class or a site level data model or - * module class. If Smarty is being requested, will load the proper class - * from the vendors directory + * module class. * * @param string $class Name of the class to be loaded * @return boolean Return value of require_once() or false (default) */ function __autoload($class) { - $loaded = false; - + $loaded = false; $filename = preg_replace('/_/', '/', $class) . '.php'; - // Path as the key, boolean value is whether ot not to convert back to hyphenated - $paths = array( - PICKLES_CLASS_PATH => false, - SITE_CLASS_PATH => false, - SITE_MODEL_PATH => false, - SITE_MODULE_PATH => true, - ); - - foreach ($paths as $path => $hyphenated) + if ($class == 'AYAH') { - // Converts the filename back to hypenated - if ($hyphenated == true) - { - $filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));; - } + $loaded = require_once PICKLES_VENDOR_PATH . '/ayah/' . $filename; + } + else + { + // Path as the key, boolean value is whether ot not to convert back to hyphenated + $paths = array( + PICKLES_CLASS_PATH => false, + SITE_CLASS_PATH => false, + SITE_MODEL_PATH => false, + SITE_MODULE_PATH => true, + ); - if (file_exists($path . $filename)) + foreach ($paths as $path => $hyphenated) { - $loaded = require_once $path . $filename; - break; + // Converts the filename back to hypenated + if ($hyphenated == true) + { + $filename = strtolower(preg_replace('/([A-Z]{1})/', '-$1', $filename));; + } + + if (file_exists($path . $filename)) + { + $loaded = require_once $path . $filename; + break; + } } } diff --git a/vendors/ayah b/vendors/ayah new file mode 120000 index 0000000..51f00c0 --- /dev/null +++ b/vendors/ayah @@ -0,0 +1 @@ +ayah-1.1.7 \ No newline at end of file diff --git a/vendors/ayah-1.1.7/ayah.php b/vendors/ayah-1.1.7/ayah.php new file mode 100755 index 0000000..3d2acc6 --- /dev/null +++ b/vendors/ayah-1.1.7/ayah.php @@ -0,0 +1,482 @@ +__load_config_file()) + { + $this->__log("DEBUG", __FUNCTION__, "The ayah_config.php file is missing."); + } + + // Get and use any valid parameters that were passed in via the $params array. + foreach ((array)$this->__valid_construct_params as $partial_variable_name) + { + // Build the full variable name...and create an upper case version. + $variable_name = "ayah_" . $partial_variable_name; + $uc_variable_name = strtoupper($variable_name); + + // Check to see if it was passed in via $params. + if (isset($params[$partial_variable_name])) + { + $this->{$variable_name} = $params[$partial_variable_name]; + } + // Check to see if it was defined in the ayah_config file. + elseif (defined($uc_variable_name)) + { + $this->{$variable_name} = constant($uc_variable_name); + } + } + + // Generate some warnings/errors if needed variables are not set. + if ($this->ayah_publisher_key == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Publisher key is not defined. This won't work."); + } + else + { + $this->__log("DEBUG", __FUNCTION__, "Publisher key: '$this->ayah_publisher_key'"); + } + if ($this->ayah_scoring_key == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Scoring key is not defined. This won't work."); + } + else + { + // For security reasons, don't output the scoring key as part of the debug info. + } + if ($this->ayah_web_service_host == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Web service host is not defined. This won't work."); + } + else + { + $this->__log("DEBUG", __FUNCTION__, "AYAH Webservice host: '$this->ayah_web_service_host'"); + } + + // If available, set the session secret. + if(array_key_exists("session_secret", $_REQUEST)) { + $this->session_secret = $_REQUEST["session_secret"]; + } + } + + /** + * Returns the markup for the PlayThru + * + * @return string + */ + public function getPublisherHTML($config = array()) + { + // Initialize. + $session_secret = ""; + $fields = array('config' => $config); + $webservice_url = '/ws/setruntimeoptions/' . $this->ayah_publisher_key; + + // If necessary, process the config data. + if ( ! empty($config)) + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Setting runtime options...config data='".implode(",", $config)."'"); + + // Add the gameid to the options url. + if (array_key_exists("gameid", $config)) + { + $webservice_url .= '/' . $config['gameid']; + } + } + + // Call the webservice and get the response. + $resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, $webservice_url, $fields); + if ($resp) + { + // Get the session secret from the response. + $session_secret = $resp->session_secret; + + // Build the url to the AYAH webservice. + $url = 'https://'; // The AYAH webservice API requires https. + $url.= $this->ayah_web_service_host; // Add the host. + $url.= "/ws/script/"; // Add the path to the API script. + $url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key. + $url.= (empty($session_secret))? "" : "/".$session_secret; // If set, add the session_secret. + + // Build and return the needed HTML code. + return "
"; + } + else + { + // Build and log a detailed message. + $url = "https://".$this->ayah_web_service_host.$webservice_url; + $message = "Unable to connect to the AYAH webservice server. url='$url'"; + $this->__log("ERROR", __FUNCTION__, $message); + + // Build and display a helpful message to the site user. + $style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;"; + $message = "Unable to load the Are You a Human PlayThru™. Please contact the site owner to report the problem."; + echo "$message
\n"; + } + } + + /** + * Check whether the user is a human + * Wrapper for the scoreGame API call + * + * @return boolean + */ + public function scoreResult() { + $result = false; + if ($this->session_secret) { + $fields = array( + 'session_secret' => urlencode($this->session_secret), + 'scoring_key' => $this->ayah_scoring_key + ); + $resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, "/ws/scoreGame", $fields); + if ($resp) { + $result = ($resp->status_code == 1); + } + } + else + { + $this->__log("DEBUG", __FUNCTION__, "Unable to score the result. Please check that your ayah_config.php file contains your correct publisher key and scoring key."); + } + + return $result; + } + + /** + * Records a conversion + * Called on the goal page that A and B redirect to + * A/B Testing Specific Function + * + * @return boolean + */ + public function recordConversion() { + // Build the url to the AYAH webservice.. + $url = 'https://'; // The AYAH webservice API requires https. + $url.= $this->ayah_web_service_host; // Add the host. + $url.= "/ws/recordConversion/"; // Add the path to the API script. + $url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key. + + if( isset( $this->session_secret ) ){ + return ''; + } else { + $this->__log("ERROR", __FUNCTION__, 'AYAH Conversion Error: No Session Secret'); + return FALSE; + } + } + + /** + * Do a HTTPS POST, return some JSON decoded as array (Internal function) + * @param $host hostname + * @param $path path + * @param $fields associative array of fields + * return JSON decoded data structure or empty data structure + */ + protected function doHttpsPostReturnJSONArray($hostname, $path, $fields) { + $result = $this->doHttpsPost($hostname, $path, $fields); + + if ($result) { + $result = $this->doJSONArrayDecode($result); + } else { + $this->__log("ERROR", __FUNCTION__, "Post to https://$hostname$path returned no result."); + $result = array(); + } + + return $result; + } + + // Internal function; does an HTTPS post + protected function doHttpsPost($hostname, $path, $fields) { + $result = ""; + // URLencode the post string + $fields_string = ""; + foreach($fields as $key=>$value) { + if (is_array($value)) { + if ( ! empty($value)) { + foreach ($value as $k => $v) { + $fields_string .= $key . '['. $k .']=' . $v . '&'; + } + } else { + $fields_string .= $key . '=&'; + } + } else { + $fields_string .= $key.'='.$value.'&'; + } + } + rtrim($fields_string,'&'); + + // Use cURL? + if ($this->__use_curl()) + { + // Build the cURL url. + $curl_url = "https://" . $hostname . $path; + + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Using cURl: url='$curl_url', fields='$fields_string'"); + + // Initialize cURL session. + if ($ch = curl_init($curl_url)) + { + // Set the cURL options. + curl_setopt($ch, CURLOPT_POST, count($fields)); + curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + // Execute the cURL request. + $result = curl_exec($ch); + + // Close the curl session. + curl_close($ch); + } + else + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Unable to initialize cURL: url='$curl_url'"); + } + } + else + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Using fsockopen(): fields='$fields_string'"); + + // Build a header + $http_request = "POST $path HTTP/1.1\r\n"; + $http_request .= "Host: $hostname\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($fields_string) . "\r\n"; + $http_request .= "User-Agent: AreYouAHuman/PHP " . $this->get_version_number() . "\r\n"; + $http_request .= "Connection: Close\r\n"; + $http_request .= "\r\n"; + $http_request .= $fields_string ."\r\n"; + + $result = ''; + $errno = $errstr = ""; + $fs = fsockopen("ssl://" . $hostname, 443, $errno, $errstr, 10); + if( false == $fs ) { + $this->__log("ERROR", __FUNCTION__, "Could not open socket"); + } else { + fwrite($fs, $http_request); + while (!feof($fs)) { + $result .= fgets($fs, 4096); + } + + $result = explode("\r\n\r\n", $result, 2); + $result = $result[1]; + } + } + + // Log the result. + $this->__log("DEBUG", __FUNCTION__, "result='$result'"); + + // Return the result. + return $result; + } + + // Internal function: does a JSON decode of the string + protected function doJSONArrayDecode($string) { + $result = array(); + + if (function_exists("json_decode")) { + try { + $result = json_decode( $string); + } catch (Exception $e) { + $this->__log("ERROR", __FUNCTION__, "Exception when calling json_decode: " . $e->getMessage()); + $result = null; + } + } elseif (file_Exists("json.php")) { + require_once('json.php'); + $json = new Services_JSON(); + $result = $json->decode($string); + + if (!is_array($result)) { + $this->__log("ERROR", __FUNCTION__, "Expected array; got something else: $result"); + $result = array(); + } + } else { + $this->__log("ERROR", __FUNCTION__, "No JSON decode function available."); + } + + return $result; + } + + /** + * Get the current debug mode (TRUE or FALSE) + * + * @return boolean + */ + public function debug_mode($mode=null) + { + // Set it if the mode is passed. + if (null !== $mode) + { + // Save it. + $this->ayah_debug_mode = $mode; + + // Display a message if debug_mode is TRUE. + if ($mode) + { + $version_number = $this->get_version_number(); + $this->__log("DEBUG", "", "Debug mode is now on. (ayah.php version=$version_number)"); + + // Flush the buffer. + $this->__flush_message_buffer(); + } + } + + // If necessary, set the default. + if ( ! isset($this->ayah_debug_mode) or (null == $this->ayah_debug_mode)) $this->ayah_debug_mode = FALSE; + + // Return TRUE or FALSE. + return ($this->ayah_debug_mode)? TRUE : FALSE; + } + + /** + * Get the current version number + * + * @return string + */ + public function get_version_number() + { + return (isset($this->__version_number))? $this->__version_number : FALSE; + } + + /** + * Determine whether or not cURL is available to use. + * + * @return boolean + */ + private function __use_curl() + { + if (FALSE === $this->ayah_use_curl) + { + return FALSE; + } + elseif (function_exists('curl_init') and function_exists('curl_exec')) + { + return TRUE; + } + return FALSE; + } + + /** + * Load the config file. + * + * @return boolean + */ + private function __load_config_file() + { + // Initialize. + $name = 'ayah_config.php'; + $locations = array( + './', + dirname(__FILE__)."/", + ); + + // Look for the config file in each location. + foreach ($locations as $location) + { + if (file_exists($location.$name)) + { + require_once($location.$name); + return TRUE; + } + } + + // Could not find the config file. + return FALSE; + } + + /** + * Log a message + * + * @return null + */ + protected function __log($type, $function, $message) + { + // Add a prefix to the message. + $message = __CLASS__ . "::$function: " . $message; + + // Is it an error message? + if (FALSE !== stripos($type, "error")) + { + error_log($message); + } + + // Build the full message. + $message_style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;"; + $full_message = "$type: $message
\n"; + + // Output to the screen too? + if ($this->debug_mode()) + { + echo "$full_message"; + } + else + { + // Add the message to the buffer in case we need it later. + $this->__message_buffer[] = $full_message; + } + } + + private function __flush_message_buffer() + { + // Flush the buffer. + if ( ! empty($this->__message_buffer)) + { + foreach ($this->__message_buffer as $buffered_message) + { + // Print the buffered message. + echo "$buffered_message"; + } + } + } +} + +endif; // if ( ! class_exists('AYAH')): diff --git a/vendors/ayah-1.1.7/ayah_config.php b/vendors/ayah-1.1.7/ayah_config.php new file mode 100755 index 0000000..c29c889 --- /dev/null +++ b/vendors/ayah-1.1.7/ayah_config.php @@ -0,0 +1,13 @@ + + * @author Matt Knapp
+ * // create a new instance of Services_JSON
+ * $json = new Services_JSON();
+ *
+ * // convert a complexe value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+ * $output = $json->encode($value);
+ *
+ * print($output);
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+ *
+ * // accept incoming POST data, assumed to be in JSON notation
+ * $input = file_get_contents('php://input', 1000000);
+ * $value = $json->decode($input);
+ *
+ */
+class Services_JSON
+{
+ /**
+ * constructs a new JSON instance
+ *
+ * @param int $use object behavior flags; combine with boolean-OR
+ *
+ * possible values:
+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
+ * "{...}" syntax creates associative arrays
+ * instead of objects in decode().
+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
+ * Values which can't be encoded (e.g. resources)
+ * appear as NULL instead of throwing errors.
+ * By default, a deeply-nested resource will
+ * bubble up with an error, so all return values
+ * from encode() should be checked with isError()
+ */
+ function Services_JSON($use = 0)
+ {
+ $this->use = $use;
+ }
+
+ /**
+ * convert a string from one UTF-16 char to one UTF-8 char
+ *
+ * Normally should be handled by mb_convert_encoding, but
+ * provides a slower PHP-only method for installations
+ * that lack the multibye string extension.
+ *
+ * @param string $utf16 UTF-16 character
+ * @return string UTF-8 character
+ * @access private
+ */
+ function utf162utf8($utf16)
+ {
+ // oh please oh please oh please oh please oh please
+ if(function_exists('mb_convert_encoding')) {
+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+ }
+
+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+ switch(true) {
+ case ((0x7F & $bytes) == $bytes):
+ // this case should never be reached, because we are in ASCII range
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0x7F & $bytes);
+
+ case (0x07FF & $bytes) == $bytes:
+ // return a 2-byte UTF-8 character
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
+ . chr(0x80 | ($bytes & 0x3F));
+
+ case (0xFFFF & $bytes) == $bytes:
+ // return a 3-byte UTF-8 character
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
+ . chr(0x80 | (($bytes >> 6) & 0x3F))
+ . chr(0x80 | ($bytes & 0x3F));
+ }
+
+ // ignoring UTF-32 for now, sorry
+ return '';
+ }
+
+ /**
+ * convert a string from one UTF-8 char to one UTF-16 char
+ *
+ * Normally should be handled by mb_convert_encoding, but
+ * provides a slower PHP-only method for installations
+ * that lack the multibye string extension.
+ *
+ * @param string $utf8 UTF-8 character
+ * @return string UTF-16 character
+ * @access private
+ */
+ function utf82utf16($utf8)
+ {
+ // oh please oh please oh please oh please oh please
+ if(function_exists('mb_convert_encoding')) {
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+ }
+
+ switch(strlen($utf8)) {
+ case 1:
+ // this case should never be reached, because we are in ASCII range
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return $utf8;
+
+ case 2:
+ // return a UTF-16 character from a 2-byte UTF-8 char
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0x07 & (ord($utf8{0}) >> 2))
+ . chr((0xC0 & (ord($utf8{0}) << 6))
+ | (0x3F & ord($utf8{1})));
+
+ case 3:
+ // return a UTF-16 character from a 3-byte UTF-8 char
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr((0xF0 & (ord($utf8{0}) << 4))
+ | (0x0F & (ord($utf8{1}) >> 2)))
+ . chr((0xC0 & (ord($utf8{1}) << 6))
+ | (0x7F & ord($utf8{2})));
+ }
+
+ // ignoring UTF-32 for now, sorry
+ return '';
+ }
+
+ /**
+ * encodes an arbitrary variable into JSON format
+ *
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
+ * if var is a strng, note that encode() always expects it
+ * to be in ASCII or UTF-8 format!
+ *
+ * @return mixed JSON string representation of input var or an error if a problem occurs
+ * @access public
+ */
+ function encode($var)
+ {
+ switch (gettype($var)) {
+ case 'boolean':
+ return $var ? 'true' : 'false';
+
+ case 'NULL':
+ return 'null';
+
+ case 'integer':
+ return (int) $var;
+
+ case 'double':
+ case 'float':
+ return (float) $var;
+
+ case 'string':
+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+ $ascii = '';
+ $strlen_var = strlen($var);
+
+ /*
+ * Iterate over every character in the string,
+ * escaping with a slash or encoding to UTF-8 where necessary
+ */
+ for ($c = 0; $c < $strlen_var; ++$c) {
+
+ $ord_var_c = ord($var{$c});
+
+ switch (true) {
+ case $ord_var_c == 0x08:
+ $ascii .= '\b';
+ break;
+ case $ord_var_c == 0x09:
+ $ascii .= '\t';
+ break;
+ case $ord_var_c == 0x0A:
+ $ascii .= '\n';
+ break;
+ case $ord_var_c == 0x0C:
+ $ascii .= '\f';
+ break;
+ case $ord_var_c == 0x0D:
+ $ascii .= '\r';
+ break;
+
+ case $ord_var_c == 0x22:
+ case $ord_var_c == 0x2F:
+ case $ord_var_c == 0x5C:
+ // double quote, slash, slosh
+ $ascii .= '\\'.$var{$c};
+ break;
+
+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+ // characters U-00000000 - U-0000007F (same as ASCII)
+ $ascii .= $var{$c};
+ break;
+
+ case (($ord_var_c & 0xE0) == 0xC0):
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+ $c += 1;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xF0) == 0xE0):
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}));
+ $c += 2;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xF8) == 0xF0):
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}));
+ $c += 3;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xFC) == 0xF8):
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}),
+ ord($var{$c + 4}));
+ $c += 4;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xFE) == 0xFC):
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}),
+ ord($var{$c + 4}),
+ ord($var{$c + 5}));
+ $c += 5;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+ }
+ }
+
+ return '"'.$ascii.'"';
+
+ case 'array':
+ /*
+ * As per JSON spec if any array key is not an integer
+ * we must treat the the whole array as an object. We
+ * also try to catch a sparsely populated associative
+ * array with numeric keys here because some JS engines
+ * will create an array with empty indexes up to
+ * max_index which can cause memory issues and because
+ * the keys, which may be relevant, will be remapped
+ * otherwise.
+ *
+ * As per the ECMA and JSON specification an object may
+ * have any string as a property. Unfortunately due to
+ * a hole in the ECMA specification if the key is a
+ * ECMA reserved word or starts with a digit the
+ * parameter is only accessible using ECMAScript's
+ * bracket notation.
+ */
+
+ // treat as a JSON object
+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+ $properties = array_map(array($this, 'name_value'),
+ array_keys($var),
+ array_values($var));
+
+ foreach($properties as $property) {
+ if(Services_JSON::isError($property)) {
+ return $property;
+ }
+ }
+
+ return '{' . join(',', $properties) . '}';
+ }
+
+ // treat it like a regular array
+ $elements = array_map(array($this, 'encode'), $var);
+
+ foreach($elements as $element) {
+ if(Services_JSON::isError($element)) {
+ return $element;
+ }
+ }
+
+ return '[' . join(',', $elements) . ']';
+
+ case 'object':
+ $vars = get_object_vars($var);
+
+ $properties = array_map(array($this, 'name_value'),
+ array_keys($vars),
+ array_values($vars));
+
+ foreach($properties as $property) {
+ if(Services_JSON::isError($property)) {
+ return $property;
+ }
+ }
+
+ return '{' . join(',', $properties) . '}';
+
+ default:
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+ ? 'null'
+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
+ }
+ }
+
+ /**
+ * array-walking function for use in generating JSON-formatted name-value pairs
+ *
+ * @param string $name name of key to use
+ * @param mixed $value reference to an array element to be encoded
+ *
+ * @return string JSON-formatted name-value pair, like '"name":value'
+ * @access private
+ */
+ function name_value($name, $value)
+ {
+ $encoded_value = $this->encode($value);
+
+ if(Services_JSON::isError($encoded_value)) {
+ return $encoded_value;
+ }
+
+ return $this->encode(strval($name)) . ':' . $encoded_value;
+ }
+
+ /**
+ * reduce a string by removing leading and trailing comments and whitespace
+ *
+ * @param $str string string value to strip of comments and whitespace
+ *
+ * @return string string value stripped of comments and whitespace
+ * @access private
+ */
+ function reduce_string($str)
+ {
+ $str = preg_replace(array(
+
+ // eliminate single line comments in '// ...' form
+ '#^\s*//(.+)$#m',
+
+ // eliminate multi-line comments in '/* ... */' form, at start of string
+ '#^\s*/\*(.+)\*/#Us',
+
+ // eliminate multi-line comments in '/* ... */' form, at end of string
+ '#/\*(.+)\*/\s*$#Us'
+
+ ), '', $str);
+
+ // eliminate extraneous space
+ return trim($str);
+ }
+
+ /**
+ * decodes a JSON string into appropriate variable
+ *
+ * @param string $str JSON-formatted string
+ *
+ * @return mixed number, boolean, string, array, or object
+ * corresponding to given JSON input string.
+ * See argument 1 to Services_JSON() above for object-output behavior.
+ * Note that decode() always returns strings
+ * in ASCII or UTF-8 format!
+ * @access public
+ */
+ function decode($str)
+ {
+ $str = $this->reduce_string($str);
+
+ switch (strtolower($str)) {
+ case 'true':
+ return true;
+
+ case 'false':
+ return false;
+
+ case 'null':
+ return null;
+
+ default:
+ $m = array();
+
+ if (is_numeric($str)) {
+ // Lookie-loo, it's a number
+
+ // This would work on its own, but I'm trying to be
+ // good about returning integers where appropriate:
+ // return (float)$str;
+
+ // Return float or int, as appropriate
+ return ((float)$str == (integer)$str)
+ ? (integer)$str
+ : (float)$str;
+
+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+ // STRINGS RETURNED IN UTF-8 FORMAT
+ $delim = substr($str, 0, 1);
+ $chrs = substr($str, 1, -1);
+ $utf8 = '';
+ $strlen_chrs = strlen($chrs);
+
+ for ($c = 0; $c < $strlen_chrs; ++$c) {
+
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
+ $ord_chrs_c = ord($chrs{$c});
+
+ switch (true) {
+ case $substr_chrs_c_2 == '\b':
+ $utf8 .= chr(0x08);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\t':
+ $utf8 .= chr(0x09);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\n':
+ $utf8 .= chr(0x0A);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\f':
+ $utf8 .= chr(0x0C);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\r':
+ $utf8 .= chr(0x0D);
+ ++$c;
+ break;
+
+ case $substr_chrs_c_2 == '\\"':
+ case $substr_chrs_c_2 == '\\\'':
+ case $substr_chrs_c_2 == '\\\\':
+ case $substr_chrs_c_2 == '\\/':
+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+ $utf8 .= $chrs{++$c};
+ }
+ break;
+
+ case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+ // single, escaped unicode character
+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
+ . chr(hexdec(substr($chrs, ($c + 4), 2)));
+ $utf8 .= $this->utf162utf8($utf16);
+ $c += 5;
+ break;
+
+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+ $utf8 .= $chrs{$c};
+ break;
+
+ case ($ord_chrs_c & 0xE0) == 0xC0:
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= substr($chrs, $c, 2);
+ ++$c;
+ break;
+
+ case ($ord_chrs_c & 0xF0) == 0xE0:
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= substr($chrs, $c, 3);
+ $c += 2;
+ break;
+
+ case ($ord_chrs_c & 0xF8) == 0xF0:
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= substr($chrs, $c, 4);
+ $c += 3;
+ break;
+
+ case ($ord_chrs_c & 0xFC) == 0xF8:
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= substr($chrs, $c, 5);
+ $c += 4;
+ break;
+
+ case ($ord_chrs_c & 0xFE) == 0xFC:
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= substr($chrs, $c, 6);
+ $c += 5;
+ break;
+
+ }
+
+ }
+
+ return $utf8;
+
+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+ // array, or object notation
+
+ if ($str{0} == '[') {
+ $stk = array(SERVICES_JSON_IN_ARR);
+ $arr = array();
+ } else {
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $stk = array(SERVICES_JSON_IN_OBJ);
+ $obj = array();
+ } else {
+ $stk = array(SERVICES_JSON_IN_OBJ);
+ $obj = new stdClass();
+ }
+ }
+
+ array_push($stk, array('what' => SERVICES_JSON_SLICE,
+ 'where' => 0,
+ 'delim' => false));
+
+ $chrs = substr($str, 1, -1);
+ $chrs = $this->reduce_string($chrs);
+
+ if ($chrs == '') {
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ return $arr;
+
+ } else {
+ return $obj;
+
+ }
+ }
+
+ //print("\nparsing {$chrs}\n");
+
+ $strlen_chrs = strlen($chrs);
+
+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
+
+ $top = end($stk);
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
+
+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+ // found a comma that is not inside a string, array, etc.,
+ // OR we've reached the end of the character list
+ $slice = substr($chrs, $top['where'], ($c - $top['where']));
+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+ //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ // we are in an array, so just push an element onto the stack
+ array_push($arr, $this->decode($slice));
+
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+ // we are in an object, so figure
+ // out the property name and set an
+ // element in an associative array,
+ // for now
+ $parts = array();
+
+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+ // "name":value pair
+ $key = $this->decode($parts[1]);
+ $val = $this->decode($parts[2]);
+
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $obj[$key] = $val;
+ } else {
+ $obj->$key = $val;
+ }
+ } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+ // name:value pair, where name is unquoted
+ $key = $parts[1];
+ $val = $this->decode($parts[2]);
+
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $obj[$key] = $val;
+ } else {
+ $obj->$key = $val;
+ }
+ }
+
+ }
+
+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+ // found a quote, and we are not inside a string
+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+ //print("Found start of string at {$c}\n");
+
+ } elseif (($chrs{$c} == $top['delim']) &&
+ ($top['what'] == SERVICES_JSON_IN_STR) &&
+ ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
+ // found a quote, we're in a string, and it's not escaped
+ // we know that it's not escaped becase there is _not_ an
+ // odd number of backslashes at the end of the string so far
+ array_pop($stk);
+ //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+ } elseif (($chrs{$c} == '[') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a left-bracket, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+ //print("Found start of array at {$c}\n");
+
+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+ // found a right-bracket, and we're in an array
+ array_pop($stk);
+ //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ } elseif (($chrs{$c} == '{') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a left-brace, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+ //print("Found start of object at {$c}\n");
+
+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+ // found a right-brace, and we're in an object
+ array_pop($stk);
+ //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ } elseif (($substr_chrs_c_2 == '/*') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a comment start, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+ $c++;
+ //print("Found start of comment at {$c}\n");
+
+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+ // found a comment end, and we're in one now
+ array_pop($stk);
+ $c++;
+
+ for ($i = $top['where']; $i <= $c; ++$i)
+ $chrs = substr_replace($chrs, ' ', $i, 1);
+
+ //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ }
+
+ }
+
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ return $arr;
+
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+ return $obj;
+
+ }
+
+ }
+ }
+ }
+
+ /**
+ * @todo Ultimately, this should just call PEAR::isError()
+ */
+ function isError($data, $code = null)
+ {
+ if (class_exists('pear')) {
+ return PEAR::isError($data, $code);
+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
+ is_subclass_of($data, 'services_json_error'))) {
+ return true;
+ }
+
+ return false;
+ }
+}
+
+if (class_exists('PEAR_Error')) {
+
+ class Services_JSON_Error extends PEAR_Error
+ {
+ function Services_JSON_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
+ }
+ }
+
+} else {
+
+ /**
+ * @todo Ultimately, this class shall be descended from PEAR_Error
+ */
+ class Services_JSON_Error
+ {
+ function Services_JSON_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+
+ }
+ }
+
+}
diff --git a/vendors/ayah-1.1.7/sample.php b/vendors/ayah-1.1.7/sample.php
new file mode 100755
index 0000000..3077428
--- /dev/null
+++ b/vendors/ayah-1.1.7/sample.php
@@ -0,0 +1,64 @@
+
+scoreResult();
+
+ if ($score)
+ {
+ // This happens if the user passes the game. In this case,
+ // we're just displaying a congratulatory message.
+ echo "Congratulations: you are a human!";
+ }
+ else
+ {
+ // This happens if the user does not pass the game.
+ echo "Sorry, but we were not able to verify you as human. Please try again.";
+ }
+}
+?>
+
+
+